不说费话了,直接进入主题。
伸展树的主要特点:每次访问某个节点时,都把此节点旋转到根部。保证从空树开始任意M次操作最多花费O(MlogN)的时间,也就是说它的摊还时间为O(F(N))。
伸展数的主要难点:展开函数的实现。
基本操作插入、删除、查找都和展开函数相关。
插入:在根处按要插入的元素展开树,如果树中已经存在此节点,则此节点在展开后就是根;如果不存在节点,根处的元素是比欲插入节点小的最大节点或比之大的最小节点。插入时则把元素插入根处!
删除:按欲删除的元素展开根,如果此元素存在,则根就是它。删除就删除它吧!^_^请看实现的代码,你会惊奇的发现,相比AVL树的删除,它竟然是如此的简单!
查找:也就是展开树了,欲查找的元素会被旋转到根部。
注意:由于每次访问都会发生旋转,树的根都可能发生变化,所以一定要注意在每一次访问(查找,删除,插入)时要保存新根!

自顶向下展开实现:
一些书上认为伸展树有三种旋转操作:即单旋转/一字旋转/之字旋转。
而我觉得实际上可以认为只有一字旋转/之字旋转,就看你是怎么旋转的思想的,其实至于是什么旋转我们不必归类得这么清晰。我们只要透彻理解展开的思想就行了,即:
设 Splay(e,t)表示从树t中找e,在根处展开,把e旋转到根处,设pcur指向当前的根,有临时节点header,其右孩子用于保存所有比pcur小的节点组成的子树,左孩子节点保存所有比pcur大的节点组成的子树,则从pcur往e的查找路径中,用leftTreeMax把比pcur小的子树串到header的右子树上,用rightTreeMin把比pcur大的子树串到header的左子树上.
(这样看这些文字是非常抽象的,请参见SP_Splay的实现)

在最终找到节点e时,它的左子树和右子树最后一次分离(通过leftTreeMax和rightTreeMin)到header的左右子树上,然后当前的e点左孩子取header的右孩子,e的右孩子取header的左孩子,展开即结束。

源代码:

/**SplayTree.h*/
/**********************************
*author:Felix
*last update:Thu Jan 24 07:56:48 EST 2008
*Address me and exchange our idea ^_^,QQ:349871604,e-mail:lzqziliao2004@163.com
*description:
*
*
*
*/
#ifndef ___SPLAYTREE___
#define ___SPLAYTREE___
#ifndef ___SP_ELEMENT___
#include<stdio.h>
#include<stdlib.h>
typedef int SP_Element;
#endif
struct SP_TreeNode;
typedef struct SP_TreeNode * SP_SplayTree;
typedef struct SP_TreeNode * SP_Position;

/*
if t is not NULL ,free it and return NULL.
*/
SP_SplayTree SP_MakeEmpty(SP_SplayTree t);
SP_SplayTree SP_FindMax(SP_SplayTree t);
SP_SplayTree SP_FindMin( SP_SplayTree t);

/*
 splay the tree.
 if the root is e return immediately
 or insert e as a root and rejust it's left and right child.
*/
SP_SplayTree SP_Insert(SP_Element e,SP_SplayTree t);

/*
 splay the tree .
 if e is found ,delete and rejust it's root
*/
SP_SplayTree SP_Delete(SP_Element e,SP_SplayTree t);

/*find an element e,if element e found ,
it's the root or the root is the one which
is the biggest one in those smaller than e or
the smallest one int those bigger than e
*/
SP_SplayTree SP_Find(SP_Element e,SP_SplayTree t);

/*get the root element**/
SP_Element SP_Retrieve(SP_Position t);

#endif

/***SplayTree.c****/
/**********************************
*author:Felix
*last update:Thu Jan 24 07:56:48 EST 2008
*Address me and exchange our idea ^_^,QQ:349871604,e-mail:lzqziliao2004@163.com
*description:
*
*
*
*/
#include "SplayTree.h"
/**definition and declaration*/
struct SP_TreeNode
{
 SP_Element e;
 SP_SplayTree left;
 SP_SplayTree right;
};
/*
  main function :splay the tree and return root;
*/
static SP_SplayTree SP_Splay(SP_Element e,SP_Position t);
static SP_Position SP_SingleRotateLeft(SP_Position p);
static SP_Position SP_SingleRotateRight(SP_Position p);

