Create SplayTree class, with all tests passed.

This commit is contained in:
Shine wOng
2019-06-13 21:18:23 +08:00
parent 5d16aa1ac5
commit 37bf0546b4
4 changed files with 320 additions and 2 deletions

View File

@@ -9,8 +9,6 @@
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);

213
thu_dsa/chp8/SplayTree.h Normal file
View File

@@ -0,0 +1,213 @@
#ifndef SPLAYTREE_H_
#define SPLAYTREE_H_
#include "../chp7/BST.h"
#define T entry<K, V>
template <typename K, typename V>
class SplayTree: public BST<K, V>{
protected:
BinNodePosi(T) splay(BinNodePosi(T) x);
BinNodePosi(T) zig(BinNodePosi(T) p); //right rotation
BinNodePosi(T) zag(BinNodePosi(T) p); //left rotation
BinNodePosi(T) zigzig(BinNodePosi(T) g);
BinNodePosi(T) zagzag(BinNodePosi(T) g);
public:
BinNodePosi(T)& search(K const &key);
BinNodePosi(T) insert(K const &key, V const &value);
bool remove(K const &key);
};
//implementations
//protected methods
template <typename K, typename V>
BinNodePosi(T) SplayTree<K, V>::splay(BinNodePosi(T) x){
BinNodePosi(T) p;
BinNodePosi(T) g;
BinNodePosi(T) hot;
while(x != __root){
p = x->parent, g = p->parent;
if (!g) {
hot = p->parent;
x = (x == p->leftChild ? zig(p) : zag(p));
x->parent = hot;
if (hot) (p == hot->leftChild)? hot->leftChild : hot->rightChild = x;
}
else {
if (p == g->leftChild) {
if (x == p->leftChild) { //zig-zig
hot = g->parent;
x = zigzig(g);
x->parent = hot;
if (hot) (g == hot->leftChild ? hot->leftChild : hot->rightChild) = x;
}
else { //zig-zag
hot = g->parent;
x = connect34(p, x, g, p->leftChild, x->leftChild, x->rightChild, g->rightChild);
x->parent = hot;
if (hot) g == hot->leftChild ? hot->leftChild : hot->rightChild = x;
}
}
else {
if (x == p->leftChild) { //zag-zig
hot = g->parent;
x = connect34(g, x, p, g->leftChild, x->leftChild, x->rightChild, p->rightChild);
x->parent = hot;
if (hot) g == hot->leftChild ? hot->leftChild : hot->rightChild = x;
}
else { //zag-zag
hot = g->parent;
x = zagzag(g);
x->parent = hot;
if (hot) g == hot->leftChild ? hot->leftChild : hot->rightChild = x;
}
}
}
if (!x->parent) __root = x;
}
return x;
}
template <typename K, typename V>
BinNodePosi(T) SplayTree<K, V>::zig(BinNodePosi(T) p){
BinNodePosi(T) x = p->leftChild;
p->leftChild = x->rightChild;
if (x->rightChild) x->rightChild->parent = p;
x->rightChild = p;
p->parent = x;
updateHeight(p);
updateHeight(x);
return x;
}
template <typename K, typename V>
BinNodePosi(T) SplayTree<K, V>::zag(BinNodePosi(T) p) {
BinNodePosi(T) x = p->rightChild;
p->rightChild = x->leftChild;
if (x->leftChild) x->leftChild->parent = p;
x->leftChild = p;
p->parent = x;
updateHeight(p);
updateHeight(x);
return x;
}
template <typename K, typename V>
BinNodePosi(T) SplayTree<K, V>::zigzig(BinNodePosi(T) g) {
BinNodePosi(T) p = g->leftChild;
BinNodePosi(T) x = p->leftChild;
p->leftChild = x->rightChild;
if (x->rightChild) x->rightChild->parent = p;
x->rightChild = p;
p->parent = x;
g->leftChild = p->rightChild;
if (p->rightChild) p->rightChild->parent = g;
p->rightChild = g;
g->parent = p;
updateHeight(g);
updateHeight(p);
updateHeight(x);
return x;
}
template <typename K, typename V>
BinNodePosi(T) SplayTree<K, V>::zagzag(BinNodePosi(T) g) {
BinNodePosi(T) p = g->rightChild;
BinNodePosi(T) x = p->rightChild;
p->rightChild = x->leftChild;
if (x->leftChild) x->leftChild->parent = p;
x->leftChild = p;
p->parent = x;
g->rightChild = p->leftChild;
if (p->leftChild) p->leftChild->parent = g;
p->leftChild = g;
g->parent = p;
updateHeight(g);
updateHeight(p);
updateHeight(x);
return x;
}
//public interfaces
template <typename K, typename V>
BinNodePosi(T)& SplayTree<K, V>::search(K const &key){
BinNodePosi(T) x = searchIn(__root, key, __hot = nullptr);
if (x) splay(x);
else if(__hot) splay(__hot);
return __root;
}
template <typename K, typename V>
BinNodePosi(T) SplayTree<K, V>::insert(K const &key, V const &value) {
BinNodePosi(T) x = search(key);
if (x && x->data.key == key) return x;
//else
__root = new BinNode<T>(entry<K, V>(key, value));
++__size;
if (!x) return __root;
if(key < x->data.key){
__root->leftChild = x->leftChild;
__root->rightChild = x;
x->leftChild = nullptr;
x->parent = __root;
}else{
__root->leftChild = x;
__root->rightChild = x->rightChild;
x->rightChild = nullptr;
x->parent = __root;
}
updateHeight(x);
updateHeight(__root);
return __root;
}
template <typename K, typename V>
bool SplayTree<K, V>::remove(K const &key){
BinNodePosi(T) x = search(key);
if (!x || x->data.key != key) return false;
//else
if(!__root->leftChild){
__root = __root->rightChild;
if(__root) __root->parent = nullptr;
search(key);
}
else if(!__root->rightChild){
__root = __root->leftChild;
__root->parent = nullptr;
search(key);
}
else {
__root = x->rightChild;
__root->parent = nullptr;
search(key); //move x's succ to root, and __root has no left child(for succ has the smallest key
__root->leftChild = x->leftChild;
x->leftChild->parent = __root;
updateHeight(__root);
}
--__size;
delete x;
return true;
}
#endif

