数据结构-伸展树

声明:本文是对某高中生的竞赛论文学习的文章

介绍:

  二叉查找树能够支持多种动态集合操作。对于一个含有n个结点的完全二叉树,这些操作的最还情况运行时间是O(lgn),但如果树是含有n个结点的线性链,则这些操作的最坏情况运行时间为O(n)。而像红黑树、AVL树这种二叉查找树的变形在最坏情况下,仍能保持较好性能。

  本文将要介绍的伸展树也是二叉查找树的变形,它对空间要求及编程难度的要求相对不高。

伸展树:

  伸展树与二叉查找树一样,具有有序性。即伸展树的每一个结点x满足:该结点的左子树中的每个元素都小于x,而其右子树的每一个元素都大于x。与二叉查找树不同的是,伸展树可以自我调整,也就是伸展操作(Splay)。

  伸展操作Splay(x,S)

    伸展操作是在保持伸展树有序的前提下,通过一系列旋转将伸展树T中的元素x调整至树的根部。在调整的过程中,分以下三种情况处理:

      1、结点x的父节点y是根节点。

        这时,如果x是y的左孩子,我们进行一次Zig(右旋)操作;

           如果x是y的右孩子,我们进行一次Zag(左旋)操作;

          

      2、结点x的父节点y不是根节点,y的父节点为z。

        且x与y同时是各自父节点的左孩子,这时我们进行Zig-Zig操作;

        或者是同时是各自父节点的右孩子,这时我们进行一次Zag-Zag操作。

          

      3、结点x的父节点y不是根节点,y的父节点为z。

        且x与y分别是其父节点的左孩子和右孩子,这时我们进行一次Zig-Zag操作。

        或者是x与y分别是其父节点的右孩子和左孩子,这时我们进行一次Zag-Zig操作。

          

    如下图所示,执行Splay(1,T),将元素1调整的树根的位置,执行Splay(2)将元素2调整到树根的位置。从直观上看,树比原来“平衡”多了,而伸展操作的过    程并不复杂,只需要左旋和右旋。

          

  基本操作:

      利用Splay可以在伸展树上T上作如下操作,  

      查找:判断元素x是否在伸展树T表示的有序集中;

         跟二叉查找树的查找操作一样,在伸展树中查找x,如果x在伸展树中,则再执行Splay(x,T)调整伸展树。

      插入:将元素x插入到伸展树T表示的有序集中;

         跟二叉查找树的插入操作一样,将元素x插入到伸展树的相应位置,在执行Splay(x,T)调整伸展树。

      删除:将元素x从伸展树T表示的有序集中删除;

          首先,查找的元素x所在的位置,如果x没有孩子或者只有一个孩子,直接删除掉x,再对x的父节点执行Splay,将x的父节点调整到根位置。否          则,查找x的后继y,用y代替x的位置,然后执行Splay(y,T),将y调整到根节点位子。

      合并:将两个伸展树T1、T2合并成一个伸展树。其中S1中的所有元素都小于T2中的元素。

          首先,找到T1中最大的元素x,在执行Splay(x,T1)将x调整到T1的根位置,然后将T2作为x的右子树就得到新的伸展树T。

            

      划分:以元素x为边界,将伸展树T划分成两个伸展树T1和T2,其中,T1中的元素都小于x,T2中的元素都大于x。

         首先,执行查找操作,将元素x调整为根位置,x的左子树为T1,右子树为T2。

          

     除了上述操作外,伸展树还可以有其他的操作。

时间复杂度:

      所有的操作其平摊复杂度为O(lgn)。

