目录
1. 头文件
需要引入C++ 数据结构学习 ---- 二叉搜索树_孤城寻欢的博客-CSDN博客的二叉搜索树文件
#include"BST.h"
template <typename T> class Splay : public BST<T> { //由BST派生的Splay树模板类
protected:
BinNodePosi(T) splay(BinNodePosi(T) v); //将节点v伸展至根
public:
BinNodePosi(T)& search(const T& e); //查找(重写)
BinNodePosi(T) insert(const T& e); //插入(重写)
bool remove(const T& e); //删除(重写)
};
//在节点*p与*lc(可能为空)之间建立父(左)子关系
template <typename NodePosi> inline void attachAsLC(NodePosi lc, NodePosi p) { p->lc = lc; if (lc) lc->parent = p; }
//在节点*p与*rc(可能为空)之间建立父(右)子关系
template <typename NodePosi> inline void attachAsRC(NodePosi p, NodePosi rc) { p->rc = rc; if (rc) rc->parent = p; }
2. 相关函数
2.1 插入函数
//将关键码e插入伸展树中
template <typename T> BinNodePosi(T) Splay<T>::insert(const T& e) {
if (BST<T>::_root==NULL) { this->_size = 1; return this->_root = new BinNode<T>(e); } //原树为空
BinNodePosi(T) t = search(e); if (e == t->data) return t; //目标节点t若存在,伸展至根
if (t->data < e) { //在右侧嫁接
t->parent = this->_root = new BinNode<T>(e, NULL, t, t->rc); //lc == t必非空
if (t->rc) { t->rc->parent = this->_root; t->rc = NULL; } //rc或为空
}
else { //在左侧嫁接
t->parent = this->_root = new BinNode<T>(e, NULL, t->lc, t); //rc == t必非空
if (t->lc) { t->lc->parent = this->_root; t->lc = NULL; } //lc或为空
}
this->_size++; this->updateHeightAbove(t); return this->_root; //更新规模及高度,报告插入成功
} //无论e是否存在于原树中,返回时总有_root->data == e
2.2 删除函数
//从伸展树中删除关键码e
template <typename T> bool Splay<T>::remove(const T& e) {
if (!BST<T>::_root || (e != search(e)->data)) return false; //若目标存在,则伸展至根
BinNodePosi(T) L = BST<T>::_root->lc;
BinNodePosi(T) R = BST<T>::_root->rc;
release(BST<T>::_root);//记下左、右子树L、R后,释放之
if ( !R ) { //若R空,则
if ( L ) L->parent = NULL; BST<T>::_root = L; //L即是余树
} else { //否则
BST<T>::_root = R; R->parent = NULL; search( e ); //在R中再次查找e:注定失败,但其中的最小节点必
if (L) L->parent = BST<T>::_root; BST<T>::_root->lc = L; //伸展至根(且无左孩子),故可令其以L作为左子树
}
if ( --BST<T>::_size ) this->updateHeight (BST<T>::_root ); return true; //更新规模及树高,报告删除成功
}
2.3 搜索函数
//在伸展树中查找e
template <typename T> BinNodePosi(T)& Splay<T>::search(const T& e) {
BinNodePosi(T) p = BST<T>::search(e);
BST<T>::_root = splay(p ? p : BST<T>::_hot); //将最后一个被访问的节点伸展至根
return BST<T>::_root;
} //与其它BST不同,无论查找成功与否,_root都指向最后被访问的节点
2.4 伸展函数
//Splay树伸展算法:从节点v出发逐层伸展
template <typename T> BinNodePosi(T) Splay<T>::splay(BinNodePosi(T) v) { //v为因最近访问而需伸展的节点位置
if (!v) return NULL; BinNodePosi(T) p; BinNodePosi(T) g; //*v的父亲与祖父
while ((p = v->parent) && (g = p->parent)) { //自下而上,反复对*v做双层伸展
BinNodePosi(T) gg = g->parent; //每轮之后*v都以原曾祖父(great-grand parent)为父
if (IsLChild(*v))
if (IsLChild(*p)) { //zig-zig
std::cout << "zIg-zIg :"<<"g:"<<g->data<<" p:" << p->data<<" v:" << v->data << std::endl;
// printf("\tzIg-zIg :"); print(g); print(p); print(v); printf("\n");
attachAsLC(p->rc, g); attachAsLC(v->rc, p);
attachAsRC(p, g); attachAsRC(v, p);
}
else { //zig-zag
std::cout << "zIg-zAg :" << "g:" << g->data << " p:" << p->data << " v:" << v->data << std::endl;
//printf("\tzIg-zAg :"); print(g); print(p); print(v); printf("\n");
attachAsLC(v->rc, p); attachAsRC(g, v->lc);
attachAsLC(g, v); attachAsRC(v, p);
}
else if (IsRChild(*p)) { //zag-zag
std::cout << "zAg-zAg :" << "g:" << g->data << " p:" << p->data << " v:" << v->data << std::endl;
//printf("\tzAg-zAg :"); print(g); print(p); print(v); printf("\n");
attachAsRC(g, p->lc); attachAsRC(p, v->lc);
attachAsLC(g, p); attachAsLC(p, v);
}
else { //zag-zig
std::cout << "zAg-zIg :" << "g:" << g->data << " p:" << p->data << " v:" << v->data << std::endl;
//printf("\tzAg-zIg :"); print(g); print(p); print(v); printf("\n");
attachAsRC(p, v->lc); attachAsLC(v->rc, g);
attachAsRC(v, g); attachAsLC(p, v);
}
if (!gg) v->parent = NULL; //若*v原先的曾祖父*gg不存在,则*v现在应为树根
else //否则,*gg此后应该以*v作为左或右孩子
(g == gg->lc) ? attachAsLC(v, gg) : attachAsRC(gg, v);
this->updateHeight(g); this->updateHeight(p); this->updateHeight(v);
} //双层伸展结束时,必有g == NULL,但p可能非空
if (p = v->parent) { //若p果真非空,则额外再做一次单旋
if (IsLChild(*v)) {
std::cout << "zIg :" << "p:" << p->data <<" v:"<< v->data << std::endl;
// printf("\tzIg :"); print(p); print(v); printf("\n");
}
else {
std::cout << "zAg :" << "p:" << p->data << " v:" << v->data << std::endl;
// printf("\tzAg :"); print(p); print(v); printf("\n");
}
if (IsLChild(*v)) { attachAsLC(v->rc, p); attachAsRC(v, p); }
else { attachAsRC(p, v->lc); attachAsLC(p, v); }
this->updateHeight(p); this->updateHeight(v);
}
v->parent = NULL; return v;
} //调整之后新树根应为被伸展的节点,故返回该节点的位置以便上层函数更新树根
3. 完整代码
#include<iostream>
#include "SplayTree.h"
using namespace std;
int main() {
Splay<int> sb;
BinNodePosi(int) root = sb.insertAsRoot(5);
sb.insert(6);
sb.insert(4);
sb.insert(0);
sb.insert(7);
sb.insert(8);
sb.insert(9);
sb.travLevel(root);
sb.search(0);
sb.travLevel(root);
cout << endl;
system("pause");
return 0;
}
4. 代码运行结果截图
以上相关代码参考邓俊辉老师的《c++语言版数据结构》!