数据结构的扩张

数据结构的扩张

由于数据结构理论已经很成熟,标准数据结构在性能与抽象上往往没有太大改动空间。所以在需要更多功能的数据结构时,往往只需找到相关的标准数据结构作为基础,然后在其上存储额外变量、构造额外运算。这样的流程就称为“数据结构的扩张”,数据结构的扩张往往不是一个单纯的数据结构与算法的问题,其还包含了一定的程序设计、面向对象设计方面的考量。下文将以广泛作为标准结构的红黑树为例,研究2种红黑树的扩张。数据结构的扩张可分为如下步骤:

1) 根据问题选择标准数据结构作为基础结构;

2) 确定基础结构上需额外维护的附加信息;

3) 验证基础结构上的运算能否维护附加信息;

4) 构造新的运算;

下面是之前写过的红黑树代码,用它作为面向对象编程的父类/基类,之后会用面向对象的继承来实现红黑树的扩张。

 

动态顺序统计树

求乱序序列中查找第\(k\)大元素被称为“TopK问题”或“选择问题”,动态顺序统计树是红黑树的扩张,其使得红黑树支持查找第\(k\)大元素,且其最坏代价为\(O(lgn)\),实现该运算的步骤如下:

1) 在节点增设\(size\)变量记录该子树的总节点数,任意节点\(x\)满足\(x.size=x.left.size + 1 + x.right.size\);

2) 利用\(size\)可递归得到排序,根节点左子树含排序为\( [1…x.left.size]\)的节点,根节点的排序为\(x.left.size+1\),根节点右子树包含排序为\( [1+x.left.size…x.size]\)的节点…

3) 在红黑树的增删运算与旋转运算中,需要额外维护\(size\)的正确性;

4) 实现\(select\)运算结构查找第\(k\)大节点的\(key\);

测试数据:

 

区间树

区间树的节点记录了一个闭区间\([low,high]\),其运算结构如下:

1) \(insert(low,high)\):插入一个闭区间\([low,high]\);

2) \(delete(low,high)\):删除一个闭区间\([low,high]\);

3) \(find(low,high)\):返回一个与闭区间\([low,high]\)有“重叠部分”的闭区间;

下面考虑把区间树作为红黑树的扩张,其步骤为:

1) 把\(low\)对应到原红黑树节点的\(key\),把\(high\)作为原红黑树节点的新变量;

2) 在原红黑树节点增加新变量\(max\)表示该子树所有节点的最大\(high\)值;

3) 原有\(insert\)的流程不变,只需额外初始化\(high\)变量,最后回溯维护\(max\);

4) 原有\(delete\)流程中的查找流程需从\(low\)重复的节点找到\(high\)符合要求的节点,最后回溯维护\(max\);

5) 当需要旋转时,由于新父节点的\(max\)显然与原父节点相同,故无需回溯更新\(max\);

6) \(find(low,high)\)的流程如下,设当前节点为\(x\)则从根节点开始执行。若\(x\)的区间与\([low,high]\)有重叠则返回,否则若\(x.left.max \geq low\)则左子树必然存在与与\([low,high]\)重叠的区间,然后记\(x = x.left\)继续循环,否则重叠区间只存在于右子树或不存在重叠区间,记\(x = x.right\)继续循环。

测试数据:

 

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部