diff --git a/thu_dsa/chp7/AVL.h b/thu_dsa/chp7/AVL.h index 169e04e..06bb6d3 100644 --- a/thu_dsa/chp7/AVL.h +++ b/thu_dsa/chp7/AVL.h @@ -9,8 +9,6 @@ template class AVL: public BST{ -protected: - public: BinNodePosi(T) insert(K const &key, V const &value); bool remove(K const &key); diff --git a/thu_dsa/chp8/SplayTree.h b/thu_dsa/chp8/SplayTree.h new file mode 100644 index 0000000..8a8795b --- /dev/null +++ b/thu_dsa/chp8/SplayTree.h @@ -0,0 +1,213 @@ +#ifndef SPLAYTREE_H_ +#define SPLAYTREE_H_ + +#include "../chp7/BST.h" + +#define T entry +template +class SplayTree: public BST{ +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 +BinNodePosi(T) SplayTree::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 +BinNodePosi(T) SplayTree::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 +BinNodePosi(T) SplayTree::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 +BinNodePosi(T) SplayTree::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 +BinNodePosi(T) SplayTree::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 +BinNodePosi(T)& SplayTree::search(K const &key){ + BinNodePosi(T) x = searchIn(__root, key, __hot = nullptr); + if (x) splay(x); + else if(__hot) splay(__hot); + return __root; +} + +template +BinNodePosi(T) SplayTree::insert(K const &key, V const &value) { + BinNodePosi(T) x = search(key); + if (x && x->data.key == key) return x; + //else + __root = new BinNode(entry(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 +bool SplayTree::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 diff --git a/thu_dsa/chp8/SplayTree.md b/thu_dsa/chp8/SplayTree.md new file mode 100644 index 0000000..b4ff6d8 --- /dev/null +++ b/thu_dsa/chp8/SplayTree.md @@ -0,0 +1,18 @@ +伸展树知识总结 +============= + +> 相对于AVL树的比较。 +AVL树更像是循规蹈矩,如履薄冰。而伸展树则更加潇洒,不顾小节。 + +> 局部性原理(locality) +类比于列表 + +> 逐层伸展策略与最坏情况 + +双层伸展策略 ++ 描述 ++ 效果 ++ 时间复杂度 + +> 伸展树的实现 +为了保证局部性,插入结点也需要插入到根节点。删除结点后,需要将被删除结点附近的结点移到根节点。这两个操作都可以通过伸展树的查找快速实现。 diff --git a/thu_dsa/chp8/test_SplayTree.cpp b/thu_dsa/chp8/test_SplayTree.cpp new file mode 100644 index 0000000..af9e66e --- /dev/null +++ b/thu_dsa/chp8/test_SplayTree.cpp @@ -0,0 +1,89 @@ +#include "SplayTree.h" +#include +#include +#include + +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 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 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); +}