原文地址:http://dsqiu.iteye.com/blog/1706592

伸展树(Splay Tree)尽收眼底

本文内容框架:

§1 伸展树定义

§2 伸展树自底向上伸展

  §3 伸展树自顶向下伸展

§4 伸展树基本操作,实现以及应用

§5 小结

§1 伸展树定义

伸展树的定义

假设想要对一个二叉查找树执行一系列的查找操作。为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置。于是想到设计一个简单方法,在每次查找之后对树进行重构,把被查找的条目搬移到离树根近一些的地方。splay tree应运而生。splay tree是一种自调整形式的二叉查找树,它会沿着从某个节点到树根之间的路径,通过一系列的旋转把这个节点搬移到树根去。

伸展树并并不利用任何明确的规则来保证它的平衡,而是在每次访问之后,利用一种称为伸展操作将当前访问的结点移动到根,来维持查找树的平和。在插入,删除,甚至查找过程中,在到达的最底部的结点X上执行伸展操作。

为了将当前被访问节点旋转到树根,我们通常将节点自底向上旋转,直至该节点成为树根为止。“旋转”的巧妙之处就是在不打乱数列中数据大小关系(指中序遍历结果是全序的)情况下,所有基本操作的平摊复杂度仍为O(log n)。

伸展树根据伸展的方式不同分为:自底向上伸展和自顶向下伸展,下面分别介绍。

§2 伸展树自底向上伸展  

自底向上伸展树

伸展树主要有三种旋转操作,分别为单旋转,一字形旋转和之字形旋转。为了便于解释,假设当前被访问节点为X,X的父亲节点为Y(如果X的父亲节点存在),X的祖父节点为Z(如果X的祖父节点存在)。

(1) 单旋转

节点X的父节点Y是根节点。这时,如果X是Y的左孩子,我们进行一次右旋操作;如果X 是Y 的右孩子,则我们进行一次左旋操作。经过旋转,X成为二叉查找树T的根节点,调整结束。

注:这张图有误,单旋之后应该A和B应该对调。

(2) 一字型旋转

节点X 的父节点Y不是根节点,Y 的父节点为Z,且X与Y同时是各自父节点的左孩子或者同时是各自父节点的右孩子。这时,我们进行一次左左旋转操作或者右右旋转操作。

(3) 之字形旋转

节点X的父节点Y不是根节点,Y的父节点为Z,X与Y中一个是其父节点的左孩子而另一个是其父节点的右孩子。这时,我们进行一次左右旋转操作或者右左旋转操作。

§3 伸展树自顶向下伸展

自顶向下伸展树

自顶向下伸展操作将伸展树分为三部分:

左树:包含所有已经知道比待查节点 X小的节点。

右树:包含所有已经知道比待查节点 X大的节点。

中树:包含所有其它节点。

在中树自根向下进行节点查找(每次向下比较两个节点),根据查找情况将中树中的节 点移动(此处的移动是指将节点和中树的连接断开,而将节点连接到左或右树的适当位置。)到左树或右树(如有必要则会先对中树进行旋转再进行节点移动)。

初始状态时,左树和右树都为空,而中树为整个原伸展树。随着查找的进行,左树和右

树会因节点的逐渐移入变大,中树会因节点的逐渐移出变小。最后查找结束(找到或遇到空

节点)时组合左中右树并是伸展树自顶向下伸展方法的最终结果。

有四种情况:

1,孩子即为要查找的点,只需要一次连接操作即可.

2,孙子为要查找的点,且左右孩子一致.需要首先旋转父亲和祖父节点,然后连接操作.

3,孙子为要查找的点,且左右孩子不一致.需要两次连接操作.

4,合并

§4 伸展树基本操作,实现以及应用

伸展树基本操作

1、插入:

当一个节点插入时,伸展操作将执行。因此,新插入的节点在根上。

2、查找:

如果查找成功(找到),那么由于伸展操作,被查找的节点成为树的新根。

如果查找失败(没有),那么在查找遇到NULL之前的那个节点成为新的根。也就是,如果查找的节点在树中,那么,此时根上的节点就是距离这个节点最近的节点。

3、查找最大最小:

查找之后执行伸展。

4、删除最大最小:

a)删除最小:

首先执行查找最小的操作。

这时,要删除的节点就在根上。根据二叉查找树的特点,根没有左子节点。

使用根的右子结点作为新的根,删除旧的包含最小值的根。

b)删除最大:

首先执行查找最大的操作。

删除根,并把被删除的根的左子结点作为新的根。

5、删除:

将要删除的节点移至根。

删除根,剩下两个子树L(左子树)和R(右子树)。

