黑红树 RedBlackTree

RedBlackTree

API

int Size() 返回大小
int Size(Key low, Key high) 返回 low 到 high 间的元素个数
bool isEmpty() 是否为空
Key Min() 返回最小元素
Key Max() 返回最大元素
int height() 返回树的高度
Value get(Key key) 返回键对应的值
bool contains(Key key) 是否含有键key
void put(Key key, Value val) 插入键key和对应的值
void deleteMin() 删除最小键
void deleteMax() 删除最大键
void deleteKey(Key key) 删除键和其对应的值
Key floor(Key key) 返回比key小的最大键
Key ceiling(Key key) 返回比key大的最小键
int rank(Key key) 返回key的排名
Key select(int rank) 返回排名为rank的key
bool isBanlanced() 是否平衡
vector<pair<int, int>> keys() 中序返回所有元素
vector<pair<int, int>> keys(Key low, Key high) 中序返回low到high间的元素
void traverse(ostream& os, Node* node) 同上二


性能分析


无论键的插入顺序如何,红黑树都是几乎完美平衡的
一棵大小为 N 的红黑树,高度不会超过 2lgN
一棵大小为 N 的红黑树,根结点到任意结点的平均路径约为 lgN

能保证对数级别的查找和插入操作



性质


红黑树既是二叉查找树,也是2-3树
结合二叉查找树高效的 get,和2-3树中高效的 put
不存在两条连续的红链接或红色的右链接
根结点是黑色

树的链接分为两种类型
红链接将两个2-结点连起来构成一个3-结点
黑链接则是2-3树中的普通链接
注:空链接是黑色
3-结点表示为由一条左斜的红色链接相连的两个2-结点
两个2-结点其中之一是另一个的左子结点
这样储存,无需修改即可直接使用标准二叉查找树的get()方法
将红链接画平,所有空链接到结点的距离相同
将红链接相连的点合并,得到的就是一棵2-3树

指向该结点的链接的颜色是红色 color = true
若为黑色 color = black



操作


(部分操作未写出,直接在代码里)

1.旋转

 在操作时,可能会出现红色右链接或者两条连续的红链接
 此时需要旋转,改变红链接的指向

 左旋:将右链接转化为左链接
   即将两个键中较小的作根结点变为较大的作根根结点

 右旋:代码与左旋相反

 旋转后返回一条链接,可能是左链接也可能是右链接,将其与父链接相连
 通过将x.color设为h.color保留它原来的颜色
 若产生两条连续的红链接,继续旋转

 h = rotateLeft(h)
 旋转结点h的红色右链接,使得h指向旋转后的子树的根结点
              |                                 |
             h                                  x
        <h          x                     h           >x
               h<&<x  >x               <h  h<&<x


2.向单个2-结点中插入新键

 一棵只含一个键的红黑树只含有一个2-结点,插入另一个键后,需要旋转
 若新键小于老键,直接新增一个红色节点
 若新键大于老键,产生一条红色的右链接,需要 root = rotateLeft(root)


3.向树底部的2-结点插入新键

 用红链接将新结点和它的父结点相连
 若指向新结点的是父节点的左链接,则父节点成为一个3-结点
 若指向新结点的是父节点的右链接,则需要左旋


4.向只含有一个3-结点的树中插入新键

 若新键大于原树中的两个键
   用红链接将新键连接到3-结点的右链接
   将两条红链接变成黑色
   得到一个由三个结点构成的平衡树(高为2)
 若新键小于原树中的两个键
   用红链接将新键连接到3-结点的左链接
   产生连续的红链接
   将上一层的红链接右旋,得到情况1
   将两个红链接变成黑色
 若新建介于原树中的两个键之间
   用红链接将新键插在3-结点的中链接
   新的链接为红色的右链接
   左旋,将红色的右链接变为红色的左链接
   产生连续的红链接,得到情况2
   将上一层的红链接右旋,得到情况1
   将两个红链接变为黑链接


