如何扩张数据结构
1) 选择基础数据结构
2) 确定要在基础数据结构中记录得附加信息
3) 提供基本(内部)操作来维护附加信息
4) 设计新得接口
1 是一颗红黑树
2 是以区间左端点维护的红黑树
3 额外信息是在每个节点中, 保存了以该节点为根的树中的最右的区间端点
class Seg { int i, j; int upbound; public: int lower() const {return i;} int higher() const {return j;} int upper() const {return upbound;} bool interval(const Seg &r) { if(i > r.j || j < r.i) return false; return true; } }; interval-search(T, Seg &i) { x = root(T); while(x && !x.interval(i)) { if(x.left && x.left.upper() >= i.lower()) x = x.left; else x = x.right; } return x; }
个人说明:
1) 算法是正确的,可以正确返回与指定区间重叠的区间
2) 该算法只返回与i有重叠得一个区间, 并不是所有的区间
3) 该算法应该是非常容易错的。 若把其中的语句修改一下, 算法就错了。
修改之前 if(x.left && x.left.upper() >= i.lower()) x = x.left; else x = x.right; 修改之后为://///errorrrrrrrr if(x.right && x.right.upper() >= i.lower()) x = x.right; else x = x.left; 举例如下, 根节点区间为[20, 21, 40] //40为upper 左孩子区间为[10, 40, 40] 右孩子区间为[25, 40, 40] 查找的区间为 [12,13] 按照修改之后的算法流程, 则到右子树中去查找了; 但这个[12,13]恰恰是只可能出现在左孩子树中。
算法导论中文版pdf中有细微描述是有问题的
根本原因是该区间树是以左端点递增有序的方式构建的红黑树(二叉排序树)。
interval_insert, interval_delete 待补充
interval_insert很简单, 只需要注意更新upper就行
interval_insert(x, i) //i插入到以x为根的树中 { while(1) { if(i.higher() > x.upper()) //更新上界 x.upbound = i.higher(); if(i.lower() < x.lower()) //然后一直走到尾插入 { if(x.left) x = x.left; else { x.left = i; return; } } else { if(x.right) x = x.right; else { x.right= i; return; } } }
interval_delete 需要回溯, 而且需要精确判断两个区间是否相同, 相同才能delete ?
// 找到x的前驱或者后继替换x 【二叉树的删除操作】
// 只需要修改该路径上的upper
使用栈是肯定可以解决的 递归呢? interval_delete(T, p, x, i) //在以树T中删除i { if(x == i) { delete(T, p, x, i); } else if(i < x) { p = x; x = x.left interval_delete(T, p, x, i); } else { p = x; x = x.right; interval_delete(T, p, x, i); } //TODO 修改p,x的upper }