程序实现:

  1 package datastructure;  4 import java.util.List;
  5 import java.util.ArrayList;
  6
 10 public class SplayTree {
 11     class TreeNode{
 12         private int key;
 13         private String data;
 14         private TreeNode left;
 15         private TreeNode right;
 16         private TreeNode parent;
 17
 18         public TreeNode(int key,String data,TreeNode left,TreeNode right,TreeNode parent) {
 19             this.key = key;
 20             this.data = data;
 21             this.left = left;
 22             this.right = right;
 23             this.parent = parent;
 24         }
 25         public int getKey() {
 26             return key;
 27         }
 28         public String toString(){
 29             String leftKey = (left == null ? " " : String.valueOf(left.key));
 30             String rightKey = (right == null ? " " : String.valueOf(right.key));
 31             return "(" + leftKey +"," +  key + "," + rightKey + ")";
 32         }
 33     }
 34     private TreeNode root = null;
 35     public boolean IsEmpty()
 36     {
 37          if(root == null)
 38             {
 39                 return true;
 40             }
 41             else
 42             {
 43                 return false;
 44             }
 45     }
 46     public TreeNode Insert(int key) {
 47         TreeNode parentNode = null;
 48         TreeNode newNode = new TreeNode(key, "v", null, null, null);
 49         TreeNode pNode = root;
 50         if(pNode == null)
 51         {
 52             root = newNode;
 53             return root ;
 54         }
 55         while(pNode != null)
 56         {
 57             parentNode = pNode;
 58             if(key < pNode.key)
 59             {
 60                 pNode = pNode.left;
 61             }
 62             else if(key > pNode.key)
 63             {
 64                 pNode = pNode.right;
 65             }
 66             else
 67             {
 68                 return pNode;//树中已存在与新结点的关键字相同的结点
 69             }
 70         }
 71         newNode.parent = parentNode;
 72         if(newNode.key < parentNode.key)
 73         {
 74             parentNode.left = newNode;
 75             return parentNode.left;
 76         }
 77         else
 78         {
 79               parentNode.right = newNode;
 80               return parentNode.right;
 81         }
 82
 83
 84     }
 85     private List<TreeNode> nodeList = new ArrayList<TreeNode>();
 86
 87     public List<TreeNode> getNodeList() {
 88         return nodeList;
 89     }
 90
 91     //获取中序列表
 92     public List<TreeNode> Inorder_SplayTree_WalkList()
 93     {
 94         if(nodeList != null)
 95         {
 96             nodeList.clear();
 97         }
 98         Inorder_SplayTree_Walk(root);
 99         return nodeList;
100     }
101     //中序遍历树
102     private void Inorder_SplayTree_Walk(TreeNode root)
103     {
104         if(root != null)
105         {
106             Inorder_SplayTree_Walk(root.left);
107             nodeList.add(root);
108             Inorder_SplayTree_Walk(root.right);
109         }
110     }
111     //给定关键字key,查找到该结点
112     private TreeNode Search(int key)
113     {
114         TreeNode pNode = root;
115         while(pNode != null && pNode.key != key)
116         {
117             if(key<pNode.key)
118             {
119                 pNode = pNode.left;
120             }
121             else {
122                 pNode = pNode.right;
123             }
124         }
125         return pNode;
126     }
127     //左旋转:x的右孩子y不空,以x与y之间的链为之架
128     private void leftRotate(TreeNode pNode)
129     {
130         TreeNode xNode = pNode;
131         TreeNode yNode = xNode.right;
132         xNode.right = yNode.left;
133         if(yNode.left != null)
134         {
135             yNode.left.parent = xNode;
136         }
137         yNode.parent = xNode.parent;
138         if(xNode.parent == null)
139         {
140             root = yNode;
141         }
142         else if(xNode.parent.left == xNode)
143         {
144             xNode.parent.left = yNode;
145         }else {
146             xNode.parent.right = yNode;
147         }
148         yNode.left = xNode;
149         xNode.parent = yNode;
150     }
151     //右旋转:x的左孩子y不空,以x与y之间的链为支架右旋转
152     private void rightRotate(TreeNode pNode)
153     {
154         TreeNode xNode = pNode;
155         TreeNode yNode = xNode.left;
156         xNode.left = yNode.right;
157         if(yNode.right != null)
158         {
159             yNode.right.parent = xNode;
160         }
161         yNode.parent = xNode.parent;
162         if(xNode.parent == null)
163         {
164             root = yNode;
165         }else if(xNode.parent.left == xNode)
166         {
167             xNode.parent.left = yNode;
168         }
169         else {
170             xNode.parent.right = yNode;
171         }
172         yNode.right = xNode;
173         xNode.parent = yNode;
174     }
175
176     public void Splay(int key)
177     {
178         TreeNode xNode = Search(key);
179         if(xNode == null)
180         {
181             return;
182         }
183         SplayT(xNode,this.root);
184     }
185
186     //伸展树的Splay操作展操作是在保持伸展树有序的前提下,
187     //通过一系列旋转将伸展树T中的元素x调整至树的根部。
188     //在调整的过程中,分以下三种情况处理:
189     private void SplayT(TreeNode xNode,TreeNode Troot)
190     {
191
192         if(Troot == null || xNode == Troot)
193         {
194             return ;
195         }
196         while(xNode.parent != null) //x是否到达根位置
197         {
198             // 1、结点x的父节点y是根节点。
199             if(xNode.parent == Troot)
200             {
201                 if (xNode.parent.left == xNode)
202                 {
203                     //如果x是y的左孩子,我们进行一次Zig(右旋)操作;
204                     rightRotate(xNode.parent);
205                 }
206                 else
207                 {
208                     //如果x是y的右孩子,我们进行一次Zag(左旋)操作;
209                     leftRotate(xNode.parent);
210                 }
211             }
212             else
213             {
214                 //2、结点x的父节点y不是根节点,y的父节点为z。
215                 TreeNode yNode = xNode.parent;
216                 if(yNode != null)
217                 {
218                     TreeNode zNode = yNode.parent;
219                     if(xNode == yNode.left && yNode ==zNode.left)
220                     {
221                         //x与y同时是其父节点的左孩子
222                         rightRotate(zNode);
223                         rightRotate(yNode);
224                     }
225                     else if(xNode == yNode.right && yNode == zNode.right)
226                     {
227                         //x与y同时是其父节点的右孩子
228                         leftRotate(zNode);
229                         leftRotate(yNode);
230                     }else if (xNode==yNode.left && yNode == zNode.right)
231                     {
232                         //x是其父节点的左孩子,y是父节点的右孩子
233                         rightRotate(xNode.parent);
234                         leftRotate(xNode.parent);
235
236                     }else
237                     {
238                         //x是其父节点的右孩子,y是父节点的左孩子
239                         leftRotate(xNode.parent);
240                         rightRotate(xNode.parent);
241                     }
242                 }
243             }
244
245         }
246     }
247     //伸展树的查找操作
248     public void SplayTree_Search(int x,TreeNode Troot)
249     {
250         TreeNode xNode = Search(x);
251         if(xNode == null)
252         {
253             return;
254         }
255         SplayT(xNode, Troot);
256     }
257     //伸展树的插入操作
258     public void SplayTree_Insert(int x,TreeNode Troot)
259     {
260         TreeNode xNode = Insert(x);
261         if(xNode == null)
262         {
263             return;
264         }
265         SplayT(xNode, Troot);
266     }
267     //伸展树的删除操作
268     public void SplayTree_Delete(int x,TreeNode Troot) throws Exception
269     {
270         TreeNode xNode = Search(x);
271         if(xNode == null)
272         {
273             throw new Exception("树中不存在要删除的元素x");
274         }
275         SplayTree_Remove(xNode,Troot);
276     }
277     private void SplayTree_Remove(TreeNode xNode,TreeNode Troot) throws Exception
278     {
279
280         if(xNode == null)
281         {
282             return;
283         }
284         TreeNode parentNode = xNode.parent;
285         if(xNode.left == null && xNode.right == null)
286         {
287             if(parentNode.left == xNode)
288             {
289                 parentNode.left = null;
290                 SplayT(parentNode, Troot);
291             }
292             if(parentNode.right == xNode)
293             {
294                 parentNode.right = null;
295                 SplayT(parentNode,Troot);
296             }
297         }
298         if(xNode.left != null && xNode.right == null)
299         {
300             if(parentNode.left == xNode)
301             {
302                 xNode.left.parent = parentNode;
303                 parentNode.left = xNode.left;
304                 SplayT(parentNode, Troot);
305             }
306             if(parentNode.right == xNode)
307             {
308                 xNode.left.parent = parentNode;
309                 parentNode.right = xNode.left;
310                 SplayT(parentNode,Troot);
311             }
312         }
313         if(xNode.left == null && xNode.right != null)
314         {
315             if(parentNode.left == xNode)
316             {
317                 xNode.right.parent = parentNode;
318                 parentNode.left = xNode.right;
319                 SplayT(parentNode, Troot);
320             }
321             if(parentNode.right == xNode)
322             {
323                 xNode.right.parent = parentNode;
324                 parentNode.right = xNode.right;
325                 SplayT(parentNode, Troot);
326             }
327         }
328         //x的左右儿子都不为空,就删除后继,让后继的内容,代替当前内容
329         TreeNode successorNode = SplayTree_Successor(xNode);
330         xNode.key = successorNode.key;
331         xNode.data = successorNode.data;
332         SplayTree_Remove(successorNode,Troot);
333         SplayT(successorNode, Troot);
334     }
335     public TreeNode SplayTree_Successor(TreeNode xNode) throws Exception
336     {
337               if(xNode == null)
338               {
339                   return null;
340               }
341               TreeNode pNode = xNode;
342               //若右子树不空,则为右子树中最小的关键字
343               if(pNode.right != null)
344               {
345                   return Tree_Minimum(pNode.right);
346               }
347               TreeNode parentNode = xNode.parent;
348               //若右子树为空,且x有一个后继y.则y是x的最低祖先结点,且y的左儿子也是x的祖先
349               while(parentNode != null && pNode == parentNode.right)
350               {
351                   pNode = parentNode;
352                   parentNode = pNode.parent;
353                }
354               return parentNode;
355     }
356     public TreeNode Tree_Maxmum(TreeNode Troot) throws Exception
357     {
358         if(Troot == null)
359         {
360             throw new Exception("树为空");
361         }
362         TreeNode xNode = Troot;
363         while(xNode.right != null)
364         {
365             xNode = xNode.right;
366         }
367         return xNode;
368     }
369     public TreeNode Tree_Minimum(TreeNode Troot) throws Exception
370     {
371         if(Troot == null)
372         {
373             throw new Exception("树为空");
374         }
375         TreeNode xNode = Troot;
376         while(xNode.left != null)
377         {
378             xNode = xNode.left;
379         }
380         return xNode;
381     }
382     public void SplayTree_Minimum(TreeNode Troot) throws Exception
383     {
384         TreeNode xNode = Tree_Minimum(Troot);
385         if(xNode == null)
386         {
387             return;
388         }
389         SplayT(xNode,Troot);
390     }
391     public TreeNode SplayTree_Join(TreeNode Troot1,TreeNode Troot2) throws Exception
392     {
393         TreeNode xNode = Tree_Maxmum(Troot1);
394         if(xNode == null)
395         {
396             return null;
397         }
398         SplayT(xNode, Troot1);
399         xNode.right = Troot2;
400         Troot2.parent = xNode;
401         return xNode;
402
403     }
404
405 }

  

