区间树
Posted dalgleish
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了区间树相关的知识,希望对你有一定的参考价值。
《算法导论》描述了一个关于区间树的重叠搜索,这里简单描述下原理,然后给出代码。
区间树是建立在红黑树的基础上,额外维护了一个信息域。在《算法导论》中,已经给出了任何额外信息域的维护,是相似的证明。所以,建议不懂得,先试着实现一个基本的,带size域的红黑树(书上已经给出原理),然后再扩展到区间树。下面是代码。
定义区间树
class rb_tree {//区间树 public: typedef struct _rb_interval { _rb_interval(int _low, int _high):low(_low), high(_high){} int low; int high; }rb_interval, *prb_interval; typedef struct _rb_type { _rb_type(_rb_type *_left, _rb_type *_right, _rb_type *_p, bool cl, _rb_interval _inte) : left(_left), right(_right), p(_p), color(cl), inte(_inte), max(_inte.high) {} bool color;//true for red, false for black int max;//区间上限 rb_interval inte;//区间范围 _rb_type *left, *right, *p; }rb_type, *prb_type; rb_tree(_rb_interval *A, int n) :root(NULL) { for (int i = 0; i < n; i++) this->rb_insert(A[i]); } ~rb_tree() { rb_empty(root); } void left_rotate(prb_type x); void right_rotate(prb_type x); void rb_insert(rb_interval _inte); prb_type rb_max(prb_type x); prb_type rb_min(prb_type x); prb_type rb_search(rb_interval _inte);//《算法导论》给出的重叠查找 prb_type rb_search_exact(rb_interval _inte);//精确查找,删除节点需要 prb_type rb_next(rb_interval _inte); prb_type rb_prev(rb_interval _inte); void rb_delete(rb_interval _inte); void rb_empty(prb_type x);//后续全部删除 prb_type rb_root(); void rb_show(prb_type x); private: bool overlap(rb_interval _x, rb_interval _y); int max(int a, int b, int c); int max(int a, int b); void rb_insert_fixup(prb_type x); void rb_delete_fixup(prb_type x); //测试使用 int rb_max_depth(prb_type x); int rb_min_depth(prb_type x); prb_type root; };
各成员函数实现
left_rotate、right_rotate成员函数,在本身的红黑树基础上,多了一个max域的维护
void rb_tree::left_rotate(typename rb_tree::prb_type x) { prb_type y = x->right;//y非空 x->right = y->left; if (y->left) y->left->p = x;//交换子节点 y->p = x->p;//更新父节点 if (x->p == NULL)//将y连接到x的父节点 root = y; else { if (x == x->p->left) x->p->left = y; else x->p->right = y; } y->left = x; x->p = y; //阶段二更新max y->max = x->max; x->max = this->max(x->inte.high, x->left ? x->left->max : 0, x->right ? x->right->max : 0); } void rb_tree::right_rotate(typename rb_tree::prb_type x) { prb_type y = x->left; x->left = y->right; if (y->right) y->right->p = x; y->p = x->p; if (x->p == NULL) root = y; else { if (x == x->p->left) x->p->left = y; else x->p->right = y; } y->right = x; x->p = y; //阶段二更新max y->max = x->max; x->max = this->max(x->inte.high, x->left ? x->left->max : 0, x->right ? x->right->max : 0); }
rb_min、rb_max成员函数,相比红黑树,没什么变化
typename rb_tree::prb_type rb_tree::rb_max(typename rb_tree::prb_type x) { if (x == NULL) return NULL; while (x->right) x = x->right; return x; } typename rb_tree::prb_type rb_tree::rb_min(typename rb_tree::prb_type x) { if (x == NULL) return NULL; while (x->left) x = x->left; return x; }
rb_search成员函数,此函数原理,由《算法导论》给出描述。这个可以用于实际应用,但是不能用于删除,因为这个函数只检测重叠的区间。
typename rb_tree::prb_type rb_tree::rb_search(typename rb_tree::rb_interval _inte) { prb_type x = root; while (x && !overlap(_inte, x->inte)) { if (x->left && x->left->max >= _inte.low) x = x->left; else x = x->right; } return x; }
rb_search_exact成员函数,基于上面rb_search函数的描述,为了之后能精准删除所有节点,再实现一个精准查找。
typename rb_tree::prb_type rb_tree::rb_search_exact(typename rb_tree::rb_interval _inte) { prb_type x = root; while (x && !(x->inte.low == _inte.low && x->inte.high == _inte.high)) { if (_inte.low < x->inte.low) x = x->left; else x = x->right; } return x; }
rb_next、rb_prev成员函数
typename rb_tree::prb_type rb_tree::rb_next(typename rb_tree::rb_interval _inte) { prb_type x = rb_search_exact(_inte), y; if (x == NULL) return NULL; if (x->right) return rb_min(x->right); y = x->p; while (y != NULL && y->right == x) {//没有则返回NULL x = y; y = y->p; } return y; } typename rb_tree::prb_type rb_tree::rb_prev(typename rb_tree::rb_interval _inte) { prb_type x = rb_search_exact(_inte), y; if (x == NULL) return NULL; if (x->left) return rb_max(x->left); y = x->p; while (y != NULL && y->left == x) { x = y; y = y->p; } return y; }
rb_insert函数,有第一阶段额外信息域的维护
void rb_tree::rb_insert(typename rb_tree::rb_interval _inte) { prb_type y = NULL, x = root, z = new rb_type(NULL, NULL, NULL, true,_inte); while (x != NULL) { y = x; x->max = this->max(x->max, z->max);//阶段一更新max if (_inte.low < x->inte.low) x = x->left; else x = x->right; } z->p = y; if (y == NULL) root = z; else { if (_inte.low < y->inte.low) y->left = z; else y->right = z; } rb_insert_fixup(z); }
rb_insert_fixup成员函数,插入后修复,和红黑树相比,没有变化,原因参考《算法导论》
void rb_tree::rb_insert_fixup(typename rb_tree::prb_type x) { prb_type y; while (x->p && x->p->color) {//红色 if (x->p == x->p->p->left) {//父节点存在,一定存在祖父节点 y = x->p->p->right; //无法满足性质4 if (!y || y->color) {//若y为NULL,默认不存在的节点是黑色 x->p->color = false; if (y) y->color = false; x->p->p->color = true; x = x->p->p;//重新设置z节点 } else if (x == x->p->right) { //无法满足性质5 x = x->p; left_rotate(x); } if (x->p && x->p->p) {//保证存在 x->p->color = false; x->p->p->color = true; right_rotate(x->p->p); } } else {//和上面左节点相反 y = x->p->p->left; if (!y || y->color) { x->p->color = false; if (y) y->color = false; x->p->p->color = true; x = x->p->p;//重新设置z节点 } else if (x == x->p->left) { x = x->p; right_rotate(x); } if (x->p && x->p->p) { x->p->color = false; x->p->p->color = true; left_rotate(x->p->p); } } } root->color = false; }
rb_delete函数,有第一阶段,额外信息域的维护
void rb_tree::rb_delete(typename rb_tree::rb_interval _inte) { prb_type z = rb_search_exact(_inte), y, x; if (z == NULL) return; if (z->left == NULL || z->right == NULL)//y是待删除的节点 y = z;//z有一个子节点 else y = rb_next(_inte);//z有两个子节点,后继和前趋保证了y有一个或没有子节点 if (y->left != NULL) x = y->left; else x = y->right; if (x != NULL) //存在一个子节点,先更正父子关系 x->p = y->p; if (y->p == NULL)//再决定是在左或者右节点 root = x; else { if (y->p->left == y) y->p->left = x; else y->p->right = x; } if (y != z)//处理两个子节点的交换 z->inte = y->inte; //更新max z = y->p; while (z) { z->max = this->max(z->max, z->left ? z->left->max : 0, z->right ? z->right->max : 0); z = z->p; } if (!y->color)//黑色 rb_delete_fixup(x); delete y; }
rb_delete_fixup成员函数,没有任何变化
void rb_tree::rb_delete_fixup(typename rb_tree::prb_type x) { prb_type w; while (x && x != root && !x->color) {//黑色 if (x == x->p->left) { w = x->p->right; if (w->color) {//红色 w->color = false; x->p->color = true; left_rotate(x->p); w = x->p->right; } if ((!w->left && !w->right) || (!w->left->color && !w->right->color)) {//双黑 w->color = true; x = x->p; } else { if (!w->right->color) {//单黑 w->left->color = false; w->color = true; right_rotate(w); w = x->p->right; } w->color = x->p->color; x->p->color = false; w->right->color = false; left_rotate(x->p); x = root; } } else {//相反的情况 w = x->p->left; if (w->color) {//红色 w->color = false; x->p->color = true; right_rotate(x->p); w = x->p->left; } if ((!w->left && !w->right) || (!w->left->color && !w->right->color)) {//双黑 w->color = true; x = x->p; } else { if (!w->left->color) {//单黑 w->right->color = false; w->color = true; left_rotate(w); w = x->p->left; } w->color = x->p->color; x->p->color = false; w->left->color = false; right_rotate(x->p); x = root; } } } if (x) x->color = false;//巧妙处理,默认黑 }
rb_empty成员函数,清空所有节点
void rb_tree::rb_empty(typename rb_tree::prb_type x) { if (x != NULL) { rb_empty(x->left); rb_empty(x->right); printf("\n--------------[%d,%d]---------\n",x->inte.low,x->inte.high); rb_delete(x->inte);//后续保证子叶为空 rb_show(root); } } typename rb_tree::prb_type rb_tree::rb_root() { return root; }
三个辅助函数,overlap,max(有重载)
bool rb_tree::overlap(typename rb_tree::rb_interval _x, typename rb_tree::rb_interval _y) {//闭区间 if (_x.high < _y.low || _x.low > _y.high) // _x 和 _y 没有重叠 return false; return true; } int rb_tree::max(int a, int b, int c) { if (a>b) return a>c ? a : c; else return b>c ? b : c; } int rb_tree::max(int a, int b) { return a > b ? a : b; }
用于测试各成员函数是否正确的相关成员函数
void rb_tree::rb_show(typename rb_tree::prb_type x) { if (x != NULL) { rb_show(x->left); if (x == root) printf("root: (%s)[%d,%d], max=%d, (%d,%d)\n", root->color ? "red" : "black", x->inte.low, x->inte.high, x->max, rb_max_depth(x), rb_min_depth(x)); else printf("(%s)[%d,%d], max=%d, (%d,%d)\n", x->color ? "red" : "black", x->inte.low, x->inte.high, x->max, rb_max_depth(x), rb_min_depth(x)); rb_show(x->right); } }
int rb_tree::rb_max_depth(typename rb_tree::prb_type x) { if (x == NULL) return 0; int l = rb_max_depth(x->left); int r = rb_max_depth(x->right); return (l > r ? l : r) + 1; } int rb_tree::rb_min_depth(typename rb_tree::prb_type x) { if (x == NULL) return 0; int l = rb_min_depth(x->left); int r = rb_min_depth(x->right); return (l < r ? l : r) + 1; }
所有代码均经过测试,结果正确!!!
以上是关于区间树的主要内容,如果未能解决你的问题,请参考以下文章
2021-12-24:划分字母区间。 字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。 力扣763。某大厂面试
代码源 Div1 - 108#464. 数数(主席树,区间比k小的数的个数)HDU4417