④伸展树基础
定义与初始化:
1 struct SplayNode{ 2 int Element; 3 SplayTree left; 4 SplayTree right; 5 };
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 }
在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 }
插入:进行一次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 }
删除:
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 }
全部代码:
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 }
疑问:只用到O(1)空间,摊还时间为O(logN)

浙公网安备 33010602011771号