数据结构-伸展树,布布扣,bubuko.com

时间: 2024-07-30 04:39:31

数据结构-伸展树的相关文章

数据结构之伸展树

1. 概述 二叉查找树(Binary Search Tree,也叫二叉排序树,即Binary Sort Tree)能够支持多种动态集合操作,它可以用来表示有序集合.建立索引等,因而在实际应用中,二叉排序树是一种非常重要的数据结构. 从算法复杂度角度考虑,我们知道,作用于二叉查找树上的基本操作(如查找,插入等)的时间复杂度与树的高度成正比.对一个含n个节点的完全二叉树,这些操作的最坏情况运行时间为O(log n).但如果因为频繁的删除和插入操作,导致树退化成一个n个节点的线性链(此时即为一个单链表

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

[0]README 1) 本文部分内容转自 数据结构与算法分析,旨在理解 高级数据结构实现——自顶向下伸展树 的基础知识: 2) 源代码部分思想借鉴了数据结构与算法分析,有一点干货原创代码,for original source code, please visithttps://github.com/pacosonTang/dataStructure-algorithmAnalysis/tree/master/chapter12/p345_topdown_splay_tree 3) you c

poj_3468 伸展树

题目大意 一个数列,每次操作可以是将某区间数字都加上一个相同的整数,也可以是询问一个区间中所有数字的和.(这里区间指的是数列中连续的若干个数)对每次询问给出结果. 思路 1. 伸展树的一般规律 对于区间的查找更新操作,可以考虑使用伸展树.线段树等数据结构.这里使用伸展树来解决.     伸展树对数组进行维护的核心思想是,将需要维护的一组数单独提取出来,形成一棵子树(一般为整棵树的根节点的右子节点的左孩子节点 为根),然后再这个子树上进行操作.此时进行某些操作(如 ADD, SUM 等),只需要在