使用DeleteMax查找L的最大节点,此时,L的根没有右子树。

使R成为L的根的右子树。

伸展树的实现

C代码  
  1. #include<stdio.h>
  2. #include<malloc.h>
  3. #include<stdlib.h>
  4. struct node
  5. {
  6. int data;
  7. struct node *parent;
  8. struct node *left;
  9. struct node *right;
  10. };
  11. int data_print(struct node *x);
  12. struct node *rightrotation(struct node *p,struct node *root);
  13. struct node *leftrotation(struct node *p,struct node *root);
  14. void splay (struct node *x, struct node *root);
  15. struct node *insert(struct node *p,int value);
  16. struct node *inorder(struct node *p);
  17. struct node *delete(struct node *p,int value);
  18. struct node *successor(struct node *x);
  19. struct node *lookup(struct node *p,int value);
  20. void splay (struct node *x, struct node *root)
  21. {
  22. struct node *p,*g;
  23. /*check if node x is the root node*/
  24. if(x==root)
  25. return;
  26. /*Performs Zig step*/
  27. else if(x->parent==root)
  28. {
  29. if(x==x->parent->left)
  30. root=rightrotation(root,root);
  31. else
  32. root=leftrotation(root,root);
  33. }
  34. else
  35. {
  36. p=x->parent; /*now points to parent of x*/
  37. g=p->parent; /*now points to parent of x's parent*/
  38. /*Performs the Zig-zig step when x is left and x's parent is left*/
  39. if(x==p->left&&p==g->left)
  40. {
  41. root=rightrotation(g,root);
  42. root=rightrotation(p,root);
  43. }
  44. /*Performs the Zig-zig step when x is right and x's parent is right*/
  45. else if(x==p->right&&p==g->right)
  46. {
  47. root=leftrotation(g,root);
  48. root=leftrotation(p,root);
  49. }
  50. /*Performs the Zig-zag step when x's is right and x's parent is left*/
  51. else if(x==p->right&&p==g->left)
  52. {
  53. root=leftrotation(p,root);
  54. root=rightrotation(g,root);
  55. }
  56. /*Performs the Zig-zag step when x's is left and x's parent is right*/
  57. else if(x==p->left&&p==g->right)
  58. {
  59. root=rightrotation(p,root);
  60. root=leftrotation(g,root);
  61. }
  62. splay(x, root);
  63. }
  64. }
  65. struct node *rightrotation(struct node *p,struct node *root)
  66. {
  67. struct node *x;
  68. x = p->left;
  69. p->left = x->right;
  70. if (x->right!=NULL) x->right->parent = p;
  71. x->right = p;
  72. if (p->parent!=NULL)
  73. if(p==p->parent->right) p->parent->right=x;
  74. else
  75. p->parent->left=x;
  76. x->parent = p->parent;
  77. p->parent = x;
  78. if (p==root)
  79. return x;
  80. else
  81. return root;
  82. }
  83. struct node *leftrotation(struct node *p,struct node *root)
  84. {
  85. struct node *x;
  86. x = p->right;
  87. p->right = x->left;
  88. if (x->left!=NULL) x->left->parent = p;
  89. x->left = p;
  90. if (p->parent!=NULL)
  91. if (p==p->parent->left) p->parent->left=x;
  92. else
  93. p->parent->right=x;
  94. x->parent = p->parent;
  95. p->parent = x;
  96. if(p==root)
  97. return x;
  98. else
  99. return root;
  100. }
  101. struct node *insert(struct node *p,int value)
  102. {
  103. struct node *temp1,*temp2,*par,*x;
  104. if(p == NULL)
  105. {
  106. p=(struct node *)malloc(sizeof(struct node));
  107. if(p != NULL)
  108. {
  109. p->data = value;
  110. p->parent = NULL;
  111. p->left = NULL;
  112. p->right = NULL;
  113. }
  114. else
  115. {
  116. printf("No memory is allocated\n");
  117. exit(0);
  118. }
  119. return(p);
  120. } //the case 2 says that we must splay newly inserted node to root
  121. else
  122. {
  123. temp2 = p;
  124. while(temp2 != NULL)
  125. {
  126. temp1 = temp2;
  127. if(temp2->data > value)
  128. temp2 = temp2->left;
  129. else if(temp2->data < value)
  130. temp2 = temp2->right;
  131. else
  132. if(temp2->data == value)
  133. return temp2;
  134. }
  135. if(temp1->data > value)
  136. {
  137. par = temp1;//temp1 having the parent address,so that's it
  138. temp1->left = (struct node *)malloc(sizeof(struct node));
  139. temp1= temp1->left;
  140. if(temp1 != NULL)
  141. {
  142. temp1->data = value;
  143. temp1->parent = par;//store the parent address.
  144. temp1->left = NULL;
  145. temp1->right = NULL;
  146. }
  147. else
  148. {
  149. printf("No memory is allocated\n");
  150. exit(0);
  151. }
  152. }
  153. else
  154. {
  155. par = temp1;//temp1 having the parent node address.
  156. temp1->right = (struct node *)malloc(sizeof(struct node));
  157. temp1 = temp1->right;
  158. if(temp1 != NULL)
  159. {
  160. temp1->data = value;
  161. temp1->parent = par;//store the parent address
  162. temp1->left = NULL;
  163. temp1->right = NULL;
  164. }
  165. else
  166. {
  167. printf("No memory is allocated\n");
  168. exit(0);
  169. }
  170. }
  171. }
  172. splay(temp1,p);//temp1 will be new root after splaying
  173. return (temp1);
  174. }
  175. struct node *inorder(struct node *p)
  176. {
  177. if(p != NULL)
  178. {
  179. inorder(p->left);
  180. printf("CURRENT %d\t",p->data);
  181. printf("LEFT %d\t",data_print(p->left));
  182. printf("PARENT %d\t",data_print(p->parent));
  183. printf("RIGHT %d\t\n",data_print(p->right));
  184. inorder(p->right);
  185. }
  186. }
  187. struct node *delete(struct node *p,int value)
  188. {
  189. struct node *x,*y,*p1;
  190. struct node *root;
  191. struct node *s;
  192. root = p;
  193. x = lookup(p,value);
  194. if(x->data == value)
  195. {       //if the deleted element is leaf
  196. if((x->left == NULL) && (x->right == NULL))
  197. {
  198. y = x->parent;
  199. if(x ==(x->parent->right))
  200. y->right = NULL;
  201. else
  202. y->left = NULL;
  203. free(x);
  204. }
  205. //if deleted element having left child only
  206. else if((x->left != NULL) &&(x->right == NULL))
  207. {
  208. if(x == (x->parent->left))
  209. {
  210. y = x->parent;
  211. x->left->parent = y;
  212. y->left = x->left;
  213. free(x);
  214. }
  215. else
  216. {
  217. y = x->parent;
  218. x->left->parent = y;
  219. y->right = x->left;
  220. free(x);
  221. }
  222. }
  223. //if deleted element having right child only
  224. else if((x->left == NULL) && (x->right != NULL))
  225. {
  226. if(x == (x->parent->left))
  227. {
  228. y = x->parent;
  229. x->right->parent = y;
  230. y->left = x->right;
  231. free(x);
  232. }
  233. else
  234. {
  235. y = x->parent;
  236. x->right->parent = y;
  237. y->right = x->right;
  238. free(x);
  239. }
  240. }
  241. //if the deleted element having two children
  242. else if((x->left != NULL) && (x->right != NULL))
  243. {
  244. if(x == (x->parent->left))
  245. {
  246. s = successor(x);
  247. if(s != x->right)
  248. {
  249. y = s->parent;
  250. if(s->right != NULL)
  251. {
  252. s->right->parent = y;
  253. y->left = s->right;
  254. }
  255. else y->left = NULL;
  256. s->parent = x->parent;
  257. x->right->parent = s;
  258. x->left->parent = s;
  259. s->right = x->right;
  260. s->left = x->left;
  261. x->parent->left = s;
  262. }
  263. else
  264. {
  265. y = s;
  266. s->parent = x->parent;
  267. x->left->parent = s;
  268. s->left = x->left;
  269. x->parent->left = s;
  270. }
  271. free(x);
  272. }
  273. else if(x == (x->parent->right))
  274. {
  275. s = successor(x);
  276. if(s != x->right)
  277. {
  278. y = s->parent;
  279. if(s->right != NULL)
  280. {
  281. s->right->parent = y;
  282. y->left = s->right;
  283. }
  284. else y->left = NULL;
  285. s->parent = x->parent;
  286. x->right->parent = s;
  287. x->left->parent = s;
  288. s->right = x->right;
  289. s->left = x->left;
  290. x->parent->right = s;
  291. }
  292. else
  293. {
  294. y = s;
  295. s->parent = x->parent;
  296. x->left->parent = s;
  297. s->left = x->left;
  298. x->parent->right = s;
  299. }
  300. free(x);
  301. }
  302. }
  303. splay(y,root);
  304. }
  305. else
  306. {
  307. splay(x,root);
  308. }
  309. }
  310. struct node *successor(struct node *x)
  311. {
  312. struct node *temp,*temp2;
  313. temp=temp2=x->right;
  314. while(temp != NULL)
  315. {
  316. temp2 = temp;
  317. temp = temp->left;
  318. }
  319. return temp2;
  320. }
  321. //p is a root element of the tree
  322. struct node *lookup(struct node *p,int value)
  323. {
  324. struct node *temp1,*temp2;
  325. if(p != NULL)
  326. {
  327. temp1 = p;
  328. while(temp1 != NULL)
  329. {
  330. temp2 = temp1;
  331. if(temp1->data > value)
  332. temp1 = temp1->left;
  333. else if(temp1->data < value)
  334. temp1 = temp1->right;
  335. else
  336. return temp1;
  337. }
  338. return temp2;
  339. }
  340. else
  341. {
  342. printf("NO element in the tree\n");
  343. exit(0);
  344. }
  345. }
  346. struct node *search(struct node *p,int value)
  347. {
  348. struct node *x,*root;
  349. root = p;
  350. x = lookup(p,value);
  351. if(x->data == value)
  352. {
  353. printf("Inside search if\n");
  354. splay(x,root);
  355. }
  356. else
  357. {
  358. printf("Inside search else\n");
  359. splay(x,root);
  360. }
  361. }
  362. main()
  363. {
  364. struct node *root;//the root element
  365. struct node *x;//x is which element will come to root.
  366. int i;
  367. root = NULL;
  368. int choice = 0;
  369. int ele;
  370. while(1)
  371. {
  372. printf("\n\n 1.Insert");
  373. printf("\n\n 2.Delete");
  374. printf("\n\n 3.Search");
  375. printf("\n\n 4.Display\n");
  376. printf("\n\n Enter your choice:");
  377. scanf("%d",&choice);
  378. if(choice==5)
  379. exit(0);
  380. switch(choice)
  381. {
  382. case 1:
  383. printf("\n\n Enter the element to be inserted:");
  384. scanf("%d",&ele);
  385. x = insert(root,ele);
  386. if(root != NULL)
  387. {
  388. splay(x,root);
  389. }
  390. root = x;
  391. break;
  392. case 2:
  393. if(root == NULL)
  394. {
  395. printf("\n Empty tree...");
  396. continue;
  397. }
  398. printf("\n\n Enter the element to be delete:");
  399. scanf("%d",&ele);
  400. root = delete(root,ele);
  401. break;
  402. case 3:
  403. printf("Enter the element to be search\n");
  404. scanf("%d",&ele);
  405. x = lookup(root,ele);
  406. splay(x,root);
  407. root = x;
  408. break;
  409. case 4:
  410. printf("The elements are\n");
  411. inorder(root);
  412. break;
  413. default:
  414. printf("Wrong choice\n");
  415. break;
  416. }
  417. }
  418. }
  419. int data_print(struct node *x)
  420. {
  421. if ( x==NULL )
  422. return 0;
  423. else
  424. return x->data;
  425. }
  426. /*some suggestion this code is not fully functional for example
  427. if you have inserted some elements then try to delete root then it may not work
  428. because we are calling right and left child of a null value(parent of root)
  429. which is not allowed and will give segmentation fault
  430. Also for inserting second element because of splaying twice(once in insert and one in main)
  431. will give error So I have made those changes but mainly in my cpp( c plus plus file) file,
  432. but I guess wiki will itself look into this and made  these changes */

