④伸展树基础

定义与初始化:

1 struct SplayNode{
2     int Element;
3     SplayTree left;
4     SplayTree right;
5 };
View Code
1 static SPosition NullNode = NULL; //伸展树中Null都指向NullNode
2 SplayTree Initial(void){
3     if (NullNode == NULL){
4         NullNode = (SPosition)malloc(sizeof(struct SplayNode));
5         NullNode->left = NullNode->right = NullNode;
6     }
7     return NullNode;
8 }
View Code

 

在X插入时,展开使得X成为新的根。

查找X时,也要对X或者是因为没找到而路径上最后一个节点进行展开。

初步想法是沿着根往下进行一次遍历,以及而后从底向上的一次遍历。这样太麻烦了啊。

所以本文介绍自顶向下的伸展树:在初始访问路径上就进行一次次的旋转。

总结一下就是不管是插入还是查找,因为我都要先找到一个位置,在找这个位置的过程中,我们一步步进行展开。

我们设X为中间树的根,L存放树T中小于X中的节点,但不存放X的子树的节点,R同理。初始化时X为T的根,L和R为空树

我们设展开函数为Splay(int Item,Position X),也就是说如果Item在X中,那么Item要变成新的根;不在的话,路径上最后一个点要变成新的根。

分为以下三种情况进行旋转(其实一共六种,其余三种对称即可)

①: 单旋转->

   

zig-zig:先对x-y进行AVL里的单旋转,再对y-z进行一次①:

所以就是说进行一次单旋转,就能和①结合了

 

③:zig-zag:

这里我们用简易版zig-zag,这样就能和①相结合了

然后看如何恢复为一棵树

----》》》

 

根据这个函数,我总结了一下应该是这么个思路:

首先创建一个NullNode,它的值为item;具体为什么下面再解释

 

①如果Item<X:

        ①如果Item比X的左节点小,那就执行一次单旋转,X=X->left(解释:如果X左节点不存在,那么Item就和X左节点一样大了)

        ②之后如果X的左节点不存在,那么就结束了。

        ③存在的话,就可以执行三种旋转中的第一种了。 

②如果Item>X:

        对称一下

③如果Item==X;

       就把左中右三个树合并起来

 

 1 SplayTree Splay(int Item, SplayTree X){
 2     SplayTree Header = (SplayTree)malloc(sizeof(struct SplayNode));//这个Header的左节点是R,右节点是L,要注意;
 3     Header->left = Header->right = NullNode;
 4     SPosition LeftTreeMax, RightTreeMin;//L中的最大和R中的最小;
 5     LeftTreeMax = RightTreeMin = Header;
 6     NullNode->Element = Item;//这句原因见红字解释
 7     while (Item != X->Element){
 8         if (Item < X->Element){
 9             if (Item < X->left->Element){
10                 X=SingleRotateLeft(X);
11             }
12             if (X->left == NullNode){
13                 break;
14             }
15             RightTreeMin->left = X;
16             RightTreeMin = X;
17             X = X->left;
18         }
19         else {
20             if (Item > X->right->Element){
21                 X=SingleRotateRight(X);
22             }
23             if (X->right == NullNode){
24                 break;
25             }
26             LeftTreeMax->right = X;
27             LeftTreeMax = X;
28             X = X->right;
29         }
30     }
31     LeftTreeMax->right = X->left;
32     RightTreeMin->left = X->right;
33     X->left = Header->right;//这里要注意,Header的左节点是R,右节点是L;
34     X->right = Header->left;
35     return X;
36 }
View Code

 

插入:进行一次Splay(Item,X),在根据Item<>=X,进行插入更改即可。

 

 1 playTree Insert(int X, SplayTree T){   //NerNode是一棵插入后新的树
 2     SplayTree NewNode=(SplayTree)malloc(sizeof(struct SplayNode));
 3     NewNode->Element = X;
 4     if (T == NullNode){
 5         NewNode->left = NewNode->right = NullNode; 
 6         T = NewNode;
 7     }
 8     else{
 9         T=Splay(X, T);
10         if (X < T->Element){
11             NewNode->left = T->left;
12             NewNode->right = T;
13             T->left = NullNode;
14             T = NewNode;
15 
16         }
17         else if (X > T->Element){
18             NewNode->left = T;
19             NewNode->right = T->right;
20             T->right = NullNode;
21             T = NewNode;
22         }
23 
24     }
25     return T;
26 }
View Code

