博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
伸展树——自顶向下
阅读量:5822 次
发布时间:2019-06-18

本文共 6142 字,大约阅读时间需要 20 分钟。

三种旋转

   当我们沿着树向下搜索某个节点X的时候,我们将搜索路径上的节点及其子树移走。我们构建两棵临时的树──左树和右树。

没有被移走的节点构成的树称作中树。在伸展操作的过程中:

1、当前节点X是中树的根。

2、左树L保存小于X的节点。
3、右树R保存大于X的节点。
开始时候,X是树T的根,左右树L和R都是空的。
1、zig:
 
                                
    如上图,在搜索到X的时候,所查找的节点比X小,将Y旋转到中树的树根。旋转之后,X及其右子树被移动到右树上。很显然,右树上的节点都大于所要查找的节点。注意X被放置在右树的最小的位置,也就是X及其子树比原先的右树中所有的节点都要小。这是由于越是在路径前面被移动到右树的节点,其值越大。
2、zig-zig:
 
                                
    在这种情况下,所查找的节点在Z的子树中,也就是,所查找的节点比X和Y都小。所以要将X,Y及其右子树都移动到右树中。首先是Y绕X右旋,然后Z绕Y右旋,最后将Z的右子树(此时Z的右子节点为Y)移动到右树中。注意右树中挂载点的位置。
3、zig-zag:
 
                            
    在这种情况中,首先将Y右旋到根。这和Zig的情况是一样的。然后变成上图右边所示的形状。接着,对Z进行左旋,将Y及其左子树移动到左树上。这样,这种情况就被分成了两个Zig情况。这样,在编程的时候就会简化,但是操作的数目增加(相当于两次Zig情况)。
    最后,在查找到节点后,将三棵树合并。如图:
 
                                

    将中树的左右子树分别连接到左树的右子树和右树的左子树上。将左右树作为X的左右子树。重新最成了一所查找的节点为根的树。

右连接:将当前根及其右子树连接到右树上。左子结点作为新根。  左连接:将当前根及其左子树连接到左树上。右子结点作为新根。

越是在路径前面被移动到右树的节点,其值越大;越是在路径前面移动到左树的节点,其值越小。

 这很显然,右连接,将当前根以及右子树全部连接到右树,即把整课树中值大的一部分移走(大于等于当前根),

 后面,在进行右连接,其值肯定小于之前的,所以,要加在右树的左边。

 

伸展树伪代码

右连接:将当前根及其右子树连接到右树上。左子结点作为新根。 左连接:将当前根及其左子树连接到左树上。右子结点作为新根。  T : 当前的根节点。  Function Top-Down-Splay     Do          If X 小于 T Then               If X 等于 T 的左子结点 Then           //zig                 右连接               ElseIf X 小于 T 的左子结点 Then       //zig-zig                 T的左子节点绕T右旋                 右连接               Else X大于 T 的左子结点 Then          //zig-zag                 右连接                 左连接               EndIf               ElseIf X大于 T Then               IF X 等于 T 的右子结点 Then                 左连接               ElseIf X 大于 T 的右子结点 Then                 T的右子节点绕T左旋                 左连接               Else X小于 T 的右子结点 Then                 左连接                 右连接               EndIf          EndIf     While  !(找到 X或遇到空节点)      组合左中右树  EndFunction

zig-zag这种情形,可以先按zig处理。第二次循环在进行一次处理。简化代码如下:

Function Top-Down-Splay      Do          If X 小于 T Then               If X 小于 T 的左孩子 Then                  T的左子节点绕T右旋               EndIf                   右连接              Else If X大于 T Then                If X 大于 T 的右孩子 Then                    T的右子节点绕T左旋                EndIf                左连接              EndIf      While  !(找到 X或遇到空节点)      组合左中右树  EndFuntion

例子

下面是一个查找节点19的例子:

    在例子中,树中并没有节点19,最后,距离节点最近的节点18被旋转到了根作为新的根。节点20也是距离节点19最近的节点,但是节点20没有成为新根,这和节点20在原来树中的位置有关系。
 
  如果查找的元素不在树中,则寻找过程中出现空的上一个节点即为根节点。

CPP代码

 .h

struct SplayNode{    int element;    SplayNode *left;    SplayNode *right;};class SplayTree{    public:        SplayTree();        ~SplayTree();                void Insert(int data);        void Remove(int data);        SplayNode *Find(int data);            private:        SplayNode *_tree;                SplayNode *_Insert(SplayNode *T, int item);        SplayNode *_Remove(SplayNode *T, int item);        SplayNode *_Splay(SplayNode *X, int Item);                SplayNode *_SingleToRight(SplayNode *K2);                  SplayNode *_SingleToLeft(SplayNode *K2);                   void  _MakeEmpty(SplayNode *root);            };