伸展树应用

(1)     数列维护问题

题目:维护一个数列,支持以下几种操作:

1. 插入:在当前数列第posi 个数字后面插入tot 个数字;若在数列首位插入,则posi 为0。

2. 删除:从当前数列第posi 个数字开始连续删除tot 个数字。

3. 修改:从当前数列第posi 个数字开始连续tot 个数字统一修改为c 。

4. 翻转:取出从当前数列第posi 个数字开始的tot 个数字,翻转后放入原来的位置。

5. 求和:计算从当前数列第posi 个数字开始连续tot 个数字的和并输出。

6. 求和最大子序列:求出当前数列中和最大的一段子序列,并输出最大和。

(2)     轻量级web服务器lighttpd中用到数据结构splay tree.

§5 小结

这篇博文非常详尽了讲解了伸展树的定义,伸展过程,基本操作以及实现等内容,学完基本可以掌握的伸展树的特点。如果你有任何建议或者批评和补充,请留言指出,不胜感激,更多参考请移步互联网。

参考:

①kernel@hcy: http://www.cnblogs.com/kernel_hcy/archive/2010/03/17/1688360.html

②董的博客: http://dongxicheng.org/structure/splay-tree/

③kmplayer: http://kmplayer.iteye.com/blog/566937

④维基百科: http://en.wikipedia.org/wiki/Splay_tree#Analysis

