伸展树 ( Splay tree )

开篇我先给出一个外国的splay tree的演示demo,跟着这个demo看下面的文章对你理解splay tree 有很大的帮助,并且里面有实现好的C语言版和java版 的splay tree(网站中输入节点个数会自动生成树,可以对其任意造作)

网站衔接:http://www.link.cs.cmu.edu/cgi-bin/splay/splay-cgi.pl

一、简介:
伸展树,或者叫自适应查找树,是一种用于保存有序集合的简单高效的数据结构。伸展树实质上是一个二叉查找树。允许查找,插入,删 除,删除最小,删除最大,分割,合并等许多操作,这些操作的时间复杂度为O(logN)。由于伸展树可以适应需求序列,因此他们的性能在实际应用中更优 秀。
伸展树支持所有的二叉树操作。伸展树不保证最坏情况下的时间复杂度为O(logN)。伸展树的时间复杂度边界是均摊的。尽管一个单独的操作可能很耗时,但对于一个任意的操作序列,时间复杂度可以保证为O(logN)。
二、自调整和均摊分析:
    平衡查找树的一些限制:
1、平衡查找树每个节点都需要保存额外的信息。
2、难于实现,因此插入和删除操作复杂度高,且是潜在的错误点。
3、对于简单的输入,性能并没有什么提高。
    平衡查找树可以考虑提高性能的地方:
1、平衡查找树在最差、平均和最坏情况下的时间复杂度在本质上是相同的。
2、对一个节点的访问,如果第二次访问的时间小于第一次访问,将是非常好的事情。
3、90-10法则。在实际情况中,90%的访问发生在10%的数据上。
4、处理好那90%的情况就很好了。
三、均摊时间边界:
在 一颗二叉树中访问一个节点的时间复杂度是这个节点的深度。因此,我们可以重构树的结构,使得被经常访问的节点朝树根的方向移动。尽管这会引入额外的操作, 但是经常被访问的节点被移动到了靠近根的位置,因此,对于这部分节点,我们可以很快的访问。根据上面的90-10法则,这样做可以提高性能。
为了达到上面的目的,我们需要使用一种策略──旋转到根(rotate-to-root)。具体实现如下:
旋转分为左旋和右旋,这两个是对称的。图示:
 
为了叙述的方便,上图的右旋叫做X绕Y右旋,左旋叫做Y绕X左旋。
下图展示了将节点3旋转到根:
 
                            图1
首先节点3绕2左旋,然后3绕节点4右旋。
注意:所查找的数据必须符合上面的90-10法则,否则性能上不升反降!!
四、基本的自底向上伸展树:
    应用伸展(splaying)技术,可以得到对数均摊边界的时间复杂度。
    在旋转的时候,可以分为三种情况:
1、zig情况。
    X是查找路径上我们需要旋转的一个非根节点。
    如果X的父节点是根,那么我们用下图所示的方法旋转X到根:
    
                                图2
    这和一个普通的单旋转相同。
2、zig-zag情况。
在这种情况中,X有一个父节点P和祖父节点G(P的父节点)。X是右子节点,P是左子节点,或者反过来。这个就是双旋转。
先是X绕P左旋转,再接着X绕G右旋转。
如图所示:
 
                            图三
3、zig-zig情况。
    这和前一个旋转不同。在这种情况中,X和P都是左子节点或右子节点。
    先是P绕G右旋转,接着X绕P右旋转。
    如图所示:
    
                                    图四
    下面是splay的伪代码:
    P(X) : 获得X的父节点,G(X) : 获得X的祖父节点(=P(P(X)))。
    Function Buttom-up-splay:
        Do
            If X 是 P(X) 的左子结点 Then
                If G(X) 为空 Then
                    X 绕 P(X)右旋
                Else If P(X)是G(X)的左子结点
                    P(X) 绕G(X)右旋
                    X 绕P(X)右旋
                Else
                    X绕P(X)右旋
                    X绕P(X)左旋 (P(X)和上面一句的不同,是原来的G(X))
                Endif
            Else If X 是 P(X) 的右子结点 Then
                If G(X) 为空 Then
                    X 绕 P(X)左旋
                Else If P(X)是G(X)的右子结点
                    P(X) 绕G(X)左旋
                    X 绕P(X)左旋
                Else
                    X绕P(X)左旋
                    X绕P(X)右旋 (P(X)和上面一句的不同,是原来的G(X))
                Endif
            Endif
        While (P(X) != NULL)
    EndFunction
    仔细分析zig-zag,可以发现,其实zig-zag就是两次zig。因此上面的代码可以简化:
    Function Buttom-up-splay:
        Do
            If X 是 P(X) 的左子结点 Then
                If P(X)是G(X)的左子结点
                    P(X) 绕G(X)右旋
                Endif
                X 绕P(X)右旋
            Else If X 是 P(X) 的右子结点 Then
                If P(X)是G(X)的右子结点
                    P(X) 绕G(X)左旋
                Endif
                X 绕P(X)左旋
            Endif
        While (P(X) != NULL)
    EndFunction
    下面是一个例子,旋转节点c到根上。
 
                                    图五