5.颜色转换

 flipColors() 转换一个结点的两个红色子结点的颜色
 并将父节点的颜色由黑变红
 若根结点变为红色,说明跟结点是3-结点的一部分,不成立
 故根结点一定是黑色
 注:每当根结点由红变黑时,树的黑链接高度+1


6.向低部的3-结点插入新键

 若指向结点的是右链接
  转换颜色
 若指向结点的是左链接
  进行右旋,并转换颜色
 若指向结点的是中链接
  左旋下层链接,再右旋上层链接,并转换颜色


7.删除最小键

 在树的底部删除3-结点很简单,删除2-结点比较复杂
 为保证不删除一个2-结点,沿左链接向下进行变换
 确保当前结点不是2-结点,可以是3-结点或临时的4-结点
 若根结点是2-结点且他的两个子结点都是2-结点,可以将这三个节点变成一个4-结点
 否则需要保证左子结点不是2-结点
 若有必要可以从他的右侧的兄弟节点借一个键过来
 沿着左链接向下的过程中
  如果当前结点的左子结点不是2-结点,完成
  如果当前结点的左子结点是2-结点而左子结点的亲兄弟节点不是2-结点
   则向兄弟节点借一个键
  如果当前结点的左子结点和左子结点的亲兄弟节点都是2-结点
   将左子结点,父节点中的最小键和左子结点最近的兄弟结点合并成一个4-结点
    使父结点由3-结点变成2-结点或由4-结点变成2-结点
 在遍历的过程中执行这个操作,最后能够得到一个含有最小键的3-结点或者4-结点
 直接将最小键删除,并向上分解所有临时的4-结点


8.删除

  在查找路径上进行和删除最小键相同的变换
  可以保证在查找过程中任意当前结点均不是2-结点
  如果删除的键在底部,可以直接删除
  如果不在底部,将它和后继结点交换


Code

// Red-Black-Tree

#include <iostream>
#include <vector>
using namespace std;

#define RED true
#define BLACK false
typedef string Key;
typedef int Value;
typedef pair<Key, Value> PKV;
const int flag = 0x3f3f3f3f;


class Node{
    
public:
    
    Key key;
    Value val;
    Node *left, *right;
    int N;
    bool color;
    
    Node(Key key, Value val, int N, bool color){
        this->key = key;
        this->val = val;
        this->color = color;
        this->N = N;
        left = NULL;
        right = NULL;
    }
    
};



class RBT{
    
public:
    
    int Size()
    { return Size(root); }
    
    int Size(Key low, Key high);
    
    bool isEmpty()
    { return root == NULL; }
    
    Key Min()
    { if (isEmpty()) return NULL; return Min(root)->key; }
    
    Key Max()
    { if (isEmpty()) return NULL; return Max(root)->key; }
    
    int height()
    { return height(root); }
    
    Value get(Key key)
    { return get(root, key); }
    
    bool contains(Key key)
    { return get(key) != flag; }
    
    //找到就更新,否则创建新结点
    void put(Key key, Value val);
    
    void deleteMin();
    
    void deleteMax();
    
    void deleteKey(Key key);
    
    Key floor(Key key);
    
    Key ceiling(Key key);
    
    int rank(Key key)
    { return rank(key, root); }
    
    Key select(int rank);
    
    bool isBalanced();
    
    vector< pair<Key, Value> > keys()
    { return keys(Min(), Max()); }
    
    vector< pair<Key, Value> > keys(Key low, Key high){
        vector< pair<Key, Value> > vec;
        keys(root, vec, low, high);
        return vec;
    }
    
    void traverse(ostream& os, Node* node){
        if (node == NULL) return;
        traverse(os, node->left);
        os << node->key << "\t\t\t\t" << node->val << endl;
        traverse(os, node->right);
    }
    
    RBT()
    { root = NULL; }
    
    ~RBT()
    { traverse_delete(root); }
    
    
private:
    
    Node* root;
    
    int Size(Node* x);
    
    Node* Min(Node* x);
    
    Node* Max(Node* x);
    
    int height(Node* x);
    
    bool isRed(Node* x);                        //判断是红链接还是黑链接
    
    int compareTo(Key k1, Key k2);              //比较键的大小
    