伸展树(Splay Tree)尽收眼底相关推荐

  1. 伸展树(Splay tree)图解与实现

    伸展树(Splay tree)图解与实现 伸展树(Splay tree)图解与实现_小张的专栏-CSDN博客_splay树 Splay树详解 Splay树详解 - 秦淮岸灯火阑珊 - 博客园 平衡树 ...

  2. splay tree java_伸展树(splay tree)自顶向下的算法

    伸展树(splay tree)是一种能自我调整的二叉搜索树(BST).虽然某一次的访问操作所花费的时间比较长,但是平摊(amortized) 之后的访问操作(例如旋转)时间能达到O(logn)的复杂度 ...

  3. 伸展树(Splay tree)浅谈

    树看的越来越多,越来越神奇. 看伸展树这种神级数据结构之前,建议大家首先彻底明白二叉搜索树,这是万树的基础. 然后可以去看下treap,最好再去看下红黑树.如果有线段树的基础那更好了,我们会发现线段树 ...

  4. 伸展树 Splay 模板

    学习Splay的时候参考了很多不同的资料,然而参考资料太杂的后果就是模板调出来一直都有问题,尤其是最后发现网上找的各种资料均有不同程度的错误. 好在啃了几天之后终于算是啃下来了. Splay也算是平衡 ...

  5. [学习笔记] 伸展树splay详解+全套模板+例题[Luogu P3369 【模板】普通平衡树]

    文章目录 引入概念 全套模板 变量声明 update ==rotate旋转== splay操作 insert插入 delete删除 查找x的位置 查找第k大 前驱/后继 极小值-inf和极大值inf的 ...

  6. [Splay伸展树]splay树入门级教程

    首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...

  7. sgu 187 Twist and whirl - want to cheat 伸展树(splay)

    裸的区间翻转..直接写个splay就行... #include <iostream> #include <cstdio> #include <algorithm> ...

  8. AVL树、splay树(伸展树)和红黑树比较

    AVL树.splay树(伸展树)和红黑树比较 一.AVL树: 优点:查找.插入和删除,最坏复杂度均为O(logN).实现操作简单 如过是随机插入或者删除,其理论上可以得到O(logN)的复杂度,但是实 ...

  9. PHP算法 《树形结构》 之 伸展树(1) - 基本概念

    伸展树的介绍 1.出处:http://dongxicheng.org/structure/splay-tree/ A. 概述 二叉查找树(Binary Search Tree,也叫二叉排序树,即Bin ...

  10. 【题集】AVL树、伸展树、红黑树、二叉查找树、替罪羊树的时间复杂度

    目录 1. AVL树 2.伸展树 3.红黑树 4.二叉查找树 5.替罪羊树 1. AVL树 AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平 ...

