create BST class, all tests passed.

This commit is contained in:
Shine wOng
2019-06-09 15:24:07 +08:00
parent 78b3dda901
commit 85f3ffeac6
3 changed files with 222 additions and 0 deletions

102
thu_dsa/chp7/BST.h Normal file
View File

@@ -0,0 +1,102 @@
#ifndef BST_H_
#define BST_H_
#include "../chp5/binTree.h"
#include <stdexcept>
using std::runtime_error;
template <typename K, typename V>
class entry {
public:
K key;
V value;
//constructor
entry(K k, V v) : key(k), value(v) {}
//overload operator
bool operator==(entry<K, V> const e) { return key == e.key; }
bool operator!=(entry<K, V> const e) { return key != e.key; }
bool operator>(entry<K, V> const e) { return key > e.key; }
bool operator<(entry<K, V> const e) { return key < e.key; }
};
#define T entry<K, V>
template <typename K, typename V>
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);
public:
//call by key, always assume that key exists, read-only
V operator[](K const &key);
virtual BinNodePosi(T)& search(K const &key);
virtual BinNodePosi(T) insert(K const &key, V const &value);
virtual BinNodePosi(T) remove(K const &key);
};
//protected methods
template <typename K, typename V>
BinNodePosi(T)& BST<K, V>::searchIn(BinNodePosi(T)& x, K const &key, BinNodePosi(T) &hot){
if (!x || x->data.key == key) return x;
hot = x;
return key < x->data.key ? searchIn(x->leftChild, key, hot) : searchIn(x->rightChild, key, hot);
}
//public interfaces
template <typename K, typename V>
V BST<K, V>::operator[](K const &key){
BinNodePosi(T) x = search(key);
if (!x) throw runtime_error("Fatal Error: key doesn't exist.");
return x->data.value;
}
template <typename K, typename V>
BinNodePosi(T)& BST<K, V>::search(K const &key){
return searchIn(__root, key, __hot = nullptr);
}
template <typename K, typename V>
BinNodePosi(T) BST<K, V>::insert(K const &key, V const &value){
BinNodePosi(T) &x = search(key);
if (x) return x;
x = new BinNode<T>(entry<K, V>(key, value), __hot);
++__size;
updateHeightAbove(__hot);
return x;
}
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;
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;
--__size;
updateHeightAbove(__hot);
return succ;
}
#undef T
#endif

23
thu_dsa/chp7/chp7.md Normal file
View File

@@ -0,0 +1,23 @@
为什么会这样
===========
## AVL
> 为什么AVL树是平衡树
### AVL 插入
+ 插入至多会导致$O(logn)$个结点失衡,全是当前结点的祖先。第一个失衡的结点,至少是新插入结点的祖父结点
+ 经过一次旋转调整后,可以使第一个失衡的结点恢复平衡,同时它的祖先也全部恢复平衡,全树重新平衡
+ 插入后有可能平衡性不变,但是高度发生改变
### AVL 删除
+ 删除至多只会导致一个结点失衡。这个结点可以是被删除结点的父结点
+ 经过一次旋转调整后,当前局部会重新恢复平衡,但是其高度可能发生变化,也可能不变
+ 因此之后的祖先结点也可能接着发生失衡。并且这种失衡至多会发生$O(logn)$次。因此至多需要$O(logn)$次调整
+ 删除后有可能某一子树平衡性不变,但是高度降低
+ 必须完全遍历至根节点,没有中途退出循环的途径。因为无法确定上层祖先是否会失衡。
## 3+4重构
+ 可以证明经过3+4重构后得到的子树仍然是满足AVL平衡条件
+ 对应了之前的单旋转和双旋转所有的情况

97
thu_dsa/chp7/test_BST.cpp Normal file
View File

@@ -0,0 +1,97 @@
#include "BST.h"
#include <iostream>
#include <cassert>
#include <string>
using std::cout;
using std::endl;
using std::string;
void test_insert_and_search();
void test_remove();
void test_index();
int main(){
cout << "Running test." << endl;
test_insert_and_search();
test_remove();
test_index();
cout << "All tests passed." << endl;
system("pause");
return 0;
}
void test_insert_and_search(){
BST<int, string> bstTree;
int keys[] = { 5, 8, 2, 7, 6, 4, 9, 1, 3 };
string values[] = { "five", "eight", "two", "seven", "six", "four", "nine", "one", "three" };
for (int ix = 0; ix != 9; ++ix)
bstTree.insert(keys[ix], values[ix]);
assert(bstTree.size() == 9);
//test duplicates
for (int ix = 0; ix != 9; ++ix)
bstTree.insert(keys[ix], values[8 - ix]);
assert(bstTree.size() == 9);
//test search
for(int ix = 0; ix != 9; ++ix)
assert(bstTree.search(keys[ix])->data.value == values[ix]);
//test BST characteristics
#define T entry<int, string>
BinNodePosi(T) x = bstTree.search(1);
for (int ix = 1; x; ++ix, x = x->succ())
assert(x->data.key == ix);
#undef T
}
void test_remove(){
BST<int, string> bstTree;
int keys[] = { 5, 8, 2, 7, 6, 4, 9, 1, 3 };
string values[] = { "five", "eight", "two", "seven", "six", "four", "nine", "one", "three" };
for (int ix = 0; ix != 9; ++ix)
bstTree.insert(keys[ix], values[ix]);
assert(bstTree.root()->data.key == 5);
//remove leaf
assert(bstTree.remove(6) == nullptr);//no succ
assert(bstTree.size() == 8);
assert(bstTree.search(6) == nullptr);
//remove intermediate node
assert(bstTree.remove(4)->data.value == "three");
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.size() == 6);
assert(bstTree.root()->data.key == 7);
assert(bstTree.root()->leftChild->data.key == 2 && bstTree.root()->rightChild->data.key == 8);
//test BST topology
#define T entry<int, string>
BinNodePosi(T) x = bstTree.search(1);
int remainedKeys[] = { 1, 2, 3, 7, 8, 9 };
for (int ix = 0; x; ++ix, x = x->succ()) {
assert(x->data.key == remainedKeys[ix]);
}
#undef T
}
void test_index(){
BST<int, string> bstTree;
int keys[] = { 5, 8, 2, 7, 6, 4, 9, 1, 3 };
string values[] = { "five", "eight", "two", "seven", "six", "four", "nine", "one", "three" };
for (int ix = 0; ix != 9; ++ix)
bstTree.insert(keys[ix], values[ix]);
for (int ix = 0; ix != 9; ++ix)
assert(bstTree[keys[ix]] == values[ix]);
}