Correct some bugs in BST::removaAt(). Finish AVL class, with all tests passed.

This commit is contained in:
Shine wOng
2019-06-11 16:10:26 +08:00
parent a7a28990ce
commit ec0f418101
6 changed files with 230 additions and 25 deletions

View File

@@ -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 <typename VST> void preOrder_Re(VST &visit);

View File

@@ -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 <typename T>
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<T>::updateHeightAbove(BinNodePosi(T) x){
for (; x && updateHeight(x); x = x->parent);
}
template <typename T>
BinNodePosi(T) BinTree<T>::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 <typename T>

65
thu_dsa/chp7/AVL.h Normal file
View File

@@ -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<K, V>
template <typename K, typename V>
class AVL: public BST<K, V>{
protected:
public:
BinNodePosi(T) insert(K const &key, V const &value);
bool remove(K const &key);
};
//public interfaces
template <typename K, typename V>
BinNodePosi(T) AVL<K, V>::insert(K const &key, V const &value){
BinNodePosi(T) &pos = search(key);
if (pos) return pos;
//else
pos = new BinNode<T>(entry<K, V>(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 <typename K, typename V>
bool AVL<K, V>::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

View File

@@ -28,9 +28,10 @@ class BST: public BinTree<T>{
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<K, V>::searchIn(BinNodePosi(T)& x, K const &key, BinNodePosi
return key < x->data.key ? searchIn(x->leftChild, key, hot) : searchIn(x->rightChild, key, hot);
}
template <typename K, typename V>
BinNodePosi(T) BST<K, V>::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 <typename K, typename V>
BinNodePosi(T) BST<K, V>::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 <typename K, typename V>
BinNodePosi(T) BST<K, V>::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 <typename K, typename V>
@@ -76,25 +142,14 @@ BinNodePosi(T) BST<K, V>::insert(K const &key, V const &value){
}
template <typename K, typename V>
BinNodePosi(T) BST<K, V>::remove(K const &key){
BinNodePosi(T)& x = search(key);
BinNodePosi(T) succ;
if (!x) return nullptr;
bool BST<K, V>::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

75
thu_dsa/chp7/test_AVL.cpp Normal file
View File

@@ -0,0 +1,75 @@
#include "AVL.h"
#include <iostream>
#include <cassert>
#include <string>
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<int, string> 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<int, string> 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);
}

View File

@@ -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);