最新文章

  1. mysql练习题——数据分析/大数据岗面试
  2. python 相对路径
  3. python 计算 IOU
  4. 推荐系统实践-第一章
  5. sublime php语法检查
  6. 前端学习(1452):表格案例--效果演示
  7. 2020年日历_2020年《故宫日历》发布:浓缩紫禁城600年沧桑
  8. Qt工作笔记-QSort的基本使用
  9. Python零基础学习代码实践 —— 99乘法表
  10. Kmalloc申请内存源码分析
  11. 【C语言】指针的算术运算
  12. FastDFS 原理 以及 简单使用
  13. 申请与认证IB课程全流程
  14. 强大便携的多标签文件管理器 XYplorer Pro 21.60 中文版
  15. element el-table 计算指定列
  16. 浅谈USB设备的VID和PID
  17. 雷军亲自捧场,双液冷游戏手机演绎“暴力美学”
  18. MySQL培训-梅科尔
  19. 32位超前进位加法器
  20. Python 的dict几种遍历方式

热门文章

  1. Android的手机ip代码设置------有图有真相
  2. 动态设置input设置只读属性
  3. 浅谈Slurm作业调度系统
  4. 安全防御设备都应该购买哪些
  5. 百度OCR文字识别、证卡识别、票据识别原生插件
  6. python打开图片的方式
  7. 锦江WeHotel正式启用全新“锦江会员”品牌标识;菲律宾长滩岛邀中国游客玩转海陆空 | 全球旅报...
  8. 如何在不重启电脑的情况下修改主机名
  9. LDC-0 使命、价值观、愿景
  10. 头歌(educoder)第 3 章 Java入门之数组 Java入门 - 数组进阶