From 4da20ee9c792ae9d7794f9b76fb5db5aa43865f9 Mon Sep 17 00:00:00 2001 From: Shine wOng <1551885@tongji.edu.cn> Date: Sun, 23 Jun 2019 20:14:12 +0800 Subject: [PATCH] Complete red-black tree, with all tests passed. --- thu_dsa/chp8/RedBlack.h | 21 +-- thu_dsa/chp8/test_RedBlack.cpp | 267 +++++++++++++++++++++++++++++++++ 2 files changed, 278 insertions(+), 10 deletions(-) diff --git a/thu_dsa/chp8/RedBlack.h b/thu_dsa/chp8/RedBlack.h index 3aa0397..a5e0035 100644 --- a/thu_dsa/chp8/RedBlack.h +++ b/thu_dsa/chp8/RedBlack.h @@ -33,9 +33,6 @@ BinNodePosi(T) RedBlack::zig(BinNodePosi(T) p){ x->rightChild = p; p->parent = x; - - updateHeight(p); - updateHeight(x); return x; } @@ -47,9 +44,6 @@ BinNodePosi(T) RedBlack::zag(BinNodePosi(T) p) { x->leftChild = p; p->parent = x; - - updateHeight(p); - updateHeight(x); return x; } @@ -80,6 +74,8 @@ void RedBlack::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::solveDoubleRed(BinNodePosi(T) x){ template void RedBlack::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::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::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::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::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; diff --git a/thu_dsa/chp8/test_RedBlack.cpp b/thu_dsa/chp8/test_RedBlack.cpp index e69de29..b2a9356 100644 --- a/thu_dsa/chp8/test_RedBlack.cpp +++ b/thu_dsa/chp8/test_RedBlack.cpp @@ -0,0 +1,267 @@ +#include "RedBlack.h" +#include +#include +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 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 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 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); +}