zoukankan      html  css  js  c++  java
  • 区间树

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

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

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

  • 相关阅读:
    Network Embedding 论文小览
    DLRS(深度学习应用于推荐系统论文汇总--2017年8月整理)
    深度语义匹配模型-DSSM 及其变种
    python 按值排序
    python 日期排序
    推荐领域数据集
    EPS 转 pdf 在线
    梯度下降法的三种形式BGD、SGD以及MBGD
    Daily paper -Science 2006: Experimental Study of Inequality and Unpredictability in an Artificial Cultural Market (探究群体行为对商品销量的影响)
    2017年Nature文章“Millions of online book co-purchases reveal partisan differences in the consumption of science”阅读笔记
  • 原文地址:https://www.cnblogs.com/dalgleish/p/9092680.html
Copyright © 2011-2022 走看看