diff --git a/thu_dsa/chp5/binNode.h b/thu_dsa/chp5/binNode.h index 002f7a9..0de3743 100644 --- a/thu_dsa/chp5/binNode.h +++ b/thu_dsa/chp5/binNode.h @@ -31,7 +31,7 @@ public: int size() const; //compute the size of the tree rooted at current node BinNodePosi(T) insertAsLC(T const &val); //always assume that this.leftChild == nullptr BinNodePosi(T) insertAsRC(T const &val); //always assume that this.rightChild == nullptr - BinNodePosi(T) succ(); //return the direct successor of current node + BinNodePosi(T) succ(); //return the direct successor of current node //tree traversal template void preOrder_Re(VST &visit); diff --git a/thu_dsa/chp5/binTree.h b/thu_dsa/chp5/binTree.h index 7665390..d6ea020 100644 --- a/thu_dsa/chp5/binTree.h +++ b/thu_dsa/chp5/binTree.h @@ -3,7 +3,9 @@ #include "binNode.h" -#define MAX(X, Y) ((X)>(Y)?(X):(Y)) +#define FROMPARENTTO(X) (X->parent?__root: X==X->parent->leftChild? X->parent->leftChild: X->parent->rightChild) +#define STATURE(X) ((X)?(X)->height: -1) +#define MAX(X, Y) ((X)>(Y)?(X):(Y)) template class BinTree{ @@ -12,6 +14,7 @@ protected: int __size; bool updateHeight(BinNodePosi(T) x); void updateHeightAbove(BinNodePosi(T) x); + BinNodePosi(T) higherChild(BinNodePosi(T) x); public: //constructor @@ -46,6 +49,13 @@ void BinTree::updateHeightAbove(BinNodePosi(T) x){ for (; x && updateHeight(x); x = x->parent); } +template +BinNodePosi(T) BinTree::higherChild(BinNodePosi(T) x){ + if (!x->leftChild) return x->rightChild; + if (!x->rightChild) return x->leftChild; + return x->leftChild->height < x->rightChild->height ? x->rightChild : x->leftChild; +} + //public interfaces template diff --git a/thu_dsa/chp7/AVL.h b/thu_dsa/chp7/AVL.h new file mode 100644 index 0000000..169e04e --- /dev/null +++ b/thu_dsa/chp7/AVL.h @@ -0,0 +1,65 @@ +#ifndef AVL_H_ +#define AVL_H_ + +#include "BST.h" + +#define BALANCE_FACTOR(X) (STATURE(X->leftChild) - STATURE(X->rightChild)) +#define AVLBALANCED(X) ((-2 < BALANCE_FACTOR(X)) && (BALANCE_FACTOR(X) < 2)) +#define T entry + +template +class AVL: public BST{ +protected: + +public: + BinNodePosi(T) insert(K const &key, V const &value); + bool remove(K const &key); +}; + +//public interfaces + +template +BinNodePosi(T) AVL::insert(K const &key, V const &value){ + BinNodePosi(T) &pos = search(key); + if (pos) return pos; + //else + pos = new BinNode(entry(key, value), __hot); + for(BinNodePosi(T) x = __hot; x; x = x->parent){ + if (AVLBALANCED(x)) updateHeight(x); + else{ + BinNodePosi(T) parent = x->parent; + BinNodePosi(T) newRoot = rotateAt(higherChild(higherChild(x))); + if (parent) + x == parent->leftChild ? parent->leftChild : parent->rightChild = newRoot; + else __root = newRoot; + break; + } + } + ++__size; + return pos; +} + +template +bool AVL::remove(K const &key) { + BinNodePosi(T) &pos = search(key); + if (!pos) return false; + //else + removeAt(pos, __hot); + for(BinNodePosi(T) x = __hot; x; x = x->parent){ + if (!AVLBALANCED(x)){ + BinNodePosi(T) parent = x->parent; + BinNodePosi(T) newRoot = rotateAt(higherChild(higherChild(x))); + if (parent) + x == parent->leftChild ? parent->leftChild : parent->rightChild = newRoot; + else __root = newRoot; + x = newRoot; + } + updateHeight(x); + } + --__size; + return true; +} + +#undef T + +#endif diff --git a/thu_dsa/chp7/BST.h b/thu_dsa/chp7/BST.h index 1770571..95d740f 100644 --- a/thu_dsa/chp7/BST.h +++ b/thu_dsa/chp7/BST.h @@ -28,9 +28,10 @@ class BST: public BinTree{ protected: BinNodePosi(T) __hot; BinNodePosi(T)& searchIn(BinNodePosi(T)& x, K const &key, BinNodePosi(T) &hot); - BinNodePosi(T) connect34(BinNodePosi(T), BinNodePosi(T), BinNodePosi(T), - BinNodePosi(T), BinNodePosi(T), BinNodePosi(T), BinNodePosi(T)); - BinNodePosi(T) rotateAt(BinNodePosi(T) x); + BinNodePosi(T) connect34(BinNodePosi(T) x, BinNodePosi(T) y, BinNodePosi(T) z, + BinNodePosi(T) T0, BinNodePosi(T) T1, BinNodePosi(T) T2, BinNodePosi(T) T3); //return new root + BinNodePosi(T) rotateAt(BinNodePosi(T) x); //return new root + BinNodePosi(T) removeAt(BinNodePosi(T) &x, BinNodePosi(T) &hot); public: @@ -39,7 +40,7 @@ public: virtual BinNodePosi(T)& search(K const &key); virtual BinNodePosi(T) insert(K const &key, V const &value); - virtual BinNodePosi(T) remove(K const &key); + virtual bool remove(K const &key); }; //protected methods @@ -50,6 +51,71 @@ BinNodePosi(T)& BST::searchIn(BinNodePosi(T)& x, K const &key, BinNodePosi return key < x->data.key ? searchIn(x->leftChild, key, hot) : searchIn(x->rightChild, key, hot); } +template +BinNodePosi(T) BST::connect34(BinNodePosi(T) x, BinNodePosi(T) y, BinNodePosi(T) z, + BinNodePosi(T) T0, BinNodePosi(T) T1, BinNodePosi(T) T2, BinNodePosi(T) T3){ + x->leftChild = T0; + x->rightChild = T1; + if (T0) T0->parent = x; + if (T1) T1->parent = x; + updateHeight(x); + + z->leftChild = T2; + z->rightChild = T3; + if (T2) T2->parent = z; + if (T3) T3->parent = z; + updateHeight(z); + + x->parent = y; + z->parent = y; + y->leftChild = x; + y->rightChild = z; + updateHeight(y); + return y; +} + +template +BinNodePosi(T) BST::rotateAt(BinNodePosi(T) x){ + BinNodePosi(T) p = x->parent; + BinNodePosi(T) g = p->parent; + if(p == g->leftChild){ + if (x == p->leftChild) { + p->parent = g->parent; + return connect34(x, p, g, x->leftChild, x->rightChild, p->rightChild, g->rightChild); + } + else { + x->parent = g->parent; + return connect34(p, x, g, p->leftChild, x->leftChild, x->rightChild, g->rightChild); + } + }else{ + if (x == p->leftChild) { + x->parent = g->parent; + return connect34(g, x, p, g->leftChild, x->leftChild, x->rightChild, p->rightChild); + } + else { + p->parent = g->parent; + return connect34(g, p, x, g->leftChild, p->leftChild, x->leftChild, x->rightChild); + } + } +} + +template +BinNodePosi(T) BST::removeAt(BinNodePosi(T) &x, BinNodePosi(T) &hot){ + BinNodePosi(T) succ; + if (!x->leftChild) succ = x = x->rightChild; + else if (!x->rightChild) succ = x = x->leftChild; + else{ + succ = x->succ(); + x->data = succ->data; + if (succ->parent == x) succ->parent->rightChild = succ->rightChild; + else succ->parent->leftChild = succ->rightChild; + hot = succ->parent; + succ = succ->rightChild; + } + if(succ) succ->parent = hot; + return succ; +} + //public interfaces template @@ -76,25 +142,14 @@ BinNodePosi(T) BST::insert(K const &key, V const &value){ } template -BinNodePosi(T) BST::remove(K const &key){ - BinNodePosi(T)& x = search(key); - BinNodePosi(T) succ; - if (!x) return nullptr; +bool BST::remove(K const &key){ + BinNodePosi(T) &x = search(key); + if (!x) return false; - if (!x->leftChild) succ = x = x->rightChild; - else if (!x->rightChild) succ = x = x->leftChild; - else{ - succ = x->succ(); - x->data = succ->data; - - succ->parent == x ? succ->parent->rightChild : succ->parent->leftChild = succ->rightChild; - __hot = succ; - succ = __hot->rightChild; - } - if (succ) succ->parent = __hot; + removeAt(x, __hot); --__size; updateHeightAbove(__hot); - return succ; + return true; } #undef T diff --git a/thu_dsa/chp7/test_AVL.cpp b/thu_dsa/chp7/test_AVL.cpp new file mode 100644 index 0000000..e81de35 --- /dev/null +++ b/thu_dsa/chp7/test_AVL.cpp @@ -0,0 +1,75 @@ +#include "AVL.h" +#include +#include +#include + +using std::cout; +using std::endl; +using std::string; + +void test_insert(); +void test_remove(); + +int main(){ + cout << "Running tests." << endl; + + test_insert(); + test_remove(); + + cout << "All tests passed." << endl; + system("pause"); + return 0; +} + +void test_insert(){ + AVL avlTree; + string values[] = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; + for (int ix = 0; ix != 10; ++ix) + avlTree.insert(ix, values[ix]); + auto root = avlTree.root(); + assert(avlTree.size() == 10); + assert(root->data.key == 3); + assert(root->height == 3); + assert(root->leftChild->data.key == 1); + assert(root->rightChild->data.key == 7); + + //test BST characteristics + auto x = avlTree.search(0); + for (int ix = 0; ix != 10; ++ix, x = x->succ()) + assert(x->data.key == ix); + assert(x == nullptr); + +} + +void test_remove(){ + AVL avlTree; + string values[] = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; + for (int ix = 0; ix != 10; ++ix) + avlTree.insert(ix, values[ix]); + + assert(avlTree.root()->height == 3); + + avlTree.remove(1); + assert(avlTree.size() == 9); + assert(avlTree.root()->height == 3); + assert(avlTree.root()->data.key == 3); + assert(avlTree.root()->leftChild->data.key == 2); + assert(avlTree.root()->rightChild->data.key == 7); + avlTree.remove(0); + assert(avlTree.size() == 8); + assert(avlTree.root()->height == 3); + assert(avlTree.root()->data.key == 5); + assert(avlTree.root()->leftChild->data.key == 3); + assert(avlTree.root()->leftChild->height == 1); + assert(avlTree.root()->rightChild->data.key == 7); + assert(avlTree.root()->rightChild->height == 2); + + avlTree.remove(5); + assert(avlTree.size() == 7); + assert(avlTree.root()->data.key == 6); + assert(avlTree.root()->height == 2); + assert(avlTree.root()->leftChild->data.key == 3); + assert(avlTree.root()->leftChild->height == 1); + assert(avlTree.root()->rightChild->data.key == 8); + assert(avlTree.root()->rightChild->height == 1); +} diff --git a/thu_dsa/chp7/test_BST.cpp b/thu_dsa/chp7/test_BST.cpp index 1002105..21a6fee 100644 --- a/thu_dsa/chp7/test_BST.cpp +++ b/thu_dsa/chp7/test_BST.cpp @@ -58,19 +58,19 @@ void test_remove(){ assert(bstTree.root()->data.key == 5); //remove leaf - assert(bstTree.remove(6) == nullptr);//no succ + assert(bstTree.remove(6));//no succ assert(bstTree.size() == 8); assert(bstTree.search(6) == nullptr); //remove intermediate node - assert(bstTree.remove(4)->data.value == "three"); + assert(bstTree.remove(4)); assert(bstTree.size() == 7); assert(bstTree.search(4) == nullptr); assert(bstTree.search(3)->parent->data.key == 2); assert(bstTree.search(2)->rightChild->data.key == 3); //remove root node - assert(bstTree.remove(5) == nullptr); + assert(bstTree.remove(5)); assert(bstTree.size() == 6); assert(bstTree.root()->data.key == 7); assert(bstTree.root()->leftChild->data.key == 2 && bstTree.root()->rightChild->data.key == 8);