Complete red-black tree, with all tests passed.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user