18
thu_dsa/chp8/SplayTree.md Normal file
View File

@@ -0,0 +1,18 @@
伸展树知识总结
=============
> 相对于AVL树的比较。
AVL树更像是循规蹈矩如履薄冰。而伸展树则更加潇洒不顾小节。
> 局部性原理(locality)
类比于列表
> 逐层伸展策略与最坏情况
双层伸展策略
+ 描述
+ 效果
+ 时间复杂度
> 伸展树的实现
为了保证局部性,插入结点也需要插入到根节点。删除结点后,需要将被删除结点附近的结点移到根节点。这两个操作都可以通过伸展树的查找快速实现。

View File

@@ -0,0 +1,89 @@
#include "SplayTree.h"
#include <time.h>
#include <iostream>
#include <cassert>
using std::cout;
using std::endl;
void test_insert_and_search();
void test_remove();
int main(){
cout << "Running tests." << endl;
test_insert_and_search();
test_remove();
cout << "All tests passed." << endl;
system("pause");
return 0;
}
void test_insert_and_search(){
SplayTree<int, int> sTree;
//orderly insert
for (int ix = 0; ix != 32; ++ix)
sTree.insert(ix, ix);
assert(sTree.size() == 32);
assert(sTree.root()->data.key == 31);
assert(sTree.root()->height == 31);
//test search
assert(sTree.search(0)->data.key == 0);
assert(sTree.root()->data.key == 0);
assert(sTree.root()->height == 17);
assert(sTree.root()->rightChild->data.key = 31);
assert(sTree.root()->leftChild == nullptr);
assert(sTree.root()->rightChild->height == 16);
assert(sTree.search(1)->data.key == 1);
assert(sTree.root()->data.key == 1);
assert(sTree.root()->height == 10);
assert(sTree.root()->rightChild->data.key = 31);
assert(sTree.root()->leftChild->data.key == 0);
assert(sTree.root()->rightChild->height == 9);
assert(sTree.search(2)->data.key == 2);
assert(sTree.root()->data.key == 2);
assert(sTree.root()->height == 7);
assert(sTree.root()->rightChild->data.key = 27);
assert(sTree.root()->leftChild->data.key == 1);
assert(sTree.root()->rightChild->height == 6);
}
void test_remove(){
SplayTree<int, int> sTree;
//orderly insert
for (int ix = 0; ix != 32; ++ix)
sTree.insert(ix, ix);
assert(sTree.size() == 32);
assert(sTree.root()->data.key == 31);
assert(sTree.root()->height == 31);
assert(!sTree.remove(33));
assert(!sTree.remove(35));
assert(sTree.size() == 32);
assert(sTree.remove(31));
assert(sTree.size() == 31);
assert(sTree.root()->data.key == 30);
assert(sTree.root()->height == 30);
assert(sTree.remove(0));
assert(sTree.size() == 30);
assert(sTree.root()->data.key == 1);
assert(sTree.root()->height == 9);
assert(sTree.root()->rightChild->data.key == 27);
assert(sTree.root()->rightChild->height == 8);
assert(sTree.root()->leftChild == nullptr);
assert(sTree.remove(27));
assert(sTree.size() == 29);
assert(sTree.root()->data.key == 28);
assert(sTree.root()->leftChild->data.key == 1);
assert(sTree.root()->rightChild->data.key == 29);
assert(sTree.root()->height == 9);
assert(sTree.root()->leftChild->height == 8);
}