.cpp

SplayTree::SplayTree(){    _tree = NULL;}SplayTree::~SplayTree(){    _MakeEmpty(_tree);}void SplayTree::Insert(int data){    _tree = _Insert(_tree, data);}void SplayTree::Remove(int data){    _tree = _Remove(_tree, data);}SplayNode *SplayTree::_SingleToRight(SplayNode *K2)  {      SplayNode *K1 = K2->left;      K2->left = K1->right;      K1->right = K2;              return K1;  }              SplayNode *SplayTree::_SingleToLeft(SplayNode *K2)  {      SplayNode *K1 = K2->right;      K2->right = K1->left;      K1->left  = K2;                return K1;  }         SplayNode *SplayTree::_Splay(SplayNode *X, int item){    static struct SplayNode Header;    SplayNode *leftTreeMax, *rightTreeMin;        Header.left = Header.right = NULL;    leftTreeMax = rightTreeMin = &Header;        while( X != NULL && item != X->element)    {        if(item < X->element)        {            if(X->left == NULL)                break;            if(item < X->left->element)            {                X = _SingleToRight(X);             }             if( X->left == NULL)                break;                        //右连接                        rightTreeMin->left = X;            rightTreeMin       = X;            X                  = X->left;        }        else        {            if(X->right == NULL)                break;            if(item > X->right->element)            {                X = _SingleToLeft(X);            }            if(X->right == NULL)                break;                        //左连接                        leftTreeMax->right = X;            leftTreeMax        = X;            X                  = X->right;        }    }    leftTreeMax->right = X->left;    rightTreeMin->left = X->right;    X->left = Header.right;    X->right = Header.left;        return X;}SplayNode *SplayTree::_Insert(SplayNode *T, int item){    static SplayNode* newNode = NULL;        if(newNode == NULL)    {        newNode = new SplayNode;    }    newNode->element = item;        if(T == NULL)    {        newNode->left = newNode->right = NULL;        T = newNode;    }    else    {        T = _Splay(T, item);        if(item < T->element)        {            newNode->left = T->left;            newNode->right = T;            T->left = NULL;            T = newNode;        }        else if(T->element < item)        {            newNode->right = T->right;            newNode->left = T;            T->right = NULL;            T = newNode;        }        else        {            delete newNode;        }    }    newNode = NULL;    return T;}SplayNode *SplayTree::_Remove(SplayNode *T, int item){    SplayNode *newTree;        if(T != NULL)    {        T = _Splay(T, item);        if(item == T->element)        {            if(T->left == NULL)            {                newTree = T->right;            }            else            {                newTree = T->left;                newTree = _Splay(newTree, item);                newTree->right = T->right;            }            delete T;            T = newTree;        }    }    return T;}void SplayTree::_MakeEmpty(SplayNode *T)  {      if(T != NULL)      {          _MakeEmpty(T->left);          _MakeEmpty(T->right);          delete T;      }  }SplayNode *SplayTree::Find(int data){    _tree = _Splay(_tree, data);    if(_tree->element == data)        return _tree;    else        return NULL;}

 

转载地址:http://qsbdx.baihongyu.com/

你可能感兴趣的文章
HP iLO2 使用详细图文教程
查看>>
Linux文本编辑器之Nano
查看>>
Linux系统集群架构线上项目配置实战(一)
查看>>
VC无闪烁刷屏技术的实现【转】
查看>>
【原】IOS中KVO模式的解析与应用
查看>>
EntityFramework Core迁移时出现数据库已存在对象问题解决方案
查看>>
urb传输的代码分析【转】
查看>>
理解 QEMU/KVM 和 Ceph(3):存储卷挂接和设备名称
查看>>
一道算法题的一种O(n)解法
查看>>
ABP理论学习之NHibernate集成
查看>>
反射之动态创建对象
查看>>
隐马尔可夫模型学习小记——forward算法+viterbi算法+forward-backward算法(Baum-welch算法)...
查看>>
[MFC] CList
查看>>
[Android Pro] 完美Android Cursor使用例子(Android数据库操作)
查看>>
4 张 GIF 图帮助你理解二叉查找树
查看>>
c++中sizeof的分析
查看>>
线程间操作无效: 从不是创建控件的线程访问它的解决方法
查看>>
hdu 1236 排名
查看>>
【爆牙游记】黄山归来不看岳-日出。
查看>>
PHP面向对象深入研究之【继承】,减少代码重复
查看>>