Complete red-black tree, with all tests passed.

This commit is contained in:
Shine wOng
2019-06-23 20:14:12 +08:00
parent cf6af38144
commit 4da20ee9c7
2 changed files with 278 additions and 10 deletions

View File

@@ -33,9 +33,6 @@ BinNodePosi(T) RedBlack<K, V>::zig(BinNodePosi(T) p){
x->rightChild = p;
p->parent = x;
updateHeight(p);
updateHeight(x);
return x;
}
@@ -47,9 +44,6 @@ BinNodePosi(T) RedBlack<K, V>::zag(BinNodePosi(T) p) {
x->leftChild = p;
p->parent = x;
updateHeight(p);
updateHeight(x);
return x;
}
@@ -80,6 +74,8 @@ void RedBlack<K, V>::solveDoubleRed(BinNodePosi(T) x){
BinNodePosi(T) newRoot = rotateAt(x);
if (gg)
(g == gg->leftChild ? gg->leftChild : gg->rightChild) = newRoot;
else __root = newRoot;
newRoot->color = BLACK;
newRoot->leftChild->color = RED;
newRoot->rightChild->color = RED;
@@ -101,6 +97,8 @@ void RedBlack<K, V>::solveDoubleRed(BinNodePosi(T) x){
template <typename K, typename V>
void RedBlack<K, V>::solveDoubleBlack(BinNodePosi(T) x){
if (x == __root) return; //recursion base
//else
BinNodePosi(T) p = (x ? x->parent : __hot);
BinNodePosi(T) s = (x == p->leftChild ? p->rightChild : p->leftChild);
@@ -109,8 +107,9 @@ void RedBlack<K, V>::solveDoubleBlack(BinNodePosi(T) x){
BinNodePosi(T) redChild = ISRED(s->leftChild) ? s->leftChild : s->rightChild;
BinNodePosi(T) g = p->parent;
BinNodePosi(T) newRoot = rotateAt(redChild);
if(g)
(p == g->leftChild? g->leftChild: g->rightChild) = newRoot:
if (g)
(p == g->leftChild ? g->leftChild : g->rightChild) = newRoot;
else __root = newRoot;
redChild->color = BLACK;
updateHeight(newRoot->leftChild);
updateHeight(newRoot->rightChild);
@@ -125,7 +124,7 @@ void RedBlack<K, V>::solveDoubleBlack(BinNodePosi(T) x){
return;
}
//case three: p is black
if(ISBLACK(p)){
if(ISBLACK(p) && ISBLACK(s)){
p->color = BLACK;
s->color = RED;
updateHeight(p);
@@ -139,7 +138,9 @@ void RedBlack<K, V>::solveDoubleBlack(BinNodePosi(T) x){
BinNodePosi(T) g = p->parent;
if(s == p->leftChild) zig(p);
else zag(p);
s->parent = g;
if (g) (p == g->leftChild ? g->leftChild : g->rightChild) = s;
else __root = s;
solveDoubleBlack(x);
}
@@ -166,7 +167,7 @@ bool RedBlack<K, V>::remove(K const &key){
BinNodePosi(T) succ = removeAt(x, __hot);
--__size;
if (ISRED(succ)) {
succ->color == BLACK;
succ->color = BLACK;
return true;
}
if (!BLACK_HEIGHT_CHANGED(__hot)) return true;

View File

@@ -0,0 +1,267 @@
#include "RedBlack.h"
#include <iostream>
#include <cassert>
using std::cout;
using std::endl;
void test_constructor();
void test_insert();
void test_remove();
int main(){
cout << "Running tests." << endl;
test_constructor();
test_insert();
test_remove();
cout << "All tests passed." << endl;
system("pause");
return 0;
}
void test_constructor(){
RedBlack<int, int> rbTree;
assert(rbTree.size() == 0);
auto root = rbTree.root();
assert(!root);
assert(ISBLACK(root));
assert(!ISRED(root));
assert(BLACK_HEIGHT(root) == 0);
assert(!BLACK_HEIGHT_CHANGED(root));
}
void test_insert(){
RedBlack<int, int> rbTree;
//insert one element
rbTree.insert(0, 0);
auto root = rbTree.root();
assert(rbTree.size() == 1);
assert(root->data.key == 0);
assert(BLACK_HEIGHT(root) == 1);
assert(ISBLACK(root));
assert(!ISRED(root));
assert(!root->leftChild && !root->rightChild);
//insert two
rbTree.insert(0, 0);
assert(rbTree.size() == 1);
assert(!root->leftChild && !root->rightChild);
rbTree.insert(1, 1);
assert(rbTree.size() == 2);
assert(root->data.key == 0);
assert(BLACK_HEIGHT(root) == 1);
assert(ISBLACK(root));
assert(!ISRED(root));
assert(!root->leftChild && root->rightChild);
auto right = root->rightChild;
assert(!ISBLACK(right));
assert(ISRED(right));
assert(BLACK_HEIGHT(right) == 1);
assert(!right->leftChild && !right->rightChild);
//double red: case one
rbTree.insert(2, 2);
root = rbTree.root();
auto left = root->leftChild;
right = root->rightChild;
assert(rbTree.size() == 3);
assert(root->data.key == 1);
assert(ISBLACK(root));
assert(BLACK_HEIGHT(root) == 1);
assert(left->data.key == 0);
assert(ISRED(left));
assert(BLACK_HEIGHT(left) == 1);
assert(!left->leftChild && !left->rightChild);
assert(right->data.key == 2);
assert(ISRED(right));
assert(BLACK_HEIGHT(right) == 1);
assert(!right->rightChild && !right->rightChild);
//double red: case two
rbTree.insert(3, 3);
assert(rbTree.size() == 4);
assert(root->data.key == 1);
assert(ISBLACK(root));
assert(BLACK_HEIGHT(root) == 2);
assert(left->data.key == 0);
assert(!ISRED(left));
assert(BLACK_HEIGHT(left) == 1);
assert(!left->leftChild && !left->rightChild);
assert(right->data.key == 2);
assert(!ISRED(right));
assert(BLACK_HEIGHT(right) == 1);
assert(right->rightChild && !right->leftChild);
assert(right->rightChild->data.key == 3);
assert(ISRED(right->rightChild));
//continue insertion
rbTree.insert(4, 4);
rbTree.insert(5, 5);
left = root->leftChild;
right = root->rightChild;
auto rightleft = right->leftChild;
auto rightright = right->rightChild;
assert(rbTree.size() == 6);
assert(ISBLACK(root));
assert(ISBLACK(left));
assert(ISRED(right));
assert(BLACK_HEIGHT(right) == 2);
assert(ISBLACK(rightleft) && ISBLACK(rightright));
assert(!rightright->leftChild && rightright->rightChild);
//continue
rbTree.insert(6, 6);
rbTree.insert(7, 7);
rbTree.insert(8, 8);
rbTree.insert(9, 9);
root = rbTree.root();
left = root->leftChild;
right = root->rightChild;
auto leftleft = left->leftChild;
auto leftright = left->rightChild;
rightleft = right->leftChild;
rightright = right->rightChild;
auto rightrightleft = rightright->leftChild;
auto rightrightright = rightright->rightChild;
assert(rbTree.size() == 10);
assert(root->data.key == 3);
assert(BLACK_HEIGHT(root) == 3);
assert(ISBLACK(root));
assert(left->data.key == 1);
assert(BLACK_HEIGHT(left) == 2);
assert(ISBLACK(left));
assert(left->parent == root);
assert(right->data.key == 5);
assert(ISBLACK(right));
assert(BLACK_HEIGHT(right) == 2);
assert(right->parent == root);
assert(leftleft->data.key == 0);
assert(ISBLACK(leftleft));
assert(BLACK_HEIGHT(leftleft) == 1);
assert(leftleft->parent == left);
assert(leftright->data.key == 2);
assert(ISBLACK(leftright));
assert(BLACK_HEIGHT(leftright) == 1);
assert(leftright->parent == left);
assert(rightleft->data.key == 4);
assert(ISBLACK(rightleft));
assert(BLACK_HEIGHT(rightleft) == 1);
assert(rightleft->parent == right);
assert(rightright->data.key == 7);
assert(!ISBLACK(rightright) && ISRED(rightright));
assert(BLACK_HEIGHT(rightright) == 2);
assert(rightright->parent == right);
assert(rightrightleft->data.key == 6);
assert(ISBLACK(rightrightleft));
assert(BLACK_HEIGHT(rightrightleft) == 1);
assert(rightrightleft->parent == rightright);
assert(rightrightright->data.key == 8);
assert(ISBLACK(rightrightright));
assert(BLACK_HEIGHT(rightrightright) == 1);
assert(rightrightright->parent == rightright);
}
void test_remove(){
RedBlack<int, int> rbTree;
for (int ix = 0; ix != 10; ++ix)
rbTree.insert(ix, ix);
//remove red leaf
assert(rbTree.remove(8));
assert(rbTree.size() == 9);
auto rightright = rbTree.root()->rightChild->rightChild;
auto rightrightleft = rightright->leftChild;
auto rightrightright = rightright->rightChild;
assert(ISRED(rightright));
assert(BLACK_HEIGHT(rightright) == 2);
assert(rightrightright->data.key == 9);
assert(ISBLACK(rightrightright));
assert(BLACK_HEIGHT(rightrightright));
assert(rightrightright->parent == rightright);
//double black: case two
assert(rbTree.remove(6));
assert(rbTree.size() == 8);
assert(ISBLACK(rightright));
assert(rightright->data.key == 7);
assert(BLACK_HEIGHT(rightright) == 1);
assert(!rightright->leftChild);
assert(rightrightright->data.key == 9);
assert(ISRED(rightrightright));
//double black: case three
assert(rbTree.remove(2));
assert(rbTree.size() == 7);
auto root = rbTree.root();
auto left = root->leftChild;
auto right = root->rightChild;
auto leftleft = left->leftChild;
auto rightleft = right->leftChild;
rightright = right->rightChild;
assert(root->data.key == 3);
assert(BLACK_HEIGHT(root) == 2);
assert(left->data.key == 1);
assert(ISBLACK(left));
assert(BLACK_HEIGHT(left) == 1);
assert(left->parent == root);
assert(!left->rightChild);
assert(leftleft->data.key == 0);
assert(ISRED(leftleft));
assert(leftleft->parent == left);
assert(BLACK_HEIGHT(leftleft) == 1);
assert(right->data.key == 5);
assert(ISRED(right));
assert(BLACK_HEIGHT(right) == 2);
assert(right->parent == root);
assert(rightleft->data.key == 4);
assert(rightright->data.key == 7);
assert(rightleft->parent == right && rightleft->parent == right);
assert(ISBLACK(rightleft) && ISBLACK(rightright));
assert(rightright->rightChild->data.key == 9 && ISRED(rightright->rightChild));
//double black: case four
assert(rbTree.remove(1));
assert(rbTree.remove(0));
assert(rbTree.size() == 5);
root = rbTree.root();
left = root->leftChild;
auto leftright = left->rightChild;
right = root->rightChild;
rightright = right->rightChild;
assert(root->data.key == 5);
assert(ISBLACK(root));
assert(BLACK_HEIGHT(root) == 2);
assert(left->data.key == 3);
assert(ISBLACK(left));
assert(BLACK_HEIGHT(left));
assert(left->parent == root && !left->leftChild);
assert(leftright->data.key == 4);
assert(ISRED(leftright));
assert(leftright->parent == left);
assert(right->data.key == 7);
assert(ISBLACK(right));
assert(right->parent == root);
assert(rightright->data.key == 9);
assert(ISRED(rightright));
assert(rightright->parent == right);
//double black: case one
assert(rbTree.remove(3));
assert(rbTree.remove(4));
assert(rbTree.size() == 3);
root = rbTree.root();
right = root->rightChild;
left = root->leftChild;
assert(root->data.key == 7);
assert(ISBLACK(root));
assert(BLACK_HEIGHT(root) == 2);
assert(left->data.key == 5);
assert(!ISRED(left));
assert(left->parent == root);
assert(!left->leftChild && !left->rightChild);
assert(right->data.key == 9);
assert(!ISRED(right));
assert(right->parent == root);
assert(!right->leftChild && !right->rightChild);
}