[Happy DSA] 将已排序的元素序列快速的插入到stl set中
来源:互联网 发布:网络共享 win10 编辑:程序博客网 时间:2024/05/29 03:07
已知一个从小到大已排序的元素序列,如何插入到stl set中最快。
1. stl set内部结构
我们知道stl set内部是用红黑树来实现的。红黑树是一种平衡二叉查找树,它有以下4个用来平衡的条件:
- 每个节点要么是红色,要么是黑色
- 根节点为黑色
- 红节点的子节点一定是黑色
- 任一个节点至页节点的任何路径上,黑节点的个数相等
所以当插入一个新的非根节点时,它一定要是红色,是为了不破坏条件4。所以最难满足的就是条件3。为了满足这个条件3,没插入一个红色节点后,都需要进行树的平衡调整。
回到题目中,要是插入速度最快,就得尽量减少RB树的平衡调整次数或花销。
RB树条件有两种条件方式,一种就是简单的将父辈节点的颜色进行调整,譬如红色变成黑色,黑色变成红色;另一种就是旋转并调整颜色,有时不止一次旋转。简单的颜色调整是必须的,减少不了。因为默认都是以红色来插入一个新节点,不可能所有的节点都是红色。因此,我们要做的就是尽量减少旋转的次数,甚至根本不要让它进行旋转来调整。
2. 按照什么顺序插入
假如排序的数组元素序列是: 0, 1, 2, 3, 4, 5, 6, 7, 8。共9个元素。
如果了解二叉查找树的特性的话,一个比较稳定的树,或者说是一个比较方便以后查找元素的二叉树,应该满足左右子树元素个数尽量对称的布局。RB树既然是一个平衡二叉查找树,那么它也应该满足这样的优势,可以让之后的查找比较迅速(不然也不会采用RB树作为set的内部实现了)。我们期望的树的布局应该是下面这样的:
这里容易有一个误区,就是递归的插入中间元素,譬如插入4之后,再递归插入左半部分的中间元素,之后是右半部分的中间。其实这样是不对的。插入4之后,插入红色节点2,之后是红色节点0/1,这时就得进行右旋转调整了,因为0/1的父节点是红色节点。所以我们必须对称的插入左右中值元素,以保持RB树的平衡。
3. 算法验证及实现
上面插入的顺序到底是不是我们的一厢情愿呢?我们来验证一下,还是以前面9个数字序列:0, 1, 2, 3, 4, 5, 6, 7, 8。根据我们前面推导的插入序列,它们应该按照这样的方式插入:4, 2, 6, 1, 3, 5, 7, 0, 8。
a) 插入节点4,标记为黑,因为它是根节点。
红色节点1作为节点2的左子节点插入,由于父节点2是红色,而且叔叔节点也是红色。根据RB树的调整规则,我们只需要将父辈节点2和节点6反转为黑色,将祖父节点4反转为红色。但是最后又得将根节点4标记为黑色(满足规则2)。
有了前面1的插入,导致现在节点2和节点6都是黑色,节点3,5,7将被直接插入,不做任何调整。
红色节点0作为节点1的左子节点插入。由于节点1和节点3都为红色,类似于当时节点1的插入,将节点1和节点3反转为黑色,将节点2反转为红色。节点8类似于节点1。
高亮标记的那个树就是RB树内部的结构。
从节点4到节点8的插入,期间只有颜色调整,没有任何旋转调整。因此满足我们之前的需求。
下面就是序列插入时,RB树内部结构变化图:
一个基于BFS的Python代码的实现(借用队列):
#insert all elements from l (type is list) to s (type is set)def insert_set(l,s): sorted_l = sorted(l) import Queue q = Queue.deque() begin, end = 0, len(l) q.append((begin,end)) while len(q): (begin, end) = q.popleft() if begin >= end: continue mid = (begin + end) /2 print mid s.add(l[mid]) q.append((begin,mid)) q.append((mid+1,end))if __name__ == '__main__': l = [0,1,2,3,4,5,6,7,8] s = set([]) insert_set(l,s)
- [Happy DSA] 将已排序的元素序列快速的插入到stl set中
- STL合并已排序的序列
- STL对已排序的序列进行排序和运算
- C 已排序的数组中一个元素,插入后排序不变
- STL中map容器的元素插入
- 将从表table2中查询到的数据插入到已建立的表table1
- [Happy DSA] 如何对单链表进行快速排序
- STL在已排序的序列上进行集合运算
- 比较 N个元素 一个一个地插入到一个堆中 以线性时间建立一个堆 已排序、反序、随机输入的运行时间
- 给定两个已排序序列,找出共同的元素
- 给定两个已排序序列,找出共同的元素
- STL中插入排序的实现
- 将查询数据插入到另一张已存在的表中
- stl 中 容器 set 类插入,删除,遍历,其中存储的元素为基础类型 int (1)
- 插入排序中元素的移动次数
- STL---对于set中元素是否有序的探究
- XML+DOM将元素的数据依次插入到表格中
- 问题: 将N个元素使用push_back插入到vector中, 求push_back操作的复杂度。
- 徐氏银行开业了!!!!秒杀一切!!!!!
- 互联网产品“冷启动”问题浅析
- API Hooking (LoadLibrary)
- 关于函数返回值的一些理解
- ASP.NET 安全认证(三)—— 用Form 表单认证实现单点登录(Single Sign On)
- [Happy DSA] 将已排序的元素序列快速的插入到stl set中
- JM8.6中NALU(此处指VCL式的NALU)是如何写进码流的?
- Java:JComboBox 用法
- 【C++11】随机数函数库random
- Eclipse 自动生成 Ant的Build.xml 配置文件
- 安装SQL Server2008的示例数据库AdventureWorks 2008
- (转)LuaPlus C++ 函数互调
- 面向对象纯JS 导出Excel,拥有它,你所需要做的就是setup数据格式(目前仅提供单个Sheet的导出,持续更新中...)。
- 程序员的八个级别