首先我们应该知道什么是伸展树?伸展树是Bst(二叉查找树)的扩展版,而且伸展树不需要存储像AVL树那样的平衡因子或者高来保持平衡,那伸展树是不是会出现严重不平衡的情况呢?就行斜树,答案:不会的哦。后面大家就明白了。伸展树的功能是什么呢?当我们搜索大量数据时为了提高搜索的效率,往往搜索到的数据,下次使用的概率往往会比较大,比如我们使用的智能输入法,浏览网页等等。这里就用到了伸展树哦。
告诉大家:伸展树也要进行旋转的哦!等等,这时有人会诧异,伸展树不具有AVL树的特性,为什么要旋转呢?让我给大家慢慢解释:伸展树的作用就是把搜索到的数据“转移”到树根,那怎么“转移”到树根呢?这就要通过伸展,这也是伸展树的核心所在。而伸展是通过什么实现的呢?答案就是旋转哦。伸展过程中有三种旋转:单旋转,一字型旋转,之字型旋转。
在介绍旋转之前,必须要说一下伸展树的两种伸展的思想:自底向上的伸展,自顶向下的伸展。
自底向上:就是从底端向上伸展,伸展的过程中要保存其父节点,而且有时候在伸展的过程中有些的节点的深度往往还会变大。所以说这种思想往往不适用,而且效率还较低。
自顶向下:从顶部向下伸展,伸展的过程中会有两个空树:RightTreeMin,LeftTreeMax. RightTreeMin存放的是比根节点大的节点,但是往往在连续存放过程中,其存放的数据会愈来愈大,所以叫"RightTreeMin"。LeftTreeMax也是同样的道理哦。
单旋转:
之字形旋转:
大家发现没,单旋转和之字形旋转是一模一样的哦。
一字型旋转:
大家发现没,一字型旋转就是AVL树种的左旋或右旋。
那为什么叫伸展树呢?不叫其他的树呢?其实这和它的实现密切相关。伸展树有两种实现的思想:自底向上的实现,自顶向下的实现。
旋转完后最终要形成一颗完整的树。
完整代码如下:
typedef struct SplayNode *TreeNode;
typedef int ElemType;
struct SplayNode {
ElemType element;
TreeNode lchild;
TreeNode rchild;
};
class SplayTree
{
public:
SplayTree() :nullnode(new SplayNode()) {
stroot = nullnode;
};
~SplayTree() {
if (nullnode)
delete nullnode;
}
void Insert(const ElemType X );
void Display();
void Delete(const ElemType X);
ElemType Find(const ElemType X);
ElemType FindMax();
ElemType FindMin();
private:
void Splay(const ElemType, TreeNode& stree);
void Display(const TreeNode& stree);
void RotateRR(TreeNode& stree); //右旋
void RotateLL(TreeNode& stree); //左旋
void FindMax(TreeNode& stree);
void FindMin(TreeNode& stree);
private:
TreeNode stroot; //根节点
TreeNode nullnode; //为什么要这个节点的呢?这样可以避免出现nullptr->左右孩子的情况
};
void SplayTree::Splay(const ElemType X, TreeNode &stroot) {
TreeNode RightChildMin, LeftChildMax;
RightChildMin = LeftChildMax = nullnode;
RightChildMin->lchild = RightChildMin->rchild = nullnode;
LeftChildMax->lchild = LeftChildMax->rchild = nullnode;
nullnode->element = X; //防止重复
while (X != stroot->element) { //不在根节点
if (X < stroot->element) { //先判断一字型,然后再进行单旋转。
if (stroot->lchild == nullnode)
break;
if (X < stroot->lchild->element)
RotateRR(stroot);
RightChildMin->lchild = stroot;
RightChildMin = stroot;
stroot = stroot->lchild;
}
else {
if (stroot->rchild == nullnode)
break;
if (X > stroot->rchild->element)
RotateLL(stroot);
LeftChildMax->rchild = stroot;
LeftChildMax = stroot;
stroot = stroot->rchild;
}
}
LeftChildMax->rchild = stroot->lchild;
RightChildMin->lchild = stroot->rchild;
stroot->lchild = LeftChildMax->rchild;
stroot->rchild = RightChildMin->lchild;
}
void SplayTree::RotateRR(TreeNode& stree) {
if (!stree)
return;
else {
auto ptr = stree->lchild;
stree->lchild = ptr->rchild;
ptr->rchild = stree;
stree = ptr;
}
}
void SplayTree::RotateLL(TreeNode& stree) {
if (!stree)
return;
else {
auto ptr = stree->rchild;
stree->rchild = ptr->lchild;
ptr->lchild = stree;
stree = ptr;
}
}
void SplayTree::Insert(const ElemType X) {
TreeNode newnode = nullptr;
if (newnode == nullptr) {
newnode = new SplayNode();
if (newnode == nullptr)
throw std::out_of_range("Out of MemorySpace!!");
}
newnode->element = X;
if (stroot == nullnode) {
newnode->lchild = newnode->rchild = nullnode;
stroot = newnode;
}
else {
Splay(X, stroot);
if (X < stroot->element) {/*
newnode
/ \
/ \
stroot->lchild stroot */
newnode->lchild = stroot->lchild;
newnode->rchild = stroot;
stroot->lchild = nullnode;
stroot = newnode;
}
else if (X > stroot->element) {
newnode->rchild = stroot->rchild;
newnode->lchild = stroot;
stroot->rchild = nullnode;
stroot = newnode;
}
else
return;
}
}
void SplayTree::Delete(const ElemType X) {
TreeNode newnode = nullnode;
if (stroot==nullnode)
return;
else {
Splay(X, stroot);
if (X == stroot->element) {
if (stroot->lchild == nullnode) //左子树为空
newnode = stroot->rchild;
else {
newnode= stroot->lchild;
Splay(X, stroot);
newnode->rchild = stroot->rchild;
}
delete stroot;
stroot = newnode;
}
}
}
ElemType SplayTree::Find(const ElemType X) {
if (!stroot)
return 0;
else {
Splay(X, stroot);
if (stroot->element == X) {
std::cout << "X is exit!!";
return stroot->element;
}
else
std::cout << "X is not exit!!";
}
}
ElemType SplayTree::FindMax() {
FindMax(stroot);
return stroot->element;
}
ElemType SplayTree::FindMin() {
FindMin(stroot);
return stroot->element;
}
void SplayTree::FindMax(TreeNode& stree) {
if (stree != nullnode)
while (stree->rchild != nullnode)
stree = stree->rchild;
Splay(stree->element, stree);
}
void SplayTree::FindMin(TreeNode& stree) {
if (stree != nullnode)
while (stree->lchild != nullnode)
stree = stree->lchild;
Splay(stree->element, stree);
}
void SplayTree::Display() {
Display(stroot);
}
void SplayTree::Display(const TreeNode &stree) {
if (stree != nullnode) {
std::cout<<stree->element << std::endl;
Display(stree->lchild);
Display(stree->rchild);
}
else
return;
}
参考:《数据结构与算法分析》