Jumping Table Skiplist

Source: Internet
Author: User

Skiplist is commonly used in various open source engines, such as Redis's SortedSet container, luence Index dictionary, and so on skiplist.
1.SkipList
Inside the data structure, we know that there are two basic data storage structures: arrays and linked lists. They all have their own characteristics, arrays (especially ordered arrays), can be quickly queried, but not easy to delete operations, linked list, can be quickly deleted and deleted operations, but not easy to query. Is it possible that there is a data structure that combines the merits of each?
Based on this idea, William Pugh, a computer professor at the University of Maryland, introduced a new data structure in 1989, jumping tables. Its similar to the balanced binary tree of the linked list, but compared with the sort of binary tree, the difference is that its siblings between the nodes are connected by pointers. For example, the following sample:

1.1. Features

A. From a longitudinal perspective:
It is similar to a B + tree, with each layer being a subset of its adjacent lower layers. However, the difference from the B + tree is that the adjacent nodes of each layer are connected by pointers. If you think of it as a tree, there will be a corresponding tree height (height).
B. From a horizontal perspective:
It is a linked list. The more high-level linked list, the more sparse its elements. Each higher layer of the list element is a subset of its adjacent lower layer, then it is the proportion of the next layer, that is, its jumping steps or interval interval.

2. Read Operation
The read operation is relatively straightforward: start at the top, prioritize the horizontal walk, and then walk vertically until you encounter the target element. From the characteristics of jumping mark can be seen, to find the characteristics of new elements:
A. If the value to be queried is in the jump table, it will always be in the lowest element;
B. Starting a query from any layer of nodes, you can find the results.
The source code is as follows:

Statusenum Find (KeyType key, RecType *rec) {  int i;  NodeType *x = LIST.HDR;  /*******************************   *  find node containing data  *   *******************************/ For  (i = list.listlevel; I >= 0, i--) {while    (x->forward[i]! = NIL && complt (x->forward[i]-> ; key, key))      x = x->forward[i];  }  x = x->forward[0];  if (x! = NIL && compeq (X->key, key)) {    *rec = x->rec;    return STATUS_OK;  }  return status_key_not_found;}

3. Write operations

When inserting a new element, we usually need to finalize 2 questions to determine where the landscape is located and where it is located vertically. For example, if you now need to insert an element with a value of 40.
A. Transverse position
Because each layer of the linked list is orderly, for a given new element, its transverse position can be quickly determined and unique through the query operation.
B. Portrait position
According to the definition of the jumping table, we can see that the new element 40 into the layer height can be located between 0 to 4 layers of any layer. However, its vertical position is directly determined by its vertical height (height) and the average interval (interval) of the horizontal jump of each layer, so the rationality of its longitudinal position should be considered.
If you build a jumping table according to the idea of two forks, you can imagine that 100% of the elements are on the 0 level, 50% are on the 1 level, 25% are on 2, and so on. So, write the rules of the new element, try to keep the jumping table at each level similar to the "stature" of the binary tree, avoid all levels of deformation, so in the new element, usually according to the number of elements in the two-fork tree to calculate the corresponding probability, the number of layers to finalize:

protected int Chooserandomheight () {  static const double _prob = 0.5;  int level = 1;  while (_rndnum.nextdouble () < _prob)  {   level++;  }  

4. Efficiency

In the "Probabilistic analysis of Skip lists" article, the average run time of Skiplist is log2n, and the worst-case run time is the linear time, of course, the probability of this worst-case occurrence is very small.

5. Source code

/* Skip list */#include <stdio.h> #include <stdlib.h>/* implementation dependent declarations */typedef enum {            STATUS_OK, status_mem_exhausted, Status_duplicate_key, status_key_not_found} statusenum;typedef int keyType;                  /* Type of key *//* user data stored in tree */typedef struct {int stuff;  /* Optional Related data */} RecType; #define COMPLT (b) (a < b) #define COMPEQ (b) (A = = b)/* levels range from (0).                Maxlevel) */#define Maxlevel 15typedef struct Nodetag {keyType key;                /* key used for searching */RecType rec; /* User Data */struct nodetag *forward[1];              /* Skip list forward pointer */} nodetype;/* implementation Independent declarations */typedef struct {NodeType *hdr;              /* List Header */int listLevel; /* Current level of list */} skiplist;                  Skiplist list; /* Skip List information */#define NIL list.hdrstatusenum Insert (keyType key, RecType *rec) {int I,Newlevel;  NodeType *update[maxlevel+1];  NodeType *x; /*********************************************** * Allocate node for data and insert in list * *********************  //* Find where Key belongs */x = LIST.HDR; for (i = list.listlevel; I >= 0; i--) {while (x->forward[i]! = NIL && complt (X->forward[i]->key, K    EY)) x = x->forward[i];  Update[i] = x;  } x = x->forward[0];  if (x! = NIL && compeq (X->key, key)) return status_duplicate_key;           /* Determine level */for (newlevel = 0;           Rand () < RAND_MAX/2 && Newlevel < maxlevel;  newlevel++);    if (Newlevel > List.listlevel) {for (i = list.listlevel + 1; I <= newlevel; i++) update[i] = NIL;  List.listlevel = Newlevel; }/* Make new node */if ((x = static_cast<nodetype*> (malloc (nodeType) + newlevel*sizeof (NodeType *))) = =  0) return status_mem_exhausted;  X->key = key; x-&Gt;rec = *rec;    /* Update forward links */for (i = 0; I <= newlevel; i++) {X->forward[i] = update[i]->forward[i];  Update[i]->forward[i] = x; } return STATUS_OK;}  Statusenum free (keyType key) {int i;  NodeType *update[maxlevel+1], *x; /******************************************* * Delete node containing data from list * *****************************  //* Find where data belongs */x = LIST.HDR; for (i = list.listlevel; I >= 0; i--) {while (x->forward[i]! = NIL && complt (X->forward[i]->key, K    EY)) x = x->forward[i];  Update[i] = x;  } x = x->forward[0];  if (x = = NIL | |!compeq (X-&GT;KEY, key)) return status_key_not_found;    /* Adjust forward pointers */for (i = 0; I <= list.listlevel; i++) {if (Update[i]->forward[i]! = x) break;  Update[i]->forward[i] = x->forward[i];  } free (x); /* Adjust Header level */while ((List.listlevel > 0) && (list.hdr->forward[list.ListLevel] = = NIL) list.listlevel--; return STATUS_OK;}  Statusenum Find (KeyType key, RecType *rec) {int i;  NodeType *x = LIST.HDR; /******************************* * Find node containing data * *******************************/for (i = List.listl Evel; I >= 0;  i--) {while (x->forward[i]! = NIL && complt (X->forward[i]->key, key)) x = x->forward[i];  } x = x->forward[0];    if (x! = NIL && compeq (X->key, key)) {*rec = x->rec;  return STATUS_OK; } return status_key_not_found;}  void Initlist () {int i; /************************** * Initialize Skip list * **************************/if (LIST.HDR = Static_cast<nod Etype*> (malloc (sizeof (NodeType) + maxlevel*sizeof (NodeType *))) = = 0) {printf ("Insufficient memory (INI    TList) \ n ");  Exit (1);  } for (i = 0; I <= maxlevel; i++) list.hdr->forward[i] = NIL; List.listlevel = 0;}  int main (int argc, char **argv) {int I, maxnum, random; RecTYpe *rec;  KeyType *key;  Statusenum status;  /* Command-Line: * * SKL maxnum [random] * * SKL * Process * Sequential records * SKL 4000  R * Process 4000 Random records * */Maxnum = 1000;//atoi (1000);  random = 10;  Initlist ();  if (rec = static_cast<rectype*> (malloc (maxnum * sizeof (recType))) = = 0) {fprintf (stderr, "Insufficient memory    (rec) \ n ");  Exit (1); } if (key = Static_cast<keytype*> (malloc (maxnum * sizeof (keyType))) = = 0) {fprintf (stderr, "insufficient mem    Ory (key) \ n ");  Exit (1);    if (random) {/* fill "a" with unique random numbers */for (i = 0; i < maxnum; i++) Key[i] = rand ();  printf ("Ran,%d items\n", maxnum);    } else {for (i = 0; i < maxnum; i++) key[i] = i;  printf ("Seq,%d items\n", maxnum);    } for (i = 0; i < Maxnum; i++) {status = Insert (Key[i], &rec[i]);  if (status) printf ("Pt1:error =%d\n", status); } for (i = maxnum-1; I >= 0; i--) {statUS = find (Key[i], &rec[i]);  if (status) printf ("Pt2:error =%d\n", status);    } for (i = maxnum-1; I >= 0; i--) {status = Free (Key[i]);  if (status) printf ("Pt3:error =%d\n", status); } return 0;}

Reference:

"Skip lists:a probabilistic alternative to Balanced Trees"
"Probabilistic analysis of Skip lists"
https://msdn.microsoft.com/en-us/library/ms379573 (v=vs.80). aspx
Http://www.cppblog.com/mysileng/archive/2013/04/06/199159.html

Jumping Table Skiplist

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.