    void flipColors(Node* h);                   //翻转结点两个子结点的颜色,及自身颜色
    
    Node* rotateLeft(Node* h);                  //左旋
    
    Node* rotateRight(Node *h);                 //右旋
    
    Value get(Node* x, Key key);                //返回x子树中,key对应的Value
    
    Node* put(Node* h, Key key, Value val);     //在结点h的子树中插入
    
    Node* deleteMin(Node* h);                   //删除h的子树中的最小键
    
    Node* deleteMax(Node* h);                   //删除h的子树中的最大值
    
    Node* moveRedLeft(Node* h);
    
    Node* moveRedRight(Node* h);
    
    Node* balance(Node* h);
    
    Node* deleteKey(Node* h, Key key);
    
    Node* floor(Node* x, Key key);

    Node* ceiling(Node* x, Key key);
    
    int rank(Key key, Node* x);
    
    Key select(Node* x, int rank);
    
    bool isBalanced(Node* x, int black);
    
    void keys(Node* x, vector< pair<Key, Value> >& vec, Key low, Key high);
    
    void traverse_delete(Node* node){
        if (node != NULL){
            Node* Left = node->left;
            Node* Right = node->right;
            delete(node);
            traverse_delete(Left);
            traverse_delete(Right);
        }
    }
    
};


int RBT::Size(Node* x){
    if (x == NULL) return 0;
    return x->N;
}

int RBT::Size(Key low, Key high){
    if (compareTo(low, high) > 0) return 0;
    if (contains(high)) return rank(high) - rank(low) + 1;
    else return rank(high) - rank(low);
}


bool RBT::isRed(Node* x){
    if (x == NULL) return false;
    return x->color == RED;
}


int RBT::compareTo(Key k1, Key k2){
    if (k1 < k2) return -1;
    if (k1 > k2) return  1;
    return 0;
}


Node* RBT::Min(Node* h){
    if (h == NULL) return NULL;
    if (h->left == NULL) return h;
    else return Min(h->left);
}


Node* RBT::Max(Node* h){
    if (h->right == NULL) return h;
    else return Max(h->right);
}


int  RBT::height(Node* x){
    if (x == NULL) return -1;
    return 1 + max(height(x->left), height(x->right));
}


void RBT::flipColors(Node* h){
    h->color = !h->color;
    h->left->color  = !h->left->color;
    h->right->color = !h->right->color;
}


Node* RBT::rotateLeft(Node* h){
    Node* x = h->right;
    h->right = x->left;
    x->left = h;
    x->color = h->color;
    h->color = RED;
    x->N = h->N;
    h->N = 1 + Size(h->left) + Size(h->right);
    return x;
}

Node* RBT::rotateRight(Node *h){
    Node* x = h->left;
    h->left = x->right;
    x->right = h;
    x->color = h->color;
    h->color = RED;
    x->N = h->N;
    h->N = 1 + Size(h->left) + Size(h->right);
    return x;
}


Value RBT::get(Node* x, Key key){
    while (x != NULL){
        int cmp = compareTo(key, x->key);
        if (cmp < 0) x = x->left;
        else if (cmp > 0) x = x->right;
        else return x->val;
    }
    return flag;
}


void RBT::put(Key key, Value val){
    root = put(root, key, val);
    root->color = BLACK;
}


Node* RBT::put(Node* h, Key key, Value val){
    if (h == NULL)              //和父节点用红链接相连
        return new Node(key, val, 1, RED);
    
    int cmp = compareTo(key, h->key);
    if (cmp < 0) h->left = put(h->left, key, val);
    else if (cmp > 0) h->right = put(h->right, key, val);
    else h->val = val;
    
    if (isRed(h->right) && !isRed(h->left))     h = rotateLeft(h);
    if (isRed(h->left) && isRed(h->left->left)) h = rotateRight(h);
    if (isRed(h->left) && isRed(h->right))      flipColors(h);
    
    h->N = Size(h->left) + Size(h->right) + 1;
    return h;
}


