Correct some bugs in BST::removaAt(). Finish AVL class, with all tests passed.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
65
thu_dsa/chp7/AVL.h
Normal 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
|
||||
@@ -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
75
thu_dsa/chp7/test_AVL.cpp
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user