|
| 1 | +# Skip List |
| 2 | + |
| 3 | +Skip List is a probablistic data-structure with same logarithmic time bound and |
| 4 | +efficiency as AVL/ or Red-Black tree and provides a clever compromise to |
| 5 | +efficiently support search and update operations and is relatively simpler to |
| 6 | +implement compared to other map data structures. |
| 7 | + |
| 8 | +A skip list *S* consists of series of sorted linked lists *{L0, ..., Ln}*, |
| 9 | +layered hierarchicaly and each layer *L* stores a subset of items in layer *L0* |
| 10 | +in incremental order. The items in layers *{L1, ... Ln}* are chosen at random |
| 11 | +based on a coin flipping function with probability 1/2 . For traversing, every |
| 12 | +item in a layer hold references to the node below and the next node. This |
| 13 | +layers serve as express lanes to the layer underneath them, effectively making |
| 14 | +fast O(log n) searching possible by skipping lanes and reducing travel distance |
| 15 | +and in worse case searching degrades to O (n), as expected with regular linked |
| 16 | +list. |
| 17 | + |
| 18 | +For a skip list *S*: |
| 19 | + |
| 20 | +1. List *L0* contains every inserted item. |
| 21 | +2. For lists *{L1, ..., Ln}*, *Li* contains a randomly generated subset of the |
| 22 | + items in *Li-1* |
| 23 | +3. Height is determined by coin-flipping. |
| 24 | + |
| 25 | + |
| 26 | +Figure 1 |
| 27 | + |
| 28 | + |
| 29 | +#Searching |
| 30 | + |
| 31 | +Searching for element *N* starts by traversing from top most layer *Ln* until |
| 32 | +*L0*. |
| 33 | + |
| 34 | +Our objective is to find an element *K* such that its value at the rightmost |
| 35 | +position of current layer, is less-than target item and its subsequent node has |
| 36 | +a greater-equal value or nil ( *K.key < N.key <= (K.next.key or nil)* ). if |
| 37 | +value of *K.next* is equal to *N*, search is terminated and we return *K.next*, |
| 38 | +otherwise drop underneath using *K.down* to the node below ( at layer Ln-1 ) and |
| 39 | +repeat the process until *L0* where *K.down* is `nil` which indicates that level |
| 40 | +is *L0* and item doesn't exists. |
| 41 | + |
| 42 | + |
| 43 | +###Example: |
| 44 | + |
| 45 | + |
| 46 | + |
| 47 | +#Inserting |
| 48 | + |
| 49 | +Inserting element *N* has a similar process as searching. It starts by |
| 50 | +traversing from top most layer *Ln* until *L0*. We need to keep track of our |
| 51 | +traversal path using a stack. It helps us to traverse the path upward when |
| 52 | +coin-flipping starts, so we can insert our new element and update references to |
| 53 | +it. |
| 54 | + |
| 55 | +Our objective is to find a element *K* such that its value at the rightmost |
| 56 | +position of layer *Ln*, is less-than new item and its subsequent node has a |
| 57 | +greater-equal value or nil ( *K.key < N.key < (K.next.key or nil)* ). Push |
| 58 | +element *K* to the stack and with element *K*, go down using *K.down* to the |
| 59 | +node below ( at layer Ln-1 ) and repeat the process ( forward searching ) up |
| 60 | +until *L0* where *K.down* is `nil` which indicates that level is *L0*. We |
| 61 | +terminate the process when *K.down* is nil. |
| 62 | + |
| 63 | +At *L0*, *N* can be inserted after *K*. |
| 64 | + |
| 65 | +Here is the interesting part. We use coin flipping function to randomly create |
| 66 | +layers. |
| 67 | + |
| 68 | +When coin flip function returns 0, the whole process is finished but when |
| 69 | +returns 1, there are two possibilities: |
| 70 | + |
| 71 | +1. Stack is empty ( Level is *L0* /- *Ln* or at uninitialized stage) |
| 72 | +2. Stack has items ( traversing upward is possible ) |
| 73 | + |
| 74 | +In case 1: |
| 75 | + |
| 76 | +A new layer M* is created with a head node *NM* referencing head node of layer |
| 77 | +below and *NM.next* referencing new element *N*. New element *N* referecing |
| 78 | +element *N* at previous layer. |
| 79 | + |
| 80 | +In case 2: |
| 81 | + |
| 82 | +repeat until stack is empty Pop an item *F* from stack and update the references |
| 83 | +accordingly. *F.next* will be *K.next* and *K.next* will be *F* |
| 84 | + |
| 85 | +when stack is empty Create a new layer consisintg of a head node *NM* |
| 86 | +referencing head node of layer below and *NM.next* referencing new element |
| 87 | +*N*. New element *N* referencing element *N* at previous layer. |
| 88 | + |
| 89 | + |
| 90 | +###Example: |
| 91 | + |
| 92 | +Inserting 13. with coin flips (0) |
| 93 | + |
| 94 | + |
| 95 | + |
| 96 | + |
| 97 | + |
| 98 | + |
| 99 | + |
| 100 | + |
| 101 | + |
| 102 | +Inserting 20. with 4 times coin flips (1) |
| 103 | + |
| 104 | + |
| 105 | + |
| 106 | + |
| 107 | + |
| 108 | +#Removing |
| 109 | + |
| 110 | +Removing works similar to insert procedure. |
| 111 | + |
| 112 | +TODO |
| 113 | + |
| 114 | +#See also |
| 115 | + |
| 116 | +[Skip List on Wikipedia](https://en.wikipedia.org/wiki/Skip_list) |
| 117 | + |
| 118 | +Written for Swift Algorithm Club by [Mike Taghavi](https://github.com/mitghi) |
0 commit comments