/**definition and declaration end*/

/*rotate function*/
SP_Position SP_SingleRotateLeft(SP_Position p)
{
   SP_Position tmp;
   tmp=p->left;
   p->left=tmp->right;
   tmp->right=p;
   return tmp;
  
}
SP_Position SP_SingleRotateRight(SP_Position p)
{
    SP_Position tmp;
    tmp=p->right;
    p->right=tmp->left;
    tmp->left=p;
    return tmp;
}
static SP_SplayTree SP_Splay(SP_Element e,SP_Position p)
{
  /*
  header stores the maxs and mins than e by
  using leftTreeMax and rightTreeMin sticking
  Nodes to itself;
  */
   struct SP_TreeNode header;
   SP_SplayTree leftTreeMax ,rightTreeMin;
   header.left=header.right=NULL;
   leftTreeMax=rightTreeMin=&header;
   if (!p)return NULL;
   while(e!=SP_Retrieve(p)) 
   {
      if(e>SP_Retrieve(p))
      {
         if(!p->right)break;
         if(e>SP_Retrieve(p->right))p=SP_SingleRotateRight(p);
         if(!p->right)break;
         leftTreeMax->right=p;
         leftTreeMax=p;
         p=p->right;
      }
      else
      {
         if(!p->left)break;
         if(e<SP_Retrieve(p->left))p=SP_SingleRotateLeft(p);
         if(!p->left)break;
         rightTreeMin->left=p;
         rightTreeMin=p;
         p=p->left;
          
      }
   }
   leftTreeMax->right=p->left;   
   rightTreeMin->left=p->right;
   p->left=header.right;
   p->right=header.left;

}
/*
if t is not NULL ,free it and return NULL.
*/
SP_SplayTree SP_MakeEmpty(SP_SplayTree t)
{
  if(t)
  {
    if(t->left)SP_MakeEmpty(t->left);
    if(t->right)SP_MakeEmpty(t->right);
    free(t);
  }
 return NULL;
}
SP_SplayTree SP_FindMax(SP_SplayTree t)
{
SP_SplayTree tmp=t;
  if(!tmp)return NULL;
  while(tmp->right)tmp=tmp->right;
 return SP_Splay(SP_Retrieve(tmp),t);
}
SP_SplayTree SP_FindMin( SP_SplayTree t)
{
SP_SplayTree tmp=t;
  if(!tmp) return NULL;
  while(tmp->left)tmp=tmp->left;
 return SP_Splay(SP_Retrieve(tmp),t);
}

/*
 splay the tree.
 if the root is e return immediately
 or insert e as a root and rejust it's left and right child.
*/
SP_SplayTree SP_Insert(SP_Element e,SP_SplayTree t)
{
   struct SP_TreeNode *newnode;
   if(t)t=SP_Splay(e,t);
   if(!t||e!=SP_Retrieve(t))
    {
        newnode = (struct SP_TreeNode*)malloc(sizeof(struct SP_TreeNode));
        newnode->e=e;
        if(!t)
        newnode->left=newnode->right=NULL;
       else
        if(e>SP_Retrieve(t))
        {
           newnode->left=t;
           newnode->right=t->right;
           t->right=NULL;
        }
        else
        {
          newnode->right=t;
          newnode->left=t->left;
          t->left=NULL;
        }
    }
  return (SP_SplayTree)newnode;
}

/*
 splay the tree .
 if e is found ,delete and rejust it's root
*/
SP_SplayTree SP_Delete(SP_Element e,SP_SplayTree t)
{
  SP_SplayTree tmp;
  if(t==NULL)return NULL;
   tmp=t=SP_Splay(e,t);
   if(SP_Retrieve(t)==e)
   {
     if(t->left==NULL)
     tmp=t->right;
     else
     {
         t->left=SP_Splay(e,t->left);
         t->left->right=t->right;
         tmp=t->left;
         free(t);
     }
   }
  return tmp;
}

/*find an element e,if element e found ,
it's the root or the root is the one which
is the biggest one in those smaller than e or
the smallest one int those bigger than e
*/
SP_SplayTree SP_Find(SP_Element e,SP_SplayTree t)
{
    return SP_Splay(e,t);
}

/*get the root element**/
SP_Element SP_Retrieve(SP_Position t)
{
  return t->e;
}

/****测试文件,这里用到前面文章提到的绘制二叉树的函数,如果你无法编译通过,请自己编写测试文件,或者找我**/

/**testSplayTeee.c**/
/*vgalib库可能不太稳定。
*author:Felix
*create date:Tue Jan 15 20:14:10 EST 2008
*last update:Tue Jan 15 20:14:10 EST 2008
*description:
*
*/
#include "menu_c.h"
#include<stdio.h>
#include<stdlib.h>
#include"SplayTree.h"
#include"drawBitTree.h"
struct SP_SplayTreeNode
{
  SP_Element e;
  SP_SplayTree left;
  SP_SplayTree right;
};
/******define some function to show the tree*******/
 int getkey(void * t)
{
   return ((struct SP_SplayTreeNode*)t)->e;
}
void * getchild(void * t,int mode)
{
  if(mode==DB_LEFTCHILD)return ((struct SP_SplayTreeNode*)t)->left;
  else return ((struct SP_SplayTreeNode*)t)->right;
}
/*****************/
int main()
{
int n;
SP_SplayTree t;
SP_Position p;
t=SP_MakeEmpty(NULL);

while(SELECT())
{
 switch (SELECTION)
 {
 case '1':
  printf("integer:>");
  scanf("%d",&n);
  t=SP_Insert(n,t);

break;
 case '2':
  printf("integer to delete:>");
  scanf("%d",&n);
  t=SP_Find(n,t);
  if(SP_Retrieve(t)!=n)printf("sorry,no integer match");
  else {
   t=SP_Delete(n,t);
   printf("deletion done");
  }
 break;
 case '3':
  if(t=SP_FindMin(t))
  {
     printf("%d " ,SP_Retrieve(p),t);
   t= SP_Delete(SP_Retrieve(t),t);
  }
 break;
 case '4':
  if(t=SP_FindMax(t))
  {
     printf("%d " ,SP_Retrieve(t));
    t=SP_Delete(SP_Retrieve(t),t);
  }
 break;
 case '5':
  if(!(t=SP_FindMax(t)))printf("sorry,the tree is NULL");
else
  printf("%d",SP_Retrieve(t));
 break;
 case '6':
  if(!(t=SP_FindMin(t)))printf("sorry ,the tree is NULL");
  else
  printf("%d",SP_Retrieve(t));
 break;
 case '7':
  
   DB_DrawBitTree(t,getchild,getkey);
 break;
 case '9':
 system("less ../SP_tree.h");
 break;
 default:break;
 }
}
return 0;
}
/**menu_c.h**/
/*///
*author:Felix
*create date:Fri Jan 11 03:45:18 EST 2008
*last update:Fri Jan 11 03:45:18 EST 2008
*description:
*
*
*/
#include <stdio.h>
#ifndef __MENU____
#define __MENU____
#define SELECT() ((___sel=___select())!='0')
#define SELECTION ___sel
char ___sel;
char ___select();
/*
 define the menu:
*/
#endif
/**menu_c.c*/
/*///
*author:Felix
*create date:Fri Jan 11 03:45:18 EST 2008
*last update:Fri Jan 11 03:45:18 EST 2008
*description:
*
*
*/
#include "menu_c.h"
char *___menu[]={
 
"1.Insert a integer.",
"2.Delete an integer from the tree.",
"3.Sort and show from small to big(will delete the tree)",
"4.Sort and show from big to small(will delete the tree)",
"5.show the max",
"6.show the min", "9.Print the file ST_tree.h",
"7.show the tree",
"0.EXIT",
NULL
};
void ___showMenu()
{
 printf("please select:/n");
 char **p=___menu;
 while(*p)printf("%s/n",*p++);
 printf(":>");
}
char ___select()
{
char c;
 ___showMenu();
 while((c=getchar())=='/n');
 return c;
}

自顶向下伸展树的实现与测试-建立自己的c数据结构与算法库系列(14)相关推荐

  1. AVL平衡树c语言实现与测试-建立自己的c数据结构与算法库系列(最新修改)(13)

    重新修改让我非常郁闷,本来已经详细分析,图文并茅,自认为分析得非常晰. 写完保存,居然没有成功,一大堆工作白费了.CSDN这个博客真是让我失望啊,Best4c中画图非常辛苦,可是画完了也白费了. 唉呀 ...

  2. 高级数据结构实现——自顶向下伸展树

    [0]README 1) 本文部分内容转自 数据结构与算法分析,旨在理解 高级数据结构实现--自顶向下伸展树 的基础知识: 2) 源代码部分思想借鉴了数据结构与算法分析,有一点干货原创代码,for o ...

  3. 自顶向下伸展树实现文件C语言

    /* SplayTree.c -- 自顶向下伸展树实现文件 */ #include "SplayTree.h" /* 外部变量引用 */ extern Node * NullNod ...

  4. js遍历树节点下的所有子节点_【数据结构与算法】(3)——树和二叉树

    树 树的基本概念 树是一种非线性的数据结构,样子如图所示: 树的主要特点是树中的数据是分层存储的,每个元素称为树的节点,最顶层有且只有一个元素,称为根节点,其余层可以有任意数量的节点.除了根节点,其余 ...

  5. 【数据结构与算法】【14】以树状形式打印二叉树

    技术难点 以树状形式打印二叉树的关键难点在于,如何计算和控制每个节点的打印位置 解决思路 将二叉树的所有节点从左往右全部打印出来,正好和二叉树中序遍历的结果是一样的 利用这个特点,我们就可以通过中序遍 ...

  6. 数据结构--伸展树(伸展树构建二叉搜索树)-学习笔记

    2019/7/16更新:封装SplayTree进入class:例题:http://poj.org/problem?id=3622 一个伸展树的板子: #include<stdio.h> # ...

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

    [0]README 0.1) 本文总结于 数据结构与算法分析,核心剖析路线为原创, 旨在理清 自底向上伸展树(之字形旋转+一字形旋转) 的基本思路: 0.2) 自底向上伸展树 是基于 AVL树,for ...

  8. 伸展树的基本操作与应用 IOI2004 国家集训队论文 杨思雨

    伸展树的基本操作与应用 安徽省芜湖一中 杨思雨 [关键字] 伸展树 基本操作 应用 [摘要] 本文主要介绍了伸展树的基本操作以及其在解题中的应用.全文可以分为以下四个部分. 第一部分引言,主要说明了二 ...

  9. 伸展树(Splay Tree)尽收眼底

    原文地址:http://dsqiu.iteye.com/blog/1706592 伸展树(Splay Tree)尽收眼底 本文内容框架: §1 伸展树定义 §2 伸展树自底向上伸展   §3 伸展树自 ...

最新文章

  1. 题目:[NOIP2008]笨小猴
  2. java的数值类型举例_Java基本类型(示例代码)
  3. 重装华为服务器系统软件,服务器系统重装软件
  4. 【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 - 笔记
  5. [react] react中修改prop引发的生命周期有哪几个?
  6. 为系统扩展而采取的一些措施——缓存
  7. selenuim webDriver API 16种定位方式
  8. 泥瓦匠 5 年 Java 的成长感悟(下)
  9. springcloud gateway_Spring Cloud构建微服务架构(五)服务网关
  10. 13我无所不能——无线网络里面的秘密
  11. 住在我隔壁储藏室的大学刚毕业的小夫妻[转载]
  12. 会议摘要怎么写?这篇论文手把手教你
  13. 一张思维导图囊括所有 Python 基础
  14. 基于android手机实时监控ipcam视频之二:mediastream2
  15. SEH X64(3)
  16. windows 上Miktex的镜像源最新配置方法
  17. angularjs 同步請求_AngularJS 应用请求设置同步问题~
  18. DDR扫盲——DDR与DDR2、DDR3的区别
  19. 康普分享未来网络四大趋势 光纤将是最佳主角
  20. 安装和简单使用visual studio 2017

热门文章

  1. 内存五区到底是什么?
  2. 李沐「动手学深度学习」中文课程笔记来了!代码还有详细中文注释
  3. 设计模式 | 观察者模式/发布-订阅模式(observer/publish-subscribe)
  4. elementui 上传图片 合集
  5. 仅有两年工作经验的我是如何成功面试阿里P6,android开发的基础
  6. 史上最全的Https讲解
  7. windows下mysql自动备份
  8. SSL/OPENSSL笔记
  9. linux下crontab命令的用法,Linux下crontab命令的用法
  10. Ant design Pro of vue 实战一