删除:

 1 SplayTree Delete(int X, SplayTree T){
 2     SplayTree NewNode = (SplayTree)malloc(sizeof(struct SplayNode));
 3     if (T != NullNode){
 4         T = Splay(X, T);
 5         if (X == T->Element){
 6             if (T->left == NullNode){
 7                 T = T->right;
 8             }
 9             else{
10                 NewNode = T->left;
11                 NewNode = Splay(X, NewNode);
12                 NewNode->right = T->right;
13             }
14             free(T);//别忘
15             T = NewNode;//别与上一句弄反
16         }
17     }
18     return T;
19 }
View Code

 

 全部代码:

  1 #include <stdlib.h>
  2 typedef struct SplayNode *SplayTree;
  3 typedef struct SplayNode *SPosition;
  4 
  5 
  6 struct SplayNode{
  7     int Element;
  8     SplayTree left;
  9     SplayTree right;
 10 };
 11 SplayTree SingleRotateLeft(SplayTree k2){    //单左旋转
 12     SplayTree k1 = k2->left;
 13     k2->left = k1->right;
 14     k1->right = k2;
 15     return k1;   //返回现在的顶点
 16 
 17 }
 18 SplayTree SingleRotateRight(SplayTree k2){    //单右旋转
 19     SplayTree k1 = k2->right;
 20     k2->right = k1->left;
 21     k1->left = k2;
 22     return k1;   //返回现在的顶点
 23 
 24 }
 25 static SPosition NullNode = NULL;
 26 SplayTree Initial(void){
 27     if (NullNode == NULL){
 28         NullNode = (SPosition)malloc(sizeof(struct SplayNode));
 29         NullNode->left = NullNode->right = NullNode;
 30     }
 31     return NullNode;
 32 }
 33 SplayTree Splay(int Item, SplayTree X){
 34     SplayTree Header = (SplayTree)malloc(sizeof(struct SplayNode));//这个Header的左节点是R,右节点是L,要注意;
 35     Header->left = Header->right = NullNode;
 36     SPosition LeftTreeMax, RightTreeMin;//L中的最大和R中的最小;
 37     LeftTreeMax = RightTreeMin = Header;
 38     NullNode->Element = Item;//这句原因见红字解释
 39     while (Item != X->Element){
 40         if (Item < X->Element){
 41             if (Item < X->left->Element){
 42                 X=SingleRotateLeft(X);
 43             }
 44             if (X->left == NullNode){
 45                 break;
 46             }
 47             RightTreeMin->left = X;
 48             RightTreeMin = X;
 49             X = X->left;
 50         }
 51         else {
 52             if (Item > X->right->Element){
 53                 X=SingleRotateRight(X);
 54             }
 55             if (X->right == NullNode){
 56                 break;
 57             }
 58             LeftTreeMax->right = X;
 59             LeftTreeMax = X;
 60             X = X->right;
 61         }
 62     }
 63     LeftTreeMax->right = X->left;
 64     RightTreeMin->left = X->right;
 65     X->left = Header->right;//这里要注意,Header的左节点是R,右节点是L;
 66     X->right = Header->left;
 67     return X;
 68 }
 69 
 70 SplayTree Insert(int X, SplayTree T){   //NerNode是一棵插入后新的树
 71     SplayTree NewNode=(SplayTree)malloc(sizeof(struct SplayNode));
 72     NewNode->Element = X;
 73     if (T == NullNode){
 74         NewNode->left = NewNode->right = NullNode; 
 75         T = NewNode;
 76     }
 77     else{
 78         T=Splay(X, T);
 79         if (X < T->Element){
 80             NewNode->left = T->left;
 81             NewNode->right = T;
 82             T->left = NullNode;
 83             T = NewNode;
 84 
 85         }
 86         else if (X > T->Element){
 87             NewNode->left = T;
 88             NewNode->right = T->right;
 89             T->right = NullNode;
 90             T = NewNode;
 91         }
 92 
 93     }
 94     return T;
 95 }
 96 
 97 SplayTree Delete(int X, SplayTree T){
 98     SplayTree NewNode = (SplayTree)malloc(sizeof(struct SplayNode));
 99     if (T != NullNode){
100         T = Splay(X, T);
101         if (X == T->Element){
102             if (T->left == NullNode){
103                 T = T->right;
104             }
105             else{
106                 NewNode = T->left;
107                 NewNode = Splay(X, NewNode);
108                 NewNode->right = T->right;
109             }
110             free(T);//别忘
111             T = NewNode;
112         }
113     }
114     return T;
115 }
View Code

 

 

疑问:只用到O(1)空间,摊还时间为O(logN)

posted @ 2015-02-17 19:32  stezqy  阅读(168)  评论(0)    收藏  举报