void RBT::deleteMin(){
    if (isEmpty()) return;
    
    //if both children of root are balck, set root to red
    if (!isRed(root->left) && !isRed(root->right))
        root->color = RED;
    
    root = deleteMin(root);
    if (!isEmpty()) root->color = BLACK;
}

    
Node* RBT::deleteMin(Node* h){
    if (h->left == NULL)
        return NULL;
    
    if (!isRed(h->left) && !isRed(h->left->left))
        h = moveRedLeft(h);
    
    h->left = deleteMin(h->left);
    return balance(h);
}


void RBT::deleteMax(){
    if (isEmpty()) return;
    
    //if both children of root are balck, set root to red
    if (!isRed(root->left) && !isRed(root->right))
        root->color = RED;
    
    root = deleteMax(root);
    if (!isEmpty()) root->color = BLACK;
}


Node* RBT::deleteMax(Node* h){
    //红色链接都是左链接,此处代码与deleteMin会有不同
    if (isRed(h->left))
        h = rotateRight(h);
    
    if (h->right == NULL)
        return NULL;
    
    if (!isRed(h->right) && !isRed(h->right->right))
        h = moveRedRight(h);
    
    h->right = deleteMax(h->right);
    return balance(h);
}


Node* RBT::moveRedLeft(Node* h){
    //结点h为红色,h->left h->left->left 为黑色
    //将 h->left 或 h->left的子结点之一变红
    flipColors(h);
    if (isRed(h->right->left)){
        h->right = rotateRight(h->right);
        h = rotateLeft(h);
        flipColors(h);
    }
    return h;
}


Node* RBT::moveRedRight(Node* h){
    flipColors(h);
    if (isRed(h->left->left)){
        h = rotateRight(h);
        flipColors(h);
    }
    return h;
}


Node* RBT::balance(Node* h){
    if (isRed(h->right) && !isRed(h->left))
        h = rotateLeft(h);
    if (isRed(h->left) && isRed(h->left->left))
        h = rotateRight(h);
    if (isRed(h->left) && isRed(h->right))
        flipColors(h);
    
    h->N = Size(h->left) + Size(h->right) + 1;
    return h;
}


void RBT::deleteKey(Key key){
    if (!contains(key)) return;
    
    if (!isRed(root->left) && !isRed(root->right))
        root->color = RED;
    
    root = deleteKey(root, key);
    if (!isEmpty()) root->color = BLACK;
}


Node* RBT::deleteKey(Node* h, Key key){
    if (compareTo(key, h->key) < 0){
        if (!isRed(h->left) && !isRed(h->left->left))
            h = moveRedLeft(h);
        h->left = deleteKey(h->left, key);
    }
    else{
        if (isRed(h->left))
            h = rotateRight(h);
        if (compareTo(key, h->key) == 0 && (h->right == NULL))
            return NULL;
        if (!isRed(h->right) && !isRed(h->right->left))
            h = moveRedRight(h);
        if (compareTo(key, h->key) == 0){
            Node* x = Min(h->right);
            h->key = x->key;
            h->val = x->val;
            h->right = deleteMin(h->right);
        }
        else{
            h->right = deleteKey(h->right, key);
        }
    }
    return balance(h);
}


Key RBT::floor(Key key){
    if (isEmpty()) return NULL;
    Node* x = floor(root, key);
    if (x == NULL) return NULL;
    else return x->key;
}

Node* RBT::floor(Node* x, Key key){
    if (x == NULL) return NULL;
    int cmp = compareTo(key, x->key);
    if (cmp == 0) return x;
    if (cmp < 0) return floor(x->left, key);
    Node* t = floor(x->right, key);
    if (t != NULL) return t;
    else return x;
}


Key RBT::ceiling(Key key){
    if (isEmpty()) return NULL;
    Node* x = ceiling(root, key);
    if (x == NULL) return NULL;
    else return x->key;
}

Node* RBT::ceiling(Node* x, Key key){
    if (x == NULL) return NULL;
    int cmp = compareTo(key, x->key);
    if (cmp == 0) return x;
    if (cmp > 0) return ceiling(x->right, key);
    Node* t = ceiling(x->left, key);
    if (t != NULL) return t;
    else return x;
}


