数据结构之五(数据结构的扩充、动态统计、区间树)

来源:互联网 发布:网络平台重庆时时彩 编辑:程序博客网 时间:2024/06/05 17:50

1.        动态有序统计

静态统计:是指数据内容一旦确定,就不再有增加、删除操作,排序的内容是静态固定不变的。(见排序之五)

动态统计:内容有可能有增减。

动态统计主要有两种操作。一是获取数组中第i大的数。二是给一个数x,返回x在数组中的位置。

动态统计实现方式:以红黑树为基础进行扩充,在每个节点x存储额外的一个记录信息---以x为根的子树的节点数(包含x自己,以及其内部孩子节点,不含NIL节点)。NIL节点处的值设置为0,可以简化处理(NIL节点使用一个伪节点表示)。

1.1.       获取数组中第i大的数

对于节点x,

如果i等于其左孩子的信息值r+1,则节点x为第i大的,因为左孩子包含所有比x小的值;

如果i小于其左孩子的信息值r+1,则第i大的比x小,第i大的还在x的左子树中,且仍为第i大的(因此递归在左子树中继续找第i大的);

否则(i大于左孩子的信息值r+1),则第i大的比x大,第i大的还在x的右子树中,且为右子树的第(i-r-1)大(因此递归在右子树中找第i-r-1大的)。

时间复杂度:每一次递归都会下降一层,因此最坏情况下最多为树的高度次。而树为红黑树,高度为O(lgn)。因此时间复杂度最多为O(lgn)。

1.2.       给一个节点x,返回x在数组中的位置,顺序统计位置。(即获取元素x的秩。)

原理:x的秩为中序遍历时的位置。因此找出比x小的所有元素即可。

作法:从x开始,往上直到根节点。值初始化为x的左孩子的信息值加1,每次循环时,如果祖先节点为其父节点的右孩子,则值累加其父节点的左孩子(即祖先节点的兄弟节点)的信息值加1。

每次循环结束,当前值为x在以该祖先节点为根的树中的秩。

时间复杂度:由于循环为从x节点往根走,每次递归上移一层。因此复杂度为O(lgn)。

1.3.       在红黑树的插入、删除中维护新增的信息节点

由于可以进行动态操作,因此在插入或删除时需要重新调整信息值。

1.3.1.      插入操作

红黑树中插入需要经过两个步骤:

l  从根开始,沿着树下降,将新节点插入为某个节点的孩子。

l  沿着树上升,改变颜色,或者作旋转。

在第一阶段中,为了维护子树大小信息,对每个经过的祖先节点,其子树大小都加1,新增节点的子树大小为1。由于经过的祖先最多为O(lgn),因此这一步的时间最多为O(lgn)。

在第二阶段中,子树大小只有旋转才会引起,改色不会引起子树大小修改,而且旋转为一个局部操作,只引起两个节点的子树大小变化。

对x左旋转(将x下降,x的右孩子上升),则x右孩子上升后,子树大小修改为原x的子树大小,x的新的子树大小按公式重新计算一次

size[x] = size[left[x]]+ size[right[x]] + 1

即可。

相应的右旋转(将x下降,x的左孩子上升),则x左孩子上升后,子树大小修改为原x节点的子树大小,x的新的子树大小按公式重新计算一次即可。

由于在一次插入操作中,旋转最多两次,因此对子树大学的修改为O(1)。

从而,在插入操作中,引进子树大小后增加的操作为O(lgn)。因此向修改后的数据结构中插入的操作也为O(lgn)(因为红黑树的插入也为O(lgn))。

1.3.2.      删除操作

红黑树删除操作的步骤:

l  第一步,查找要删除的节点

l  第二步,最多三次旋转

因此和插入类似。对新的数据结构的删除也只需要O(lgn)的时间。

1.4.       节点信息的技巧

节点而我的信息存储的是子树大小,二不是节点的秩。

原因在于,如果直接存秩,则如果新插入的为最小元素,则树中每个节点的秩都需要修改。时间当然为O(n),不会达到O(lgn)

2.        数据结构的扩张

使用数据结构扩张是在原有数据结构基础上,对数据加入新的属性,以便满足新的特性。

数据结构扩充一般分四个步骤

2.1.       选择基本数据结构(如之前的选择红黑树,红黑树可以很好的维护全序数组上的最大、最小、前驱、后继操作)

2.2.       确定要新加的信息(如之前的增加子树大小信息,新增信息主要是使得新增的操作更加有效,如果不增加新的数据域,操作会比较耗时)

2.3.       验证可以用原有的修改操作维护新的信息(如之前的可以在红黑树的插入、删除过程中,以同阶的O(lgn)时间来维护新增的信息。)

2.4.       增加新的操作(如之前的获取第i大的元素,获取元素x的秩。)

当然这四个步骤也并不是严格一步不少的,因为有些操作可以不用,因此只是一种指导思想。

2.5.       红黑树扩张特性

如果红黑树中新增域f,且对于节点x,其f[x]可以只用x,left[x],right[x]的信息,包括f域信息来计算,则在插入和删除操作中,可以在不影响其O(lgn)的性能的条件下维护新增的f域信息。

3.        区间树

3.1.       概念

区间树的概念,用一个时间区间来表示一个对象。

一个区间为早上8点到10点,一个区间为9点到11点,等等时间区间。

区间有一个高位值和一个低位值。

区间树上的操作插入、删除、查询。

最主要的是查询,给一个区间,查询出所有这个时间内发生的事情,即和这个区间有重叠的区间

两个区间重叠等价于每个区间的低位都小于另一个的高位。

两个区间的三分法,任何两个区间满足以下三个条件之一:

l  这两个区间重叠。重叠有四种情况,但只要每个的低位小于另一个的高位即可。

l  两个区间(i1,i2),i1在i2的左边,即i1的高位小于i2的低位

l  两个区间(i1,i2),i1在i2的右边,即i1的低位大于i2的高位。

3.2.       扩张

扩张的四个步骤

l  区间树用红黑树来扩张。

l  每个节点x增加一个f域。f表示以x为根的树中,所有节点的高位的最大值。

l  信息维护。插入删除操作中维护的复杂度为O(lgn)。因为

f[x]=max(high[x],f[left[x]],f[right[x]])

即x的f域为:x区间的高位、左节点的f域、右节点的f域中的最大值。因此由红黑树扩张性质,可以在O(lgn)内维护。新的插入、删除可以在原有的红黑树的插入、删除上修改f域来实现。

l  新增加的查询操作:给定一个区间i,查找出一个与该区间重叠的区间。

思想:查找从根开始,逐步向下,直到找到,或者达到NIL节点。

第一种情况,当节点x非空,且x节点的区间与i不重叠时,往下循环(否则找到区间x);

第二种情况,如果x左节点非空,且左节点的f域大于等于i节点的低端值时,下降到x的左节点继续处理;

第三种情况,否则(第二种情况不满足)下降到x的右节点继续处理。

最后返回x节点(可能为NIL)即可。

                   新增的查询操作只需从根往下最多到NIL,因此时间为O(lgn)。

3.3.       扩充

扩张区间树

增加一个方法:给一个区间i,返回与i重叠的区间中低端最小的区间。

增加一个方法:列出与区间i重叠的所有区间。(1.找到一个就删除该元素,直到没有重叠的即可。2.也可以不修改树。)

增加一个方法:查询与区间i相等的区间,低位、高位和i的低位、高位都相等。(需要修改区间树的其他方法来维护)。

判断一组区间中是否有两个区间重叠。

扩充区间数,可以找出最大重叠点。

 

原创粉丝点击