zoukankan      html  css  js  c++  java
  • 伸展树 ( 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  
  • 相关阅读:
    Implicit conversion from enumeration type 'enum CGImageAlphaInfo' to different enumeration type 'CGB
    iOS谋职之OC面试题
    IOS_视图实现圆角效果的三种方法及比较
    Objective-C 中的方法回掉
    returnValue of Chrome
    获取最新ADT下载地址的方法
    Git 分支使用
    Windows下运行jekyll,编码已不再是问题
    Github Pages另一个选择:GitCafe-Pages
    还没更换RubyGems镜像?
  • 原文地址:https://www.cnblogs.com/UnGeek/p/3013333.html
Copyright © 2011-2022 走看看