int RBT::rank(Key key, Node* x){
    if (x == NULL) return 0;
    int cmp = compareTo(key, x->key);
    if (cmp < 0) return rank(key, x->left);
    else if (cmp > 0) return 1 + Size(x->left) + rank(key, x->right);
    else return Size(x->left);
}


Key RBT::select(int rank){
    if (rank < 0 || rank >= Size()) return NULL;
    return select(root, rank);
}

Key RBT::select(Node* x, int rank){
    if (x == NULL) return NULL;
    int leftSize = Size(x->left);
    if (leftSize > rank) return select(x->left, rank);
    else if (leftSize < rank) return select(x->right, rank - leftSize - 1);
    else return x->key;
}


bool RBT::isBalanced(){
    int black = 0;
    Node* x = root;
    while (x != NULL){
        if (!isRed(x)) black ++;
        x = x->left;
    }
    return isBalanced(root, black);
}

bool RBT::isBalanced(Node* x, int black){
    if (x == NULL) return black == 0;
    if (!isRed(x)) black --;
    return isBalanced(x->left, black) && isBalanced(x->right, black);
}


void RBT::keys(Node* x, vector< pair<Key, Value> >& vec, Key low, Key high){
    if (x == NULL) return;
    int cmpLow = compareTo(low, x->key);
    int cmpHigh = compareTo(high, x->key);
    if (cmpLow < 0) keys(x->left, vec, low, high);
    if (cmpLow <= 0 && cmpHigh >= 0) vec.push_back(make_pair(x->key, x->val));
    if (cmpHigh > 0) keys(x->right, vec, low, high);
}


int main(){
    RBT rbt;
    rbt.put("a", 3124);
    rbt.put("d", 3124);
    rbt.put("dd", 3124);
    rbt.put("e", 3124);
    rbt.put("ee", 3124);
    rbt.put("cc", 3124);
    rbt.put("c", 3124);
    rbt.put("b", 3124);
    rbt.put("b", 1111);
    rbt.put("bb", 3124);
    rbt.deleteKey("a");
    cout << rbt.floor("ccc") << endl;
    cout << rbt.ceiling("ccc") << endl;
    cout << rbt.rank("cc") << endl;
    cout << rbt.select(5) << endl;
    cout << rbt.Size() << endl;
    cout << rbt.height() << endl;
    vector<PKV> res = rbt.keys();
    for (int i = 0; i < res.size(); i ++)
        cout << res[i].first << ' ' << res[i].second << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
vruntime黑红是一种用于进程调度的数据结构,它的设计目的是为了提高多任务操作系统中进程调度的效率和准确性。下面是关于vruntime黑红的回答: vruntime是指虚拟运行时间,在进程调度中用于衡量进程的优先级高低。而黑红是一种自平衡的二叉搜索,它通过对节点的颜色进行调整以保持的平衡。vruntime黑红将进程的vruntime值作为节点的键值,通过黑红的自平衡特性,可以快速地找到最小vruntime值的进程进行调度。 在vruntime黑红中,每个节点表示一个进程,节点的vruntime值用于比较进程的优先级。中的节点按照vruntime值从小到大排列,即的最左侧节点的vruntime值最小。通过对黑红进行旋转、颜色调整等操作,可以快速地插入新的进程节点,并找到最小vruntime值的进程节点进行调度。 通过使用vruntime黑红,进程调度可以更加高效、公平。当新的进程加入系统时,将根据其vruntime值插入到黑红中的合适位置。而在每次调度时,系统会选择具有最小vruntime的进程进行运行,保证了优先级最高的进程能够被及时调度。 vruntime黑红的设计不仅提高了调度效率,还使得调度更公平,避免了某个进程长期占用CPU的情况。它遵循了红黑的平衡特性,保证了的高度相对较低,从而加速了插入和查找操作。 总之,vruntime黑红是一种用于进程调度的数据结构,通过使用虚拟运行时间作为优先级指标,并通过黑红的平衡特性实现了高效、公平的进程调度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值