红黑树特殊性质:
1.每个结点或是红色的,或是黑色的;
2.根结点是黑色的;
3.每个叶节点是黑色的;
4.若一个是红色的,则他的两个子节点都是黑色的;
5.对每个结点,从该结点到其所有后代叶节点的简单路径上,黑色结点数相同
(
这里的叶节点指的是空结点,参考算法导论,设置一个尾指针Nail代表叶节点,空的左右孩子一律连接在Nail上)
高度:
一.类:
enum color { RED, BLACK }; struct Node { int key; color co; Node* left; Node* right; Node* p; Node(int k, Node* a, Node* b, color c) :key(k), co(c), left(a), right(b), p(nullptr) {} }; class Tree { private: Node * root; void Left(Node* x); void Right(Node* x); void Transplant(Node* u, Node* v); void preOrder(Node*); void inOrder(Node*); void postOrder(Node*); int height(Node*); Node* Max(); Node* Min(); public: Node * Root() { return root; } Node* Nail; Tree(); bool Insert(int k); void bfs(Node*); void Delete(Node* z); Node* Min(Node* x); Node* Search(int k); void PreOrder(); void InOrder(); void PostOrder(); Node* max(Node*); Node* min(Node*); int Height(); };
二.旋转操作:左旋和右旋
void Tree::Left(Node* x) { Node* s = x->right; x->right = s->left; if (s->left != Nail)//防止对尾指针操作 s->left->p = x; s->p = x->p; if (x->p == Nail)//更新根结点 { root = s; } else if (x == x->p->left) x->p->left = s; else x->p->right = s; s->left = x; x->p = s; } void Tree::Right(Node* x) { Node* s = x->left; x->left = s->right; if (s->right != Nail) s->right->p = x; s->p = x->p; if (x->p == Nail) root = s; else if (x == x->p->left) x->p->left = s; else x->p->right = s; s->right = x; x->p = s; }
三.插入操作:
插入z时,将z先作为红色。此时,性质1,3,5均不会被破坏。若z是根结点,则性质2被破坏;若z的父节点为红色,则性质4被破坏。
实现中使用迭代更新z,while中保持如下循环不变式:
1. z为红色结点
2. 若z.p为根结点,则z.p为黑色结点
3. 性质至多只有一条没破坏,或者为2、或者为4.
Case1: z的叔结点y为红色。z.p.p(原来必为黑)变成红色;z.p和y着为黑色。z.p.p成为新的z结点重复while循环。
扫描二维码关注公众号,回复:
1048842 查看本文章
这时,以z.p.p为根的子树中红黑树性质不变,且各路径上黑色结点数目不变,性质5不可能被破坏。
Case2: y为黑色且z为一个右结点
Case3: y为黑色且z为一个左结点
此时z.p为黑色,不必再重复while循环。
bool Tree::Insert(int k) { Node* z = new Node(k, Nail, Nail, RED);//先设置为红色 Node* x = root; Node* y = Nail; while (x != Nail)//寻找插入位置 { y = x; if (z->key < x->key) x = x->left; else if (z->key > x->key) x = x->right; else { cout << "Two equal is banned!\n"; return false; } } //x指向尾节点,y为该路径上最后一个非空结点 z->p = y; if (y == Nail)//空树 root = z; else if (z->key < y->key) y->left = z; else y->right = z; while (z != root && z->p->co == RED)//开始循环 { if (z->p == z->p->p->left)//确定叔结点是左孩子还是右孩子 { y = z->p->p->right;//y是z的叔结点 if (y->co == RED)// Case1 { z->p->co = BLACK; z->p->p->co = RED; y->co = BLACK; z = z->p->p; } else { if (z == z->p->right) //Case2 转化为 Case3 { z = z->p;//更新z Left(z); } z->p->co = BLACK; z->p->p->co = RED; Right(z->p->p); } } else//同上 { y = z->p->p->left; if (y->co == RED) { z->p->co = BLACK; z->p->p->co = RED; y->co = BLACK; z = z->p->p; } else { if (z == z->p->left) { z = z->p; Right(z); } z->p->co = BLACK; z->p->p->co = RED; Left(z->p->p); } } } root->co = BLACK; return true; }
四.删除:
首先一个子过程,用于替换结点
void Tree::Transplant(Node* u, Node* v)//以v替换u { if (u->p == Nail) root = v; else if (u == u->p->left) u->p->left = v; else u->p->right = v; if (v != Nail) v->p = u->p; }
令z为要删除的结点,y为实际删除或移动的结点,x为y的孩子。
当z有两个孩子,y为z的后继,并将y移动至z的位置,同时必须记录y原来的颜色,y的实际颜色变为z的颜色。x移动到y原来的位置。
此时,若y原来为红色,则红黑树性质仍保持,原因如下:
1.树的黑高没有变化;
2.不存在两个相邻的红节点(x一定为黑色);
3.y是红色,则y不可能是根结点,根结点仍为黑色。
若y为黑色会产生三个问题:
1.若y为根结点,同时y的一个红孩子成了根结点,违反性质2;
2.若x和x.p为红色,违反性质5;
3.在树中移动y会导致原先包含y的简单路径上黑结点数少一。
现维护红黑树性质,分四种情况:
(若x为红色,直接着色为黑色即可)(x为黑色是迭代,以下维持性质4)
(x可理解为包含了所有黑色结点均少一的简单路径的子树)
Case1: x的兄弟结点w为红色。通过一次左旋转换为情况二,同时w和x.p的颜色互换。
Case2: x的兄弟结点w为黑色,w的两个子节点都是黑色。w着色为红色,x上移为x.p。(拉兄弟下水)
若是由Case1转向的Case2,则在循环测试时可终止。(新的x为红色)(情况一下,w为红色,则x.p必为黑色,互换后 变为红色)。
Case3: x的兄弟结点w为黑色,w左孩子红,w右孩子黑。右旋,并交换w和w.left的颜色,x不变,更新w。转到Case。
Case4: x的兄弟节点w为黑色,w右孩子为红色。对x.p一次左旋。w.right着色为黑色,w着色为x.p的颜色,x.p不论红黑均着 色为黑色。此时x包含的简单路径黑色结点数加一,其余不变,性质得到维持,x设为根,可以跳出循环。
(寻求使x的父节点变成红色再被设置为黑色)
void Tree::Delete(Node* z) { color Ori = z->co;//y原先的颜色 Node* x;//实际消失结点的孩子 Node* y = z;//y实际消失的结点 if (z->left == Nail) { x = z->right; Transplant(z, z->right); } else if (z->right == Nail) { x = z->left; Transplant(z, z->left); } else//左右皆非空,y应为z的后继 { y = Min(z->right); Ori = y->co;//y发生改变,更新y原来的颜色 x = y->right; if (y->p != z) { Transplant(y, y->right); y->right = z->right; y->right->p = y; } Transplant(z, y); y->left = z->left; y->left->p = y; y->co = z->co; } if (Ori == BLACK)//维持性质 { Node* w; if (x == Nail)//便于对叶节点操作 x->p = y; while (x != root && x->co == BLACK) { if (x == x->p->left) { w = x->p->right; if (w->co == RED) { w->co = BLACK; x->p->co = RED; Left(x->p); w = x->p->right; } if (w->left->co == BLACK && w->right->co == BLACK) { w->co = RED; x = x->p; } else { if (w->right->co == BLACK) { w->left->co = BLACK; w->co = RED; Right(w); w = x->p->right; } w->co = x->p->co; x->p->co = BLACK; w->right->co = BLACK; Left(x->p); x = root; } } else//与上面对称 { w = x->p->left; if (w->co == RED) { w->co = BLACK; x->p->co = RED; Right(x->p); w = x->p->left; } if (w->right->co == BLACK && w->left->co == BLACK) { w->co = RED; x = x->p; } else { if (w->left->co == BLACK) { w->right->co = BLACK; w->co = RED; Left(w); w = x->p->left; } w->co = x->p->co; x->p->co = BLACK; w->left->co = BLACK; Right(x->p); x = root; } } } x->co = BLACK; } }
其它功能:
Node* Tree::Search(int x) { Node* t = root; while (t != Nail && t->key != x) { if (x < t->key) t = t->left; else t = t->right; } return t; } Node* Tree::Min(Node* x) //以x为根子树最小元素 { while (x->left != Nail) x = x->left; return x; } void Tree::bfs(Node* x) { if (x == Nail) return; queue<Node*> q; q.push(x); Node* t; while (!q.empty()) { t = q.front(); q.pop(); if (t->left != Nail) { if (t->co == RED) cout << "RED "; else cout << "BLACK "; cout << t->key << "'s L : "; if (t->left->co == RED) cout << "RED "; else cout << "BLACK "; cout << t->left->key << '\t' << endl; q.push(t->left); } if (t->right != Nail) { if (t->co == RED) cout << "RED "; else cout << "BLACK "; cout << t->key << "'s R : "; if (t->right->co == RED) cout << "RED "; else cout << "BLACK "; cout << t->right->key << endl; q.push(t->right); } } } void Tree::preOrder(Node* a) { if (a != nullptr) { cout << a->key; preOrder(a->left); preOrder(a->right); } } void Tree::PreOrder() { preOrder(root); } void Tree::inOrder(Node* a) { if (a != nullptr) { inOrder(a->left); cout << a->key; inOrder(a->right); } } void Tree::InOrder() { inOrder(root); } void Tree::postOrder(Node* a) { if (a != nullptr) { postOrder(a->left); postOrder(a->right); cout << a->key; } } void Tree::PostOrder() { postOrder(root); } Node* Tree::max(Node* t) { if (t == nullptr || t == Nail) return nullptr; else { while (t->right != Nail) t = t->right; return t; } } Node* Tree::Max() { return max(root); } Node* Tree::min(Node* t) { if (t == Nail || t == nullptr) return nullptr; else { while (t->left != Nail) t = t->left; return t; } } Node* Tree::Min() { return min(root); } int Tree::height(Node* t) { int h1 = 0, h2 = 0; if (t != Nail) { h1 = height(t->left) + 1; h2 = height(t->right) + 1; return h1 > h2 ? h1 : h2; } else return 0; } int Tree::Height() { return height(root); }