• 区间树


    《算法导论》描述了一个关于区间树的重叠搜索,这里简单描述下原理,然后给出代码。

    区间树是建立在红黑树的基础上,额外维护了一个信息域。在《算法导论》中,已经给出了任何额外信息域的维护,是相似的证明。所以,建议不懂得,先试着实现一个基本的,带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("
    --------------[%d,%d]---------
    ",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)
    ", 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)
    ", 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;
    }

    所有代码均经过测试,结果正确!!!

    转载于:https://www.cnblogs.com/dalgleish/p/9092680.html

  • 相关阅读:
    SPOJ GSS4 Can you answer these queries IV ——树状数组 并查集
    SPOJ GSS3 Can you answer these queries III ——线段树
    SPOJ GSS2 Can you answer these queries II ——线段树
    SPOJ GSS1 Can you answer these queries I ——线段树
    BZOJ 2178 圆的面积并 ——Simpson积分
    SPOJ CIRU The area of the union of circles ——Simpson积分
    HDU 1724 Ellipse ——Simpson积分
    HDU 1071 The area ——微积分
    HDU 4609 3-idiots ——FFT
    BZOJ 2194 快速傅立叶之二 ——FFT
  • 原文地址:https://www.cnblogs.com/twodog/p/12136823.html
Copyright © 2020-2023  润新知