五、基本伸展树操作:
1、插入:
    当一个节点插入时,伸展操作将执行。因此,新插入的节点在根上。
2、查找:
    如果查找成功(找到),那么由于伸展操作,被查找的节点成为树的新根。
如果查找失败(没有),那么在查找遇到NULL之前的那个节点成为新的根。也就是,如果查找的节点在树中,那么,此时根上的节点就是距离这个节点最近的节点。
3、查找最大最小:
        查找之后执行伸展。
4、删除最大最小:
a)删除最小:
    首先执行查找最小的操作。
这时,要删除的节点就在根上。根据二叉查找树的特点,根没有左子节点。
使用根的右子结点作为新的根,删除旧的包含最小值的根。
b)删除最大:
首先执行查找最大的操作。
删除根,并把被删除的根的左子结点作为新的根。
5、删除:
        将要删除的节点移至根。
        删除根,剩下两个子树L(左子树)和R(右子树)。
        使用DeleteMax查找L的最大节点,此时,L的根没有右子树。
        使R成为L的根的右子树。
        如下图示:
        
                                图六
六、自顶向下的伸展树:
    在自底向上的伸展树中,我们需要求一个节点的父节点和祖父节点,因此这种伸展树难以实现。因此,我们可以构建自顶向下的伸展树。
    当我们沿着树向下搜索某个节点X的时候,我们将搜索路径上的节点及其子树移走。我们构建两棵临时的树──左树和右树。没有被移走的节点构成的树称作中树。在伸展操作的过程中:
1、当前节点X是中树的根。
2、左树L保存小于X的节点。
3、右树R保存大于X的节点。
开始时候,X是树T的根,左右树L和R都是空的。和前面的自下而上相同,自上而下也分三种情况:
1、zig:
 
                                图七
    如上图,在搜索到X的时候,所查找的节点比X小,将Y旋转到中树的树根。旋转之后,X及其右子树被移动到右树上。很显然,右树上的节点都大于所要查找的 节点。注意X被放置在右树的最小的位置,也就是X及其子树比原先的右树中所有的节点都要小。这是由于越是在路径前面被移动到右树的节点,其值越大。读者可 以分析一下树的结构,原因很简单。
2、zig-zig:
 
                                图八
    在这种情况下,所查找的节点在Z的子树中,也就是,所查找的节点比X和Y都小。所以要将X,Y及其右子树都移动到右树中。首先是Y绕X右旋,然后Z绕Y右旋,最后将Z的右子树(此时Z的右子节点为Y)移动到右树中。注意右树中挂载点的位置。
3、zig-zag:
 
                            图九
    在这种情况中,首先将Y右旋到根。这和Zig的情况是一样的。然后变成上图右边所示的形状。接着,对Z进行左旋,将Y及其左子树移动到左树上。这样,这种情况就被分成了两个Zig情况。这样,在编程的时候就会简化,但是操作的数目增加(相当于两次Zig情况)。
    最后,在查找到节点后,将三棵树合并。如图:
 
                                图十
    将中树的左右子树分别连接到左树的右子树和右树的左子树上。将左右树作为X的左右子树。重新最成了一所查找的节点为根的树。
    下面给出伪代码:
    右连接:将当前根及其右子树连接到右树上。左子结点作为新根。
    左连接:将当前根及其左子树连接到左树上。右子结点作为新根。
    T : 当前的根节点。