HYSBZ 1503 郁闷的出纳员 伸展树

题目链接: https://vjudge.net/problem/26193/origin 题目描述: 中文题面....... 解题思路: 伸展树, 需要伸展树的模板, 突然发现自己昨天看到的模板不是太好, 现在又新找了一个,  很简练, 自己将模板的实现从头到尾看了一遍, 觉得数组实现的实在是非常的巧妙, 然后自己照着敲了一遍, 边敲边看, 崩掉了.....肯定是哪里手残了, 没有必要浪费时间去改了, 有那时间不如看点别的 代码: #include <iostream> #include &

[转载]伸展树(一)之 图文解析 和 C语言的实现

概要 本章介绍伸展树.它和"二叉查找树"和"AVL树"一样,都是特殊的二叉树.在了解了"二叉查找树"和"AVL树"之后,学习伸展树是一件相当容易的事情.和以往一样,本文会先对伸展树的理论知识进行简单介绍,然后给出C语言的实现.后序再分别给出C++和Java版本的实现:这3种实现方式的原理都一样,选择其中之一进行了解即可.若文章有错误或不足的地方,希望您能不吝指出! 目录 1. 伸展树的介绍 2. 伸展树的C实现 3. 伸展树的

poj_3580 伸展树

自己伸展树做的第一个题 poj 3580 supermemo. 题目大意 对一个数组进行维护,包含如下几个操作: ADD x, y, d 在 A[x]--A[y] 中的每个数都增加d REVERSE x, y 将 A[x]--A[y] 中的数进行反转,变为 A[y],A[y-1]....A[x+1],A[x] REVOLVE x, y, T 将 A[x]--A[y]中的数连续右移T次 INSERT x, P 在A后添加数P DELETE x 删除A[x] MIN x, y 查询A[x]--A[y

查找——清晰图解伸展树SplayTree

伸展树 伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它由Daniel Sleator和Robert Tarjan创造,后者对其进行了改进. 假设想要对一个二叉查找树执行一系列的查找操作.为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置.于是想到设计一个简单方法,在每次查找之后对树进行重构,把被查找的条目搬移到离树根近一些的地方.splaytree应运而生.splaytree是一种自调整形式的二叉查找树,它会沿着从某个节点到树根之间的路径,通过一系列的旋转

Splay Tree(伸展树)

参考:<数据结构(C++语言版)>邓俊辉著 (好书 一. 伸展树(由 D. D. Sleator 和 R. E. Tarjan 于 1985 年发明)也是平衡二叉搜索树的一种形式.相对于 AVL 树,伸展树的实现更为简洁 伸展树无需时刻都严格地保持全树的平衡,但却能够在任何足够长的真实操作序列中,保持分摊意义上的高效率 伸展树也不需要对基本的二叉树节点结构做任何附加的要求或改动,更不需要记录平衡因子或高度之类的额外信息,故适用范围更广 二.局部性 信息处理的典型模式是,将所有的数据项视作一个集

HDU 1890 Robotic Sort 伸展树的区间反转与延迟标记

延迟标记像极了线段树,不再多说. 区间反转在树伸展到位之后,也变成了简单的递归交换左右儿子. 愈发感觉到伸展树简直太漂亮了,伸展操作更是诱惑到不行 ,总之数据结构太有魅力了. 比较简单,就直接上模板了. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #in