C++实现仅有孩子节点的红黑树
在旋转时用栈存储叔叔父亲祖先等等。
支持基本的插删查。
使用该红黑树编写的Map通过部分OJ,未发现bug。
/*
此版本无父指针,旋转时用栈确定祖先。
使用该红黑树编写的Map通过部分OJ,未发现bug
*/
#include <queue>
#include <vector>
#include <stack>
#include <iostream>
#include <algorithm>
using namespace std;
#define RefValue -1e8
#define red 0
#define black 1
template<class K, class E>
struct RBNode {
bool color;
K key;
E data;
RBNode<K, E> *left, *right;
RBNode() {
left = NULL;
right = NULL;
color = red;
}
RBNode(E d, K k, bool c = red, RBNode<K, E> *l = NULL, RBNode<K, E> *r = NULL) {
data = d;
left = l;
right = r;
key = k;
color = c;
}
};
template<class K, class E>
class RBTree{
public:
RBNode<K, E> *root;
size_t _size;
void RotateL(RBNode<K, E> *&ptr) {
RBNode<K, E> *subL = ptr;
ptr = ptr->right;
subL->right = ptr->left;
ptr->left = subL;
}
void RotateR(RBNode<K, E> *&ptr) {
RBNode<K, E> *subR = ptr;
ptr = ptr->left;
subR->left = ptr->right;
ptr->right = subR;
}
E & Search(RBNode<K, E> *&ptr, K k, bool& found) {
E tmp();
RBNode<K, E> *cur = ptr;
while (cur != NULL) {
if (k == cur->key) {
found = true;
return cur->data;
}
else if (k < cur->key) cur = cur->left;
else cur = cur->right;
}
found = false;
return tmp;
}
bool Insert(RBNode<K, E> *&ptr, E d, K k) {
RBNode<K, E> *cur = NULL, *p = NULL, *pp = NULL;
if (ptr == NULL) {
ptr = new RBNode<K, E>(d, k, black);
++_size;
return true;
}
stack<RBNode<K, E> *> st;
cur = ptr;
while (cur != NULL) {
st.push(cur);
pp = p;
p = cur;
if (k == cur->key) return false;
else if (k < cur->key) cur = cur->left;
else cur = cur->right;
}
cur = new RBNode<K, E>(d, k, red);
++_size;
if (k < p->key) {
p->left = cur;
}
else p->right = cur;
if (p->color == black) return true;
while(st.top() != pp) {
st.pop();
}
st.pop();
while (true) {
RBNode<K, E> *uncle = (pp->left == p) ? pp->right : pp->left;
if (p->color == black) break;
else if (uncle != NULL && uncle->color == red) {
pp->left->color = pp->right->color = black;
if (pp == root) break;
pp->color = red;
cur = pp;
}
else if (uncle == NULL || uncle->color == black) {
RBNode<K, E> *orgpp = pp; //原先的pp
if (pp->left == p) {
if (cur == p->right) {
RotateL(p);
pp->left = p;
cur = p->left;
}
pp->color = red;
p->color = black;
RotateR(pp);
}
else if (pp->right == p) {
if (cur == p->left) {
RotateR(p);
pp->right = p;
cur = p->right;
}
pp->color = red;
p->color = black;
RotateL(pp);
}
if (st.empty()) {
root = pp;
}
else {
RBNode<K, E> *ppp = st.top();
if (ppp->left == orgpp) ppp->left = pp;
else ppp->right = pp;
}
break;
}
p = st.top();//注意此时栈一定不空,如果空的话,前面一定break掉了,所以可以果断弹出
st.pop();
if (!st.empty()) { //这时候栈空不空就要看命了,如果这时候栈空,那么p就是root,下一次循环直接break,用不到pp
pp = st.top();
st.pop();
}
}
return true;
}
bool Remove(RBNode<K, E> *&ptr, K k) {
/*第一步是要找到删除节点*/
RBNode<K, E> *cur = NULL, *p = NULL, *brother = NULL;
stack<RBNode<K, E> *> st;
cur = ptr;
while (cur != NULL) {
st.push(cur);
p = cur;
if (k == cur->key) {
break;
}
else if (k < cur->key) cur = cur->left;
else cur = cur->right;
}
if (cur == NULL) {
//cout << cur << endl;
return false;
}
--_size;
if (st.top() == root && root->left == NULL && root->right == NULL) {
delete root;
root = NULL;
return true;
}
/*锁定替代节点,要求是叶节点或者只挂载一个孩子*/
if (cur->left != NULL && cur->right != NULL) {
RBNode<K, E> *subT = cur->right; //subT将是cur在中序下的后继节点,中序后继一定在右子树上
p = cur;
stack<RBNode<K, E> *> inOrderst;
/*下面这个循环是迭代寻找中序后继*/
while (subT != NULL || !inOrderst.empty()) {
if (subT != NULL) {
inOrderst.push(subT);
st.push(subT);
subT = subT->left;
}
else {
subT = inOrderst.top();
break;
}
}
cur->data = subT->data;
cur->key = subT->key;
//cout << cur->key << "replace\n";
cur = subT;
}
/*待删节点有一个孩子,待删节点肯定是黑色,而且这个孩子肯定是红色。
处理方式是待删节点父节点接上这个孩子,这个孩子置黑
如果这个待删节点是通过上面找后继找出来的,如果这个待删节点有一个孩子,一定是右孩子*/
st.pop();
if (!st.empty()) {
p = st.top();//将p赋值为代替节点的父节点
st.pop();
}
if (cur->left != NULL) {
cur->left->color = black;
if (cur != root) {
if (p->left == cur) p->left = cur->left;
else p->right = cur->left;
}
else root = cur->left;
delete cur;
return true;
}
else if (cur->right != NULL){
cur->right->color = black;
if (cur != root) {
if (p->left == cur) p->left = cur->right;
else p->right = cur->right;
}
else root = cur->right;
delete cur;
return true;
}
/*待删节点是叶节点*/
else if (cur->color == red){
if (p->left == cur) p->left = NULL;
else p->right = NULL;
delete cur;
return true;
}
/*待删的节点是黑色的叶节点,
注意根到待删节点的完整路径已经存在st中,
并且路径包含根和这个代替节点*/
/*黑色节点,需要考虑的情况比较多。注意如果待删节点是黑色,那么他一定有兄弟,不然也不满足黑色平衡
同时他兄弟有子节点也只可能是红色的!!!不可能有黑色子节点!!因为他自己是叶节点,这样会破坏平衡性*/
else {
RBNode<K, E> *pDel = cur, *ppDel = p;
while (true) {
//cout << "ASD" << endl;
//cout << st.size();
brother = (p->left == cur) ? p->right : p->left;
RBNode<K, E> *orgp = p;
if (cur->color == red || cur == root) {
if (pDel == ppDel->left) ppDel->left = NULL;
else pDel->right = NULL;
delete pDel;
return true;
}
//cout << "ASDsd" << endl;
if (cur == p->left) {
if (brother->color == red) { //兄弟节点是红的,由于红黑树平衡性要求,兄弟节点必有两个黑色子节点,而且父节点是黑色
p->color = red;
brother->color = black;
brother = brother->left; //为了可以经过情况四的处理
RotateL(p);
if (st.empty()) root = p;
else {
RBNode<K, E> *pp = st.top();
if (pp->left == orgp) pp->left = p;
else pp->right = p;
}
p = p->left;//新的双亲
}//再经过一次情况四的处理即可结束
else if (brother->color == black) {
//cout << "brother == black" << endl;
if (brother->right != NULL && brother->right->color == red) {
swap(brother->color, p->color);
brother->right->color = black;
RotateL(p);
if (st.empty()) root = p;
else {
RBNode<K, E> *pp = st.top();
if (pp->left == orgp) pp->left = p;
else pp->right = p;
}
break;
}
else if ((brother->right == NULL || brother->right->color == black) &&
(brother->left != NULL && brother->left->color == red)) {
swap(brother->color, brother->left->color);
RotateR(brother);
p->right = brother;
}//再经过一次情况二处理即可
/*左旋一次,直接删除,结束*/
else if ((brother->right == NULL || brother->right->color == black) && (
brother->left == NULL || brother->left->color == black)) {
//cout << "double NULL" << endl;
if (brother->color == black) {
brother->color = red;
cur = p;
}
if (!st.empty()) {
p = st.top();
st.pop();
}
}
}
}
else {
if (brother->color == red) { //兄弟节点是红的,由于红黑树平衡性要求,兄弟节点必有两个黑色子节点,而且父节点是黑色
p->color = red;
brother->color = black;
brother = brother->right; //为了可以经过情况四的处理
RotateR(p);
if (st.empty()) root = p;
else {
RBNode<K, E> *pp = st.top();
if (pp->left == orgp) pp->left = p;
else pp->right = p;
}
p = p->right;//新的双亲
}//再经过一次情况四的处理即可结束
else if (brother->color == black) {
//cout << "brother == black" << endl;
if (brother->left != NULL && brother->left->color == red) {
swap(brother->color, p->color);
brother->left->color = black;
RotateR(p);
if (st.empty()) root = p;
else {
RBNode<K, E> *pp = st.top();
if (pp->left == orgp) pp->left = p;
else pp->right = p;
}
break;
}
else if ((brother->left == NULL || brother->left->color == black) &&
(brother->right != NULL && brother->right->color == red)) {
swap(brother->color, brother->right->color);
RotateR(brother);
p->left = brother;
}//再经过一次情况二处理即可
/*左旋一次,直接删除,结束*/
else if ((brother->right == NULL || brother->right->color == black) && (
brother->left == NULL || brother->left->color == black)) {
//cout << "double NULL" << endl;
if (brother->color == black) {
brother->color = red;
cur = p;
}
if (!st.empty()) {
p = st.top();
st.pop();
}
}
}
}
}
if (cur == ppDel->left) ppDel->left = NULL;
else ppDel->right = NULL;
cur->color = black;
delete pDel;
return true;
}
}
void delete_tree(RBNode<K, E> *ptr) {
if (ptr != NULL) {
delete_tree(ptr->left);
delete_tree(ptr->right);
delete ptr;
}
}
void preOrder(RBNode<K, E> *ptr) {
if (ptr != NULL) {
cout << ptr->data << " color" << ptr->color << endl;
preOrder(ptr->left);
preOrder(ptr->right);
}
}
void inOrder(RBNode<K, E> *ptr) {
if (ptr != NULL) {
inOrder(ptr->left);
cout << ptr->data << " color" << ptr->color << endl;
inOrder(ptr->right);
}
}
void testRBTree(RBNode<K, E> *ptr, int &deep) {
if (ptr != NULL) {
if (ptr->color == black) {
++deep;
}
testRBTree(ptr->left, deep);
testRBTree(ptr->right, deep);
if (ptr->color == black) --deep;
}
else {
cout << deep << endl;
}
}
public:
RBTree(): root(NULL), _size(0) {}
~RBTree() {
delete_tree(root);
root = NULL;
}
size_t size() {
return _size;
}
E & Search(K k) {//这个Search实际上是为了Map写的,如果查不到,就插入该节点,这是STL map使用[]访问时的行为 !!
bool found = false;
E &result = Search(root, k, found);
if (found == false) {
Insert(E(), k);
return Search(root, k, found);
}
return result;
}
bool Contains(K k) {
bool found = false;
Search(root, k, found);
return found;
}
bool Insert(E d, K k) {
return Insert(root, d, k);
}
bool Remove(K k) {
return Remove(root, k);
}
void showInOrder() {
inOrder(root);
}
void showPreOrder(){
preOrder(root);
}
void testRB() {
int deep = 0;
testRBTree(root, deep);
}
};
附简易Map代码
#include <iostream>
#include "RBTree.h"
using namespace std;
template <class K, class E>
class Map {
RBTree<K, E> tree;
public:
Map() {}
size_t size() {
return tree.size();
}
bool empty() {
return tree.size() == 0;
}
E & operator[](K i) {
return tree.Search(i);
}
bool contains(K k) {
return tree.Contains(k);
}
};