zoukankan      html  css  js  c++  java
  • 《算法导论》笔记 第14章 14.1 动态顺序统计

    【笔记】

    一棵顺序统计量树T通过简单地在红黑树的每个结点存入附加信息而成。在一个结点x内,除了包含通常的红黑树的域key color p left right,还包括域size[x]。这个域中包含以结点x为根的子树的结点数(包括x本身),即子树的大小。如果定义哨兵为0,也就是设置size[nil]为0,则有等式 size[x]=size[left[x]]+size[right[x]]+1。

    在出现相等关键字的情况下,定义排序为按中序遍历树时输出的结点位置,以此消除顺序统计树原定义的不确定性。


    检索具有给定排序的元素:

    过程OS-SELECT(x,i)返回一个指向以x为根的子树中包含第i小关键字的结点的指针。

        NODE* osSelect(NODE* x, int i) {
            int r = x->l->size + 1;
            if (i == r) { return x; }
            else if (i < r) { return osSelect(x->l,i); }
            else { return osSelect(x->r,i-r); }
        }
    最坏情况下,OS-SELECT的总时间与树的高度成正比。所以对含n个元素的动态集合,运行时间为O(lgn)。


    确定一个元素的秩:

    给定指向一顺序统计树T中结点x的指针,过程OS-RANK返回对T进行中序遍历后得到的线性序中x的位置。

        int osRank(NODE* x) {
            int r = x->l->size + 1;
            NODE *y = x;
            while (y != root) {
                if (y == y->p->r) { r += y->p->l->size + 1;}
                y = y->p;
            }
            return r;
        }
    x的秩可以视为在对树的中序遍历中,排在x之前的结点个数再加上1。

    运行时间与树的高度成正比:对含n个结点的顺序统计树时间为O(lgn)。


    对子树规模的维护:

    插入:第一阶段沿根下降,将新结点插入为某个已有结点的孩子。第二阶段沿树上升,做颜色修改和旋转保持性质。

    第一阶段:对路径上的每个结点都要增加其size。

    第二阶段:对旋转增加两行代码:

            y->size = x->size;
            x->size = x->l->size + x->r->size + 1;
    删除:第一阶段对查找树进行操作。第二阶段至多三次旋转。
    要删除结点y,遍历一条由y到根的路径,减少路径上每个结点的size。


    #define COLOR int
    #define BLACK 1
    #define RED 0
    using namespace std;
    
    template <class T>
    class RBTREE{
    public:
        struct NODE{
            NODE *p,*l,*r;
            T key;
            COLOR c;
            int size;
            NODE() {}
        }NIL;
        NODE *nil, *root;
        NODE* newNode(T k, COLOR cl = RED) {
            NODE *p = new NODE;
            p->c = cl;
            p->p = nil;
            p->l = nil;
            p->r = nil;
            p->key = k;
            p->size = 1;
            return p;
        }
        void deleteNode(NODE *p) {
            delete p;
        }
        void init() {
            nil = &NIL;
            nil->c = BLACK;
            nil->p = nil;
            nil->l = nil;
            nil->r = nil;
            nil->size = 0;
            root = nil;
        }
        RBTREE () { init(); }
    /*********************************************/
        void leftRotate(NODE *x) {
            NODE *y = x->r;
            x->r = y->l;
            if (y->l != nil) { y->l->p = x; }
            y->p = x->p;
            if (x->p == nil) { root = y; }
            else {
                if (x == x->p->l) { x->p->l = y; }
                else { x->p->r = y; }
            }
            y->l = x;
            x->p = y;
            y->size = x->size;
            x->size = x->l->size + x->r->size + 1;
        }
        void rightRotate(NODE *x) {
            NODE *y = x->l;
            x->l = y->r;
            if (y->r != nil) { y->r->p = x; }
            y->p = x->p;
            if (x->p == nil) { root = y; }
            else {
                if (x == x->p->l) { x->p->l = y; }
                else { x->p->r = y; }
            }
            y->r = x;
            x->p = y;
            y->size = x->size;
            x->size = x->l->size + x->r->size + 1;
        }
    /*********************************************/
        void rbInsert(NODE *z) {
            NODE *y = nil;
            NODE *x = root;
            while (x != nil) {
                y = x;
                y->size += 1;
                if (z->key < x->key) { x = x->l; }
                else { x = x->r; }
            }
            z->p = y;
            if (y == nil) { root = z; }
            else {
                if (z->key < y->key) { y->l = z; }
                else { y->r = z; }
            }
            z->l = nil;
            z->r = nil;
            z->c = RED;
            rbInsertFixup(z);
        }
        void rbInsertFixup(NODE *z) {
            NODE *y;
            while (z->p->c == RED) {
                if (z->p == z->p->p->l) {// z 的父亲是爷爷的左儿子
                    y = z->p->p->r;// z 的叔叔 y
                    if (y->c == RED) {// case 1:叔叔是红的
                        z->p->c = BLACK;// 将 z 的父亲与叔叔置为黑
                        y->c = BLACK;
                        z->p->p->c = RED;// 将 z 的爷爷置为红
                        z = z->p->p;// 问题上移两层
                    }
                    else {
                        if (z == z->p->r) {// case 2:z 是右儿子
                            z = z->p;
                            leftRotate(z);// 左旋,转为 case 3
                        }
                        z->p->c = BLACK;// case 3:z 是左儿子,对z的爷爷做一次右旋即可完成维护
                        z->p->p->c = RED;
                        rightRotate(z->p->p);
                    }
                }
                else if (z->p == z->p->p->r) {// z 的父亲是爷爷的右儿子
                    y = z->p->p->l;// z 的叔叔 y
                    if (y->c == RED) {// case 1:叔叔是红的
                        z->p->c = BLACK;// 将 z 的父亲与叔叔置为黑
                        y->c = BLACK;
                        z->p->p->c = RED;// 将 z 的爷爷置为红
                        z = z->p->p;// 问题上移两层
                    }
                    else {
                        if (z == z->p->l) {// case 2:z 是左儿子
                            z = z->p;
                            rightRotate(z);// 右旋,转为 case 3
                        }
                        z->p->c = BLACK;
                        z->p->p->c = RED;
                        leftRotate(z->p->p);
                    }
                }
            }
            root->c = BLACK;
        }
    /*********************************************/
        NODE* treeMinimum(NODE *rt) {
            while (rt->l!=nil) rt=rt->l;
            return rt;
        }
        NODE* treeMaximum(NODE *rt) {
            while (rt->r!=nil) rt=rt->r;
            return rt;
        }
        NODE* treeSuccessor(NODE *rt) {
            if (rt->r!=nil) return treeMinimum(rt->r);
            NODE* pt=rt->p;
            while (pt!=nil && rt==pt->r) {
                rt=pt;
                pt=pt->p;
            }
            return pt;
        }
        NODE* treePredecessor(NODE *rt) {
            if (rt->l!=nil) return treeMaximum(rt->l);
            NODE* pt=rt->p;
            while (pt!=nil && rt==pt->l) {
                rt=pt;
                pt=pt->p;
            }
            return pt;
        }
    /*********************************************/
        NODE* rbDelete(NODE *z) {
            NODE *y, *x, *t;
            t = z;
            while (t != root) {
                t = t->p;
                t->size -= 1;
            }
            if (z->l == nil || z->r == nil) { y = z; }
            else { y = treeSuccessor(z); }
            if (y->l != nil) { x = y->l; }
            else { x = y->r; }
            x->p = y->p;
            if (y->p == nil) { root = x; }
            else {
                if (y == y->p->l) { y->p->l = x; }
                else { y->p->r = x; }
            }
            if (y != z) {
                z->key = y->key;
                // copy y's satellite data into z
            }
            if (y->c == BLACK) { rbDeleteFixup(x); }
            return y;
        }
        void rbDeleteFixup(NODE *x) {
            NODE *w;
            while (x != root && x->c == BLACK) {
                if (x == x->p->l) {// x 为左儿子
                    w = x->p->r;// w 是 x 的兄弟
                    if (w->c == RED) {// case 1:w 为红色,必有黑色儿子
                        w->c = BLACK;
                        x->p->c = RED;
                        leftRotate(x->p);
                        w = x->p->r;// x 的新兄弟必为黑色
                    }
                    if (w->l->c == BLACK && w->r->c == BLACK) {// case 2:x 的兄弟 w 是黑色的,w 的两个儿子都是黑色
                        w->c = RED;// 去掉一重黑色
                        x = x->p;// 以 x 父亲重复 while 循环
                    }
                    else {
                        if (w->r->c == BLACK) {// case 3:x 的兄弟 w 是黑色的,w 的左儿子是红色的,右儿子是黑色
                            w->l->c = BLACK;// 交换 w 与左儿子的颜色
                            w->c = RED;
                            rightRotate(w);// w 右旋
                            w = x->p->r;// 新兄弟是一个有红色右孩子的黑结点
                        }
                        w->c = x->p->c;// case 4:x 的兄弟 w 是黑色的,而且 w 的右儿子是红色的
                        x->p->c = BLACK;
                        w->r->c = BLACK;
                        leftRotate(x->p);
                        x = root;
                    }
                }
                else if (x == x->p->r) {// x 为右儿子
                    w = x->p->l;// w 是 x 的兄弟
                    if (w->c == RED) {// case 1:w 为红色,必有黑色儿子
                        w->c = BLACK;
                        x->p->c = RED;
                        rightRotate(x->p);
                        w = x->p->l;// x 的新兄弟必为黑色
                    }
                    if (w->l->c == BLACK && w->r->c == BLACK) {// case 2:x 的兄弟 w 是黑色的,w 的两个儿子都是黑色
                        w->c = RED;// 去掉一重黑色
                        x = x->p;// 以 x 父亲重复 while 循环
                    }
                    else {
                        if (w->l->c == BLACK) {// case 3:x 的兄弟 w 是黑色的,w 的右儿子是红色的,左儿子是黑色
                            w->r->c = BLACK;// 交换 w 与右儿子的颜色
                            w->c = RED;
                            leftRotate(w);// w 左旋
                            w = x->p->l;// 新兄弟是一个有红色左孩子的黑结点
                        }
                        w->c = x->p->c;// case 4:x 的兄弟 w 是黑色的,而且 w 的左儿子是红色的
                        x->p->c = BLACK;
                        w->l->c = BLACK;
                        rightRotate(x->p);
                        x = root;
                    }
                }
            }
            x->c = BLACK;
        }
    /*********************************************/
        NODE* treeSearch(NODE *rt,T k) {
            if (rt==nil || k==rt->key) return rt;
            if (k<rt->key) return treeSearch(rt->l,k);
            else return treeSearch(rt->r,k);
        }
        void remove(T key) {
            NODE *p = treeSearch(root,key);
            if (p != nil) p = rbDelete(p);
            deleteNode(p);
        }
    /*********************************************/
        void insert(T key) {
            rbInsert(newNode(key));
        }
        void showAll(NODE *p) {
            if (p != nil) {
                std::cout << "key = " << p->key << ", color = " << p->c << ", size = " << p->size << std::endl;
                std::cout << "LEFT:" << std::endl;
                showAll(p->l);
                std::cout << "RIGHT:" << std::endl;
                showAll(p->r);
                std::cout << "END." << std::endl;
            }
            //else { std::cout << " NIL " << endl; }
        }
    /*********************************************
        数据结构的扩张
    *********************************************/
        NODE* osSelect(NODE* x, int i) {
            int r = x->l->size + 1;
            if (i == r) { return x; }
            else if (i < r) { return osSelect(x->l,i); }
            else { return osSelect(x->r,i-r); }
        }
        int osRank(NODE* x) {
            int r = x->l->size + 1;
            NODE *y = x;
            while (y != root) {
                if (y == y->p->r) { r += y->p->l->size + 1;}
                y = y->p;
            }
            return r;
        }
    };



    【练习】




  • 相关阅读:
    传值与传引用
    【M10】在构造方法内阻止资源泄漏
    【M9】利用destructors避免泄漏资源
    C++异常
    【M5】对定制的“类型转换函数”保持警觉
    方法调用的方式
    Fatal Error: TXK Install Service oracle.apps.fnd.txk.config.ProcessStateException: OUI process failed : Exit=255 See log for details
    here was insufficient free space available after evicting expired cache entries
    python
    Python Decorator 和函数式编程
  • 原文地址:https://www.cnblogs.com/cyendra/p/3687866.html
Copyright © 2011-2022 走看看