區間樹


《算法導論》描述了一個關於區間樹的重疊搜索,這里簡單描述下原理,然后給出代碼。

區間樹是建立在紅黑樹的基礎上,額外維護了一個信息域。在《算法導論》中,已經給出了任何額外信息域的維護,是相似的證明。所以,建議不懂得,先試着實現一個基本的,帶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;
}

 

所有代碼均經過測試,結果正確!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM