关闭

伸展树的代码实现

标签: 数据结构
295人阅读 评论(0) 收藏 举报
分类:

一、伸展树的数据结构

typedef struct Node
{
    int key;    
    struct Node *lch,*rch,*parent;
}* Node ,* Tree;

二、伸展树的基础操作

下面几个函数中,设x 的父节点为 p, p的父节点为g 。

  • zig( t , x )
    右旋。当p是根节点,x是p的左孩子,将x右旋。
    这里写图片描述
    代码如下:
//单次右旋以 root 节点 为根节点的树 
Node zig( Tree tree , Node root)
{
    Node lc = root->lch;
    Node parent = root->parent;

    //处理父节点关系 
    if( parent )
    {
        if( root == parent->lch )
        {
            parent->lch = lc;
        }else{
            parent->rch = lc;
        }
        lc->parent = parent;
    }else{
        lc->parent = NULL;
    }

    //翻转 
    if( lc != NULL )
    {
        root->lch = lc->rch;
        if( lc->rch )
        {
            lc->rch->parent = root;
        } 
        lc->rch = root;
        root->parent = lc;
        if( parent )
        {
            return tree;
        }else{
            return lc;  
        }

    }
    return tree;
}
  • zag( t , x )
    左旋。当p是根节点,x是p的右孩子,将x左旋
//单次左旋以 root 节点 为根节点的树 
Node zag( Tree tree , Node root)
{
    Node rc = root->rch;
    Node parent = root->parent;
    //处理父节点关系 
    if( parent )
    {
        if( root == parent->lch )
        {
            parent->lch = rc;
        }else{
            parent->rch = rc;
        }
        rc->parent = parent;
    }else{
        rc->parent = NULL;
    }
    //翻转 
    if( rc != NULL )
    {
        root->rch = rc->lch;
        if( rc->lch )
        {
            rc->lch->parent = root;
        } 
        rc->lch = root;
        root->parent = rc;
        if( parent )
        {
            return tree;
        }else{
            return rc;  
        }
    }
    return tree;
}
  • zig_zig( t , x )
    右双旋。x是p的左节点,当p是g的左节点,先将p右旋,再将x右旋
//右双旋以 root 节点 为根节点的树 
Node zig_zig( Tree tree , Node root)
{
    Node lc = root->lch;
    Node node=zig( tree , root );
    return zig( node , lc );
}
  • zag_zag( t , x )
    左双旋。x是p的右节点,当p是g的右节点,先将p左旋,再将x左旋
//左双旋以 root 节点 为根节点的树 
Node zag_zag( Tree tree , Node root)
{
    Node rc = root->rch;
    Node node=zag( tree , root );
    return zag( node , rc );
}
  • zig_zag( t , x )
    右旋再左旋。x是p的左节点,当p是g的右节点,先将x右旋,再将x左旋
Node zig_zag( Tree tree , Node root)
{
    Node node=zig( tree , root->rch );
    return zag( node , root );
}
  • zag_zig( t , x )
    左旋再右旋。x是p的右节点,当p是g的左节点,先将x左旋,再将x右旋
Node zag_zig( Tree tree , Node root)
{
    Node node=zag( tree , root->lch ); 
    return zig( node , root );
}
  • zig_zag_manager( t , x)
    旋转管理者。 找到x,分析x与父亲节点,父亲节点与祖父节点的关系,选择恰当的旋转方式。
//根据目标节点的结构选择相应的算法,策略模式 
Node zig_zag_manager( Tree tree , Node node )
{ 
    Node parent = node->parent;
    if( parent == tree  )    //1
    {
        if( parent->lch == node )
        {
            return zig( tree , parent );
        }else{
            return zag( tree , parent );
        }

    }else if(  parent->lch == node ){ //2
        Node grand = parent->parent;    
        if( grand->lch == parent ){ /*左左*/
            return zig_zig( tree , grand ); 
        }else{                      /*右左*/ 
            return zig_zag( tree , grand );
        }

    }else if( parent->rch == node ){ //3

        Node grand = parent->parent;    
        if( grand->lch == parent ){ /*左右*/
            return zag_zig( tree , grand ); 
        }else{                      /*右右*/
            return zag_zag( tree , grand );
        }
    }

    return tree;
}
  • splay( t ,x )
    将x调至根部。循环调用zig_zag_manager( t , x) 方法,直到x == t
//将目标节点调整到树的根部,并返回树根 
Node splay(Tree tree , Node node)
{
    while( node->parent!=NULL )
    {
        zig_zag_manager( tree , node );
    }
    return node;
}
  • find( t , x )
    找到x。找到x,然后将x旋转到树根。
//寻找key节点 
Node find( Tree tree , int key )
{
    Node curr = tree;
    while( curr != NULL )
    {
        if( curr->key == key ){
            splay( tree , curr );
            return curr;    
        } else if( curr->key > key ){
            curr = curr->lch;
        }else{
            curr = curr->rch;
        }
    }
    return NULL;
}
  • spilt( t , x)
    以x为界分离t。找到x,将x旋转到树根,然后将x的左子树和剩余部分分离
//以 node 为届,分离 tree 的左子树 ,返回剩余部分 
Node spilt( Tree tree , Node node )
{
    tree = splay( tree , node ); //将 node 调至根部
    Node lc = tree->lch;
    tree->lch = NULL;
    if( lc ) 
    {
        lc->parent = NULL;
    }
    return tree;
}

注意这里,要获得左子树可以在分离之前获得。

  • join( t1 , t2 )
    合并子树 t1和t2,要求t1所有元素小于t2的任一元素。找到t1的最大元素,并调整到根部,将t2作为根的右子树插入
//合并tree1 和 tree2 ,要求 tree1 所有元素小于 tree2 任一元素 
Node join( Tree tree1, Tree tree2)
{
    //找打 tree1 中最大的元素 
    Node temp = tree1;
    while( temp->rch != NULL )
    {
        temp = temp->rch;
    } 
    //将 temp调至 tree1的根部 
    splay( tree1 ,temp );
    //将 tree2 作为 temp的右子树
    temp->rch = tree2;
    tree2->parent = temp;
    return temp; 
}

附件:
1. C-free工程,也可直接打开文件.zip
2. 广东工业大学-计算机学院-伸展树.pdf

0
0
查看评论

查找——图文翔解SplayTree(伸展树)

伸展树 伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它由Daniel Sleator和Robert Tarjan创造,后者对其进行了改进。 假设想要对一个二叉查找树执行一系列的查找操作。为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置。于是想到设计一个简...
  • yang_yulei
  • yang_yulei
  • 2015-05-27 00:05
  • 5804

伸展树学习

一篇很好的伸展树学习文章,不转载了,直接贴地址吧http://blog.csdn.net/niuox/article/details/8018280
  • discreeter
  • discreeter
  • 2016-05-28 12:06
  • 2570

伸展树解决区间问题

伸展树解决区间问题的原理 考虑一个序列,从1开始编号,记作A[1...N]A[1...N],在其上实施一些区间操作。例如,将[s,e][s, e]中的数都增加一个deltadelta,查询[s,e][s, e]的所有数的和或者极值,甚至将[s,e][s, e]区间从原序列中删除(之后的数依次前移)...
  • u012061345
  • u012061345
  • 2016-06-04 12:18
  • 828

自底向上伸展树(之字形旋转+一字形旋转)

【0】README0.1) 本文总结于 数据结构与算法分析,核心剖析路线为原创, 旨在理清 自底向上伸展树(之字形旋转+一字形旋转) 的基本思路;【1】伸展树(之字形旋转+一字形旋转)1.1)定义: 伸展树保证从空树开始任意连续M次对树的操作最多花费 O(M logN)时间; 1.2)摊还运行时...
  • PacosonSWJTU
  • PacosonSWJTU
  • 2016-01-15 18:58
  • 1622

无比强大的数据结构 伸展树总结

链接 :http://www.notonlysuccess.com/index.php/splay-tree/ 论文链接:http://www.docin.com/p-62465596.html 其实本来不想学splay树的,因为好像平时做题不怎么用到,但是,请注意,书到用时方恨少啊,多...
  • haha593572013
  • haha593572013
  • 2012-09-30 17:09
  • 3091

伸展树的旋转和伸展操作

伸展树(Splay Tree)是一种排序二叉树,其核心操作是伸展。所谓伸展就是把指定节点旋转至树根(同时保持排序二叉树性质)的过程。而伸展操作的基础就是旋转。     旋转是所有排序二叉树的基本操作,各种平衡二叉树想要维持其平衡性质都离不开旋转。旋转分为左旋和右旋。但实际上,如果...
  • u012061345
  • u012061345
  • 2014-05-08 09:37
  • 1318

bzoj1503: [NOI2004]郁闷的出纳员(伸展树)

题目传送门 基本也算入门题了。解法: 就伸展树维护一下然后加个暴力吧。代码实现:#include<cstdio> #include<cstring> #include<cmath> using namespace std; int root; struct n...
  • Hanks_o
  • Hanks_o
  • 2017-10-23 19:46
  • 230

伸展树应用初步——解决区间问题

伸展树的基本操作就是伸展,也就是将指定节点旋转至树根(同时不改变排序二叉树的性质)。在这个操作的基础上,配合节点中保存额外的数据域,伸展树可以完成多种任务,包括各种区间问题。     伸展树的节点除了保存必要的指针信息和键值对之外,经常使用的额外的数据域包括size域、sum域、...
  • u012061345
  • u012061345
  • 2014-05-09 21:44
  • 1420

Java数据结构与算法解析(八)——伸展树

伸展树简介伸展树(Splay Tree)是特殊的二叉查找树。 它的特殊是指,它除了本身是棵二叉查找树之外,它还具备一个特点: 当某个节点被访问时,伸展树会通过旋转使该节点成为树根。这样做的好处是,下次要访问该节点时,能够迅速的访问到该节点。特性1.和普通的二叉查找树相比,具有任何情况下、任何操作的...
  • u012124438
  • u012124438
  • 2017-09-22 23:48
  • 8699

C++伸展树自顶向下实现

伸展树的三种旋转:单旋转,一字型旋转,之字形旋转 为了简化程序,将之字形旋转转变为如下旋转方式: -SplayTree.h 代码: /* * by: peige * 2015/11/29 */ #ifndef __SPLAY_TREE_H__ #define __SPLAY_TRE...
  • qq1263292336
  • qq1263292336
  • 2015-11-29 11:12
  • 493
    个人资料
    • 访问:192914次
    • 积分:3271
    • 等级:
    • 排名:第12337名
    • 原创:128篇
    • 转载:0篇
    • 译文:4篇
    • 评论:35条
    博客专栏