Function Top-Down-Splay
     Do
          If X 小于 T Then
               If X 等于 T 的左子结点 Then  
                 右连接
               ElseIf X 小于 T 的左子结点 Then
                 T的左子节点绕T右旋
                 右连接
               Else X大于 T 的左子结点 Then
                 右连接
                 左连接
               EndIf    
          ElseIf X大于 T Then
               IF X 等于 T 的右子结点 Then
                 左连接
               ElseIf X 大于 T 的右子结点 Then
                 T的右子节点绕T左旋
                 左连接
               Else X小于 T 的右子结点‘ Then
                 左连接
                 右连接
               EndIf
          EndIf
     While  !(找到 X或遇到空节点)
      组合左中右树
EndFunction

 

    同样,上面的三种情况也可以简化:
    Function Top-Down-Splay
        Do
              If X 小于 T Then
                   If X 小于 T 的左孩子 Then
                     T的左子节点绕T右旋
                   EndIf    
                右连接
              Else If X大于 T Then
                   If X 大于 T 的右孩子 Then
                     T的右子节点绕T左旋
                   EndIf
左连接
         EndIf
While  !(找到 X或遇到空节点)
组合左中右树
    EndFuntion

    下面是一个查找节点19的例子:
    在例子中,树中并没有节点19,最后,距离节点最近的节点18被旋转到了根作为新的根。节点20也是距离节点19最近的节点,但是节点20没有成为新根,这和节点20在原来树中的位置有关系。
 
    这个例子是查找节点c:
 
下面给一个用C语言实现的例子,比较简单易懂:

View Code
  1 /*
  2                  An implementation of top-down splaying
  3                      D. Sleator <sleator@cs.cmu.edu>
  4                               March 1992
  5   */
  6  #include <stdlib.h>
  7  #include <stdio.h>
  8   int size;  /* number of nodes in the tree */
  9             /* Not actually needed for any of the operations */
 10  typedef struct tree_node Tree;
 11   struct tree_node
 12  {
 13      Tree * left, * right;
 14      int item;
 15  };
 16  
 17  Tree * splay (int i, Tree * t)
 18  {
 19   /* Simple top down splay, not requiring i to be in the tree t.  */
 20   /* What it does is described above.                             */
 21      Tree N, *l, *r, *y;
 22      if (t == NULL)
 23          return t;
 24      N.left = N.right = NULL;
 25      l = r = &N;
 26      for (;;)
 27      {
 28          if (i < t->item)
 29          {
 30              if (t->left == NULL)
 31              {
 32                  break;
 33              }
 34              if (i < t->left->item)
 35              {
 36                  y = t->left;                           /* rotate right */
 37                  t->left = y->right;
 38                  y->right = t;
 39                  t = y;
 40                  if (t->left == NULL)
 41                  {
 42                      break;
 43                  }
 44              }
 45              r->left = t;                               /* link right */
 46              r = t;
 47              t = t->left;
 48          }     
 49          else if (i > t->item)
 50          {    
 51              if (t->right == NULL)
 52              {
 53                  break;
 54              }
 55              if (i > t->right->item)
 56              {
 57                  y = t->right;                          /* rotate left */
 58                  t->right = y->left;
 59                  y->left = t;
 60                  t = y;
 61                  if (t->right == NULL)
 62                  {
 63                      break;
 64                  }
 65              }
 66              l->right = t;                              /* link left */
 67              l = t;
 68              t = t->right;
 69          }     
 70          else    
 71          {
 72              break;
 73          }
 74      }
 75      l->right = t->left;                                /* assemble */
 76      r->left = t->right;
 77      t->left = N.right;
 78      t->right = N.left;
 79      return t;
 80  }
 81   /* Here is how sedgewick would have written this.                    */
 82  /* It does the same thing.                                           */
 83  Tree * sedgewickized_splay (int i, Tree * t)
 84  {
 85      Tree N, *l, *r, *y;
 86      if (t == NULL)
 87      {
 88          return t;
 89      }
 90      N.left = N.right = NULL;
 91      l = r = &N;
 92      for (;;)
 93      {
 94          if (i < t->item)
 95          {
 96              if (t->left != NULL && i < t->left->item)
 97              {
 98                  y = t->left;
 99                  t->left = y->right;
100                  y->right = t;
101                  t = y;
102              }
103              if (t->left == NULL)
104              {
105                  break;
106              }
107              r->left = t;
108              r = t;
109              t = t->left;
110          }
111          else if (i > t->item)
112          {
113              if (t->right != NULL && i > t->right->item)
114              {
115                  y = t->right;
116                  t->right = y->left;
117                  y->left = t;
118                  t = y;
119              }
120              if (t->right == NULL)
121              {
122                  break;
123              }
124              l->right = t;
125              l = t;
126              t = t->right;
127          }
128          else
129          {
130              break;
131          }
132      }
133      l->right=t->left;
134      r->left=t->right;
135      t->left=N.right;
136      t->right=N.left;
137      return t;
138  }
139  
140  Tree * insert(int i, Tree * t)
141  {
142  /* Insert i into the tree t, unless it's already there.    */
143  /* Return a pointer to the resulting tree.                 */
144      Tree * new;
145      
146      new = (Tree *) malloc (sizeof (Tree));
147      if (new == NULL)
148      {
149          printf("Ran out of space\n");
150          exit(1);
151      }
152      new->item = i;
153      if (t == NULL)
154      {
155          new->left = new->right = NULL;
156          size = 1;
157          return new;
158      }
159      t = splay(i,t);
160      if (i < t->item)
161      {
162          new->left = t->left;
163          new->right = t;
164          t->left = NULL;
165          size ++;
166          return new;
167      }
168      else if (i > t->item)
169      {
170          new->right = t->right;
171          new->left = t;
172          t->right = NULL;
173          size++;
174          return new;
175      }
176      else
177      {
178          /* We get here if it's already in the tree */
179          /* Don't add it again                      */
180          free(new);
181          return t;
182      }
183  }
184  
185  Tree * delete(int i, Tree * t)
186  {
187  /* Deletes i from the tree if it's there.               */
188  /* Return a pointer to the resulting tree.              */
189      Tree * x;
190      if (t==NULL)
191      {
192          return NULL;
193      }
194      t = splay(i,t);
195      if (i == t->item)
196      {               /* found it */
197          if (t->left == NULL)
198          {
199              x = t->right;
200          }
201          else
202          {
203              x = splay(i, t->left);
204              x->right = t->right;
205          }
206          size--;
207          free(t);
208          return x;
209      }
210      return t;                         /* It wasn't there */
211  }
212  
213  int main(int argv, char *argc[])
214  {
215  /* A sample use of these functions.  Start with the empty tree,         */
216  /* insert some stuff into it, and then delete it                        */
217      Tree * root;
218      int i;
219      root = NULL;              /* the empty tree */
220      size = 0;
221      for (i = 0; i < 1024; i++)
222      {
223          root = insert((541*i) & (1023), root);
224      }
225      printf("size = %d\n", size);
226      for (i = 0; i < 1024; i++)
227      {
228          root = delete((541*i) & (1023), root);
229      }
230      printf("size = %d\n", size);
231  }

 

 

下面给出一个终极版的splay tree 源代码,下面的源代码来自freeBSD内核,其在网络库libevent中也有应用,完全用macro实现,丝毫不逊色于STL中的set和map容器

View Code
  1 /*
  2  * This file defines data structures for different types of trees:
  3  * splay trees and red-black trees.
  4  *
  5  * A splay tree is a self-organizing data structure.  Every operation
  6  * on the tree causes a splay to happen.  The splay moves the requested
  7  * node to the root of the tree and partly rebalances it.
  8  *
  9  * This has the benefit that request locality causes faster lookups as
 10  * the requested nodes move to the top of the tree.  On the other hand,
 11  * every lookup causes memory writes.
 12  *
 13  * The Balance Theorem bounds the total access time for m operations
 14  * and n inserts on an initially empty tree as O((m + n)lg n).  The
 15  * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
 16  */
 17 #define SPLAY_HEAD(name, type)                        \
 18 struct name {                                \
 19     struct type *sph_root; /* root of the tree */            \
 20 }
 21 
 22 #define SPLAY_INITIALIZER(root)                        \
 23     { NULL }
 24 
 25 #define SPLAY_INIT(root) do {                        \
 26     (root)->sph_root = NULL;                    \
 27 } while (0)
 28 
 29 #define SPLAY_ENTRY(type)                        \
 30 struct {                                \
 31     struct type *spe_left; /* left element */            \
 32     struct type *spe_right; /* right element */            \
 33 }
 34 
 35 #define SPLAY_LEFT(elm, field)        (elm)->field.spe_left
 36 #define SPLAY_RIGHT(elm, field)        (elm)->field.spe_right
 37 #define SPLAY_ROOT(head)        (head)->sph_root
 38 #define SPLAY_EMPTY(head)        (SPLAY_ROOT(head) == NULL)
 39 
 40 /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
 41 #define SPLAY_ROTATE_RIGHT(head, tmp, field) do {            \
 42     SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field);    \
 43     SPLAY_RIGHT(tmp, field) = (head)->sph_root;            \
 44     (head)->sph_root = tmp;                        \
 45 } while (0)
 46     
 47 #define SPLAY_ROTATE_LEFT(head, tmp, field) do {            \
 48     SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field);    \
 49     SPLAY_LEFT(tmp, field) = (head)->sph_root;            \
 50     (head)->sph_root = tmp;                        \
 51 } while (0)
 52 
 53 #define SPLAY_LINKLEFT(head, tmp, field) do {                \
 54     SPLAY_LEFT(tmp, field) = (head)->sph_root;            \
 55     tmp = (head)->sph_root;                        \
 56     (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);        \
 57 } while (0)
 58 
 59 #define SPLAY_LINKRIGHT(head, tmp, field) do {                \
 60     SPLAY_RIGHT(tmp, field) = (head)->sph_root;            \
 61     tmp = (head)->sph_root;                        \
 62     (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);    \
 63 } while (0)
 64 
 65 #define SPLAY_ASSEMBLE(head, node, left, right, field) do {        \
 66     SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field);    \
 67     SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
 68     SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field);    \
 69     SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field);    \
 70 } while (0)
 71 
 72 /* Generates prototypes and inline functions */
 73 
 74 #define SPLAY_PROTOTYPE(name, type, field, cmp)                \
 75 void name##_SPLAY(struct name *, struct type *);            \
 76 void name##_SPLAY_MINMAX(struct name *, int);                \
 77                                     \
 78 static __inline void                            \
 79 name##_SPLAY_INSERT(struct name *head, struct type *elm)        \
 80 {                                    \
 81     if (SPLAY_EMPTY(head)) {                        \
 82         SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL;    \
 83     } else {                                \
 84         int __comp;                            \
 85         name##_SPLAY(head, elm);                    \
 86         __comp = (cmp)(elm, (head)->sph_root);            \
 87         if(__comp < 0) {                        \
 88             SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
 89             SPLAY_RIGHT(elm, field) = (head)->sph_root;        \
 90             SPLAY_LEFT((head)->sph_root, field) = NULL;        \
 91         } else if (__comp > 0) {                    \
 92             SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
 93             SPLAY_LEFT(elm, field) = (head)->sph_root;        \
 94             SPLAY_RIGHT((head)->sph_root, field) = NULL;    \
 95         } else                            \
 96             return;                        \
 97     }                                    \
 98     (head)->sph_root = (elm);                        \
 99 }                                    \
100                                     \
101 static __inline void                            \
102 name##_SPLAY_REMOVE(struct name *head, struct type *elm)        \
103 {                                    \
104     struct type *__tmp;                        \
105     if (SPLAY_EMPTY(head))                        \
106         return;                            \
107     name##_SPLAY(head, elm);                    \
108     if ((cmp)(elm, (head)->sph_root) == 0) {            \
109         if (SPLAY_LEFT((head)->sph_root, field) == NULL) {    \
110             (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
111         } else {                        \
112             __tmp = SPLAY_RIGHT((head)->sph_root, field);    \
113             (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
114             name##_SPLAY(head, elm);            \
115             SPLAY_RIGHT((head)->sph_root, field) = __tmp;    \
116         }                            \
117     }                                \
118 }                                    \
119                                     \
120 /* Finds the node with the same key as elm */                \
121 static __inline struct type *                        \
122 name##_SPLAY_FIND(struct name *head, struct type *elm)            \
123 {                                    \
124     if (SPLAY_EMPTY(head))                        \
125         return(NULL);                        \
126     name##_SPLAY(head, elm);                    \
127     if ((cmp)(elm, (head)->sph_root) == 0)                \
128         return (head->sph_root);                \
129     return (NULL);                            \
130 }                                    \
131                                     \
132 static __inline struct type *                        \
133 name##_SPLAY_NEXT(struct name *head, struct type *elm)            \
134 {                                    \
135     name##_SPLAY(head, elm);                    \
136     if (SPLAY_RIGHT(elm, field) != NULL) {                \
137         elm = SPLAY_RIGHT(elm, field);                \
138         while (SPLAY_LEFT(elm, field) != NULL) {        \
139             elm = SPLAY_LEFT(elm, field);            \
140         }                            \
141     } else                                \
142         elm = NULL;                        \
143     return (elm);                            \
144 }                                    \
145                                     \
146 static __inline struct type *                        \
147 name##_SPLAY_MIN_MAX(struct name *head, int val)            \
148 {                                    \
149     name##_SPLAY_MINMAX(head, val);                    \
150         return (SPLAY_ROOT(head));                    \
151 }
152 
153 /* Main splay operation.
154  * Moves node close to the key of elm to top
155  */
156 #define SPLAY_GENERATE(name, type, field, cmp)                \
157 void name##_SPLAY(struct name *head, struct type *elm)            \
158 {                                    \
159     struct type __node, *__left, *__right, *__tmp;            \
160     int __comp;                            \
161 \
162     SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
163     __left = __right = &__node;                    \
164 \
165     while ((__comp = (cmp)(elm, (head)->sph_root))) {        \
166         if (__comp < 0) {                    \
167             __tmp = SPLAY_LEFT((head)->sph_root, field);    \
168             if (__tmp == NULL)                \
169                 break;                    \
170             if ((cmp)(elm, __tmp) < 0){            \
171                 SPLAY_ROTATE_RIGHT(head, __tmp, field);    \
172                 if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
173                     break;                \
174             }                        \
175             SPLAY_LINKLEFT(head, __right, field);        \
176         } else if (__comp > 0) {                \
177             __tmp = SPLAY_RIGHT((head)->sph_root, field);    \
178             if (__tmp == NULL)                \
179                 break;                    \
180             if ((cmp)(elm, __tmp) > 0){            \
181                 SPLAY_ROTATE_LEFT(head, __tmp, field);    \
182                 if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
183                     break;                \
184             }                        \
185             SPLAY_LINKRIGHT(head, __left, field);        \
186         }                            \
187     }                                \
188     SPLAY_ASSEMBLE(head, &__node, __left, __right, field);        \
189 }                                    \
190                                     \
191 /* Splay with either the minimum or the maximum element            \
192  * Used to find minimum or maximum element in tree.            \
193  */                                    \
194 void name##_SPLAY_MINMAX(struct name *head, int __comp) \
195 {                                    \
196     struct type __node, *__left, *__right, *__tmp;            \
197 \
198     SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
199     __left = __right = &__node;                    \
200 \
201     while (1) {                            \
202         if (__comp < 0) {                    \
203             __tmp = SPLAY_LEFT((head)->sph_root, field);    \
204             if (__tmp == NULL)                \
205                 break;                    \
206             if (__comp < 0){                \
207                 SPLAY_ROTATE_RIGHT(head, __tmp, field);    \
208                 if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
209                     break;                \
210             }                        \
211             SPLAY_LINKLEFT(head, __right, field);        \
212         } else if (__comp > 0) {                \
213             __tmp = SPLAY_RIGHT((head)->sph_root, field);    \
214             if (__tmp == NULL)                \
215                 break;                    \
216             if (__comp > 0) {                \
217                 SPLAY_ROTATE_LEFT(head, __tmp, field);    \
218                 if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
219                     break;                \
220             }                        \
221             SPLAY_LINKRIGHT(head, __left, field);        \
222         }                            \
223     }                                \
224     SPLAY_ASSEMBLE(head, &__node, __left, __right, field);        \
225 }
226 
227 #define SPLAY_NEGINF    -1
228 #define SPLAY_INF    1
229 
230 #define SPLAY_INSERT(name, x, y)    name##_SPLAY_INSERT(x, y)
231 #define SPLAY_REMOVE(name, x, y)    name##_SPLAY_REMOVE(x, y)
232 #define SPLAY_FIND(name, x, y)        name##_SPLAY_FIND(x, y)
233 #define SPLAY_NEXT(name, x, y)        name##_SPLAY_NEXT(x, y)
234 #define SPLAY_MIN(name, x)        (SPLAY_EMPTY(x) ? NULL    \
235                     : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
236 #define SPLAY_MAX(name, x)        (SPLAY_EMPTY(x) ? NULL    \
237                     : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
238 
239 #define SPLAY_FOREACH(x, name, head)                    \
240     for ((x) = SPLAY_MIN(name, head);                \
241          (x) != NULL;                        \
242          (x) = SPLAY_NEXT(name, head, x))
243 
244  

 

posted @ 2013-04-10 22:47  godjob  Views(1778)  Comments(0Edit  收藏  举报