A jumping table is a data structure that inserts, queries, and deletes the average time complexity of O (Nlogn), which is O (n) in the worst case, which is almost impossible to come by.
compared to the red and black trees .The worst time complexity is much worse, the red-black tree is O (Nlogn), and the Jump table is O (n) The average time complexity is the same implementation is much simpler
Https://en.wikipedia.org/wiki/Skip_list Wiki's jumping table example
the structure of the jumping table is as follows
Jumping table implementation or a linked list, is an ordered list, in the traversal of the time based on the comparison, but the ordinary linked list can only traverse, jumping table added a layer of the concept, the higher the number of elements, the less, each time first from the top to find, and then gradually drop the layer, until the appropriate location. You can see that the nodes at the top level are far less than the number of nodes at the bottom, thus realizing a hopping lookup.
definitions in Redis/* * Jump Table */typedef struct zskiplist { // header node and footer node struct zskiplistNode *header, *tail; // Number of nodes in the table unsigned long length; // number of layers of the node with the largest number of middle-level tables int level;} zskiplist; Jumping table Nodes/* * jumping table node */typedef struct zskiplistNode { // member Objects robj *obj; // score double score; // Back Hands struct zskiplistnode *backward; // Floor struct zskiplistlevel { // Forward Hands struct zskiplistNode *forward; // span unsigned int span; } level[];} The zskiplistNode; jump table is a spatial time-out data structure, compared to a doubly linked list, the extra space overhead is the level array element in Zskiplistnode, where redundancy stores the forward pointers for each layer.
Some methods of redis jumping table implementationZslcreatenodezslcreatezslfreenodezslfreezslrandomlevelzslinsertzsldeletenodezsldelete and a few other
focus on several methods/* * creates and returns a new jump table * * t = o (1) */zskiplist *zslcreate (void) { int j; zskiplist *zsl; // Allocated Space zsl = zmalloc (sizeof (*ZSL)); // Set the height and start layer number zsl->level = 1; zsl->length = 0; // Initialize header nodes //headers must have the highest level // t = o (1) zsl->header = zslcreatenode (ZSKIPLIST_MAXLEVEL,0,NULL); for (j = 0; j < zskiplist_maxlevel; j++) { zsl->header->level[j].forward = NULL; zsl->header->level[j].span = 0; } zsl->header->backward = null; // Set Footer zsl- >TAIL&NBSP;=&NBSP;NULL;&NBSP;&NBSP;&NBSP;&NBSP;RETURN&NBSP;ZSL;} Return a random value, as the level//level of the new Jumping table node is reasonable distribution is the efficiency of the jump table Int zslrandomlevel (void) { int level = 1; while ((random () &0xffff) < (zskiplist_p &NBSP;*&NBSP;0XFFFF)) level += 1; return (Level<zskiplist_maxlevel) ? level : zskiplist_maxlevel;} /* * creates a member for &NBSP;OBJ&NBSP, a new node with a score of score , * and inserts the new node into jump table zsl . The return value of the * * function is the new node. * * t_wrost = o (n^2), t_avg = o (n log n) */ Zskiplistnode *zslinsert (zskiplist *zsl, double score, robj *obj) { zskiplistnode *update[zskiplist_maxlevel], *x; unsigned int rank[zskiplist_maxlevel]; int i, level; redisassert (!isnan (score)); // Find the insertion position of the node at each layer // t_wrost = o (n^2), t_avg = o (N log n) x = zsl->header; for (i = zsl->level-1; i >= 0; i--) { /* store rank that is crossed to reach the insert position */ // if i is not zsl-> level-1 Layer // then i the start rank value of the layer is i+1 rank values // various layers of rank Value one layer accumulation // final rank[0] value plus one is the pre-node row of the new node // rank[0] will later become the basis for calculating span values and rank values rank[i] = i == (ZSL->LEVEL-1) ? 0 : rank[i+1]; // traverse the Jumping table /along the forward pointer / t_wrost = o (n^2), t_avg = o (n log n) while (x->level[i].forward && (x->level[i].forward->score < score | | // Comparison Score (x->level[i ].forward->score == score && Members, t = o (N) comparestringobjects (x->level[i].forward->obj,obj) < 0)) { // record the number of nodes that have been crossed along the way rank[i] += x->level[i].span; // move to next pointer x = x->level[i].forward; } // record the nodes that will be connected to the new node update[i] = x; } /* we assume the key is not already inside, since we allow duplicated * scores, and the re-insertion of score and redis object should never * happen since the caller of zslinsert () should test in the hash table * if the element is already inside or not. * * zslinsert () callers will ensure that the same score and elements of the same member do not appear, * so there's no need for further checks, so you can create new elements directly. */ // gets a random value as the number of layers for the new node // t = o (N) level = zslrandomlevel (); // If the number of layers in the new node is larger than the number of other nodes in the table // initializes unused layers in the header node and logs them to update array // in the future also points to the new node if (level > Zsl->level) { // initialize not used layer // t = o (1) for (i = zsl->level; i < level; i++) { rank[i] = 0; update[i] = zsl->header; update[i]->level[i].span = zsl->length; } // Update the maximum number of nodes in a table zsl->level = level; } // Create a new node &NBSP;&NBSP;&NBSp; x = zslcreatenode (Level,score,obj); // points the previously recorded pointer to the new node and makes the appropriate settings // t = o (1) for (i = 0; i < level; i++) { // set the of the new node forward Pointer x->level[i].forward = update[i]- >level[i].forward; // the forward of each node that will be recorded along the way The pointer points to the new node update[i]->level[i].forward = x; /* update span covered by update[i] as x is inserted here */ // Calculate the number of nodes spanned by a new node x->level[i].span = update[i]-> level[i].span - (rank[0] - rank[i]); // The span value of nodes along the way after the new node is inserted // where +1 calculates the new node update[i]->level[i].span = (Rank[0] - rank[i]) + 1; } /* increment span for untouched levels */ // the span values of the non-contact nodes also need to be added, which point directly from the table header to the new node // t = o (1) for (i = level; i < zsl-> level; i++) { update[i]->level[i].span++; } // set the new node's back pointer x->backward = (Update[0] == zsl->header) ? NULL : update[0]; if (X->level[0].forwarD) x->level[0].forward->backward = x; else zsl->tail = x; // the node count of the jumping table is increased by one zsl->length++; return x;}
procedure for jumping tables to find nodes(Take the Insert element as an example, delete, The process of finding is the same) 1. Start with the head, looking forward based on the forward pointer, if the previous element is larger than the element to be found, or if the tail pointer is encountered, the lower level continues to look up, and if the next element is not greater than the element to be found, forward advances a node and continues the comparison. 2. Repeat the 1 steps until the value of the previous node that Level1 encounters is greater than the value to be looked up eventually always finding the previous position that is larger than the value of the node to be found, inserting the element at this location.
Redis's Jumping table