Splay Tree 是二叉查找树的一种,它与平衡二叉树、红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋转到树根的位置,这样就使得Splay Tree天生有着一种类似缓存的能力,因为每次被查找到的节点都会被搬到树根的位置,所以当80%的情况下我们需要查找的元素都是某个固定的节点,或者是 一部分特定的节点时,那么在很多时候,查找的效率会是O(1)的效率!当然如果查找的节点是很均匀地分布在不同的地方时,Splay Tree的性能就会变得很差了,但Splay Tree的期望的时间复杂度还是O(nlogn)的。

      为了使访问的节点调到树根,必定要有像维护平衡二叉树那样的旋转操作,来维持二叉树节点间的偏序关系;与平衡二叉树类似,Splay有2种旋转操作(左旋zag、右旋zig)和4种旋转情况(LL,LR,RL,RR);旋转操作要保持二叉查找树的性质,通过对访问点x的位置来判断旋转情况,对应的情况使用对应的旋转操作序列,就可以让x的所属层上升,循环对x操作就可以把x调到根节点的位置。

      /                             \  
      p                              x  
     / \         Zig(x)             / \  
    x  <>   ----------------->     <>  p  
   / \                                / \  
  <> <>                              <> <>  
       /                             \ 
      x                              p 
     / \         Zag(x)             / \ 
    p  <>   <-----------------     <>  x 
   / \                                / \ 
  <> <>                              <> <> 
 1 struct node
 2 {
 3     int data;
 4     node *left,*right,*father;
 5     node(int d=0,node* a=NULL,node *b=NULL,node *c=NULL):data(d),left(a),right(b),father(c){}
 6 }*root;
 7 void zig(node *k)
 8 {
 9     node* fa=k->father;
10     fa->left=k->right;
11     if (k->right) k->right->father=fa;
12     k->right=fa;
13     k->father=fa->father;
14     fa->father=k;
15     if (!k->father) return;
16     if (k->father->data>k->data)
17         k->father->left=k;
18     else
19         k->father->right=k;
20 }
21 void zag(node *k)
22 {
23     node* fa=k->father;
24     fa->right=k->left;
25     if (k->left) k->left->father=fa;
26     k->left=fa;
27     k->father=fa->father;
28     fa->father=k;
29     if (!k->father) return;
30     if (k->father->data>k->data)
31         k->father->left=k;
32     else
33         k->father->right=k;
34 }
35 void splay(node *k,node *&root)
36 {
37     while (k->father)
38     {
39         node *fa=k->father;
40         if (fa->father==NULL)
41         {
42             if (k==fa->left) zig(k);
43                else zag(k);
44 
45         } else
46         {
47             node *gf=fa->father;
48             if (fa==gf->left && k==fa->left){zig(fa);zig(k);}
49             if (fa==gf->left && k==fa->right){zag(k);zig(k);}
50             if (fa==gf->right && k==fa->left){zig(k);zag(k);}
51             if (fa==gf->right && k==fa->right){zag(fa);zag(k);}
52         }
53     }
54     root=k;
55 }
Splay旋转调整代码

相关文章: