Skip List
Skip List is a search data structure invented by William Pugh, supporting fast search, insertion, and deletion of data.
The expected space complexity of a skip list is \(O(n)\), and the expected time complexity for search, insertion, and deletion operations is \(O(\log n)\).
Basic Idea
As the name suggests, a skip list is a data structure similar to a linked list. More precisely, a skip list is an improvement over an ordered linked list.
For convenience, all subsequent ordered linked lists are assumed to be sorted in ascending order.
The search operation in an ordered linked list starts from the head and compares nodes one by one until the current node's value is greater than or equal to the target node's value. Clearly, the complexity of this operation is \(O(n)\).
A skip list introduces the concept of layers on top of an ordered linked list. First, each layer of a skip list is an ordered linked list, with the bottom layer being the original ordered linked list. Each node at layer \(i\) has a probability \(p\) of appearing at layer \(i+1\), where \(p\) is a constant.
Let \(L(n)\) denote the layer in a skip list with \(n\) nodes that is expected to contain \(\frac{1}{p}\) elements. It follows that \(L(n) = \log_{\frac{1}{p}}n\).
Searching in a skip list starts from layer \(L(n)\), horizontally comparing nodes until the next node is greater than or equal to the target node, then moving down to the next layer. This process repeats until reaching the first layer and no further operations can be performed. At this point, if the next node is the target node, the search is successful; otherwise, the element does not exist. This approach skips unnecessary comparisons, making skip list searches faster than those in ordered linked lists. It can be proven that the average complexity of skip list search is \(O(\log n)\).
Complexity Proof
Space Complexity
For a single node, the probability that its highest layer is \(i\) is \(p^{i-1}(1 - p)\). Therefore, the expected number of layers in a skip list is \(\sum_{i\ge 1} ip^{i - 1}(1-p) = \frac{1}{1 - p}\). Since \(p\) is a constant, the expected space complexity of a skip list is \(O(n)\).
In the worst case, each layer's ordered linked list is identical to the original ordered linked list, meaning the worst-case space complexity of a skip list is \(O(n \log n)\).
Time Complexity
Analyzing the search path from back to front, this process can be divided into two parts: climbing from the bottom layer to layer \(L(n)\) and subsequent operations. During analysis, it is assumed that a node's specific information is unknown before it is accessed.
Suppose we are currently at a node \(x\) at layer \(i\). We do not know the maximum layer of \(x\) or the maximum layer of nodes to the left of \(x\), only that \(x\)'s maximum layer is at least \(i\). If \(x\)'s maximum layer is greater than \(i\), the next step should be to move upward, with probability \(p\); if \(x\)'s maximum layer equals \(i\), the next step should be to move left, with probability \(1-p\).
Let \(C(i)\) be the expected cost of climbing \(i\) layers in an infinitely long skip list. Then:
Solving gives \(C(i)=\frac{i}{p}\).
Thus, in a skip list of length \(n\), the expected number of steps to climb from the bottom layer to layer \(L(n)\) is bounded above by \(\frac{L(n) - 1}{p}\).
Now, we only need to analyze how many more steps are required after reaching layer \(L(n)\). It is clear that after reaching layer \(L(n)\), the number of leftward steps will not exceed the total number of nodes at layer \(L(n)\) and above, whose expected value is \(\frac{1}{p}\). Therefore, the expected number of leftward steps after reaching layer \(L(n)\) is bounded above by \(\frac{1}{p}\). Similarly, the expected number of upward steps after reaching layer \(L(n)\) is bounded above by \(\frac{1}{p}\).
Thus, the expected number of search steps in a skip list query is \(\frac{L(n) - 1}{p} + \frac{2}{p}\). Since \(L(n)=\log_{\frac{1}{p}}n\), the expected time complexity of a skip list query is \(O(\log n)\).
In the worst case, each layer's ordered linked list is identical to the original ordered linked list, making the search process equivalent to querying the highest layer's ordered linked list. Therefore, the worst-case time complexity of a skip list query operation is \(O(n)\).
Insertion and deletion operations involve performing a search, recording nodes that need modification along the way, and finally applying the modifications. Since at most one node per layer needs modification and the expected number of layers in a skip list is \(\log_{\frac{1}{p}}n\), the expected time complexity of insertion and deletion is also \(O(\log n)\).
Implementation
Obtaining the Maximum Layer of a Node
Simulate adding layers with probability \(p\), then take the minimum with the upper limit.
1 2 3 4 5 6 | |
Search
Check if a node with key key exists in the skip list. Sentinel nodes can be used to reduce boundary condition discussions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
Insertion
Insert a node (key, value). The insertion process involves performing a search, recording which nodes the new node should be inserted after, and then performing the insertion. The last node with key less than key in each layer is the node that needs modification.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | |
Deletion
Delete the node with key key. The deletion process involves performing a search, recording which nodes the node to delete is after, and then performing the deletion. The last node with key less than key in each layer is the node that needs modification.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | |
Complete Code
The following code implements a map using a skip list. It is for reference only and has not been rigorously tested.
Reference Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | |
Random Access Optimization for Skip Lists
Accessing the \(k\)-th node in a skip list is equivalent to accessing the \(k\)-th node in the original ordered linked list. Clearly, this operation has a time complexity of \(O(n)\), which is not efficient enough.
Random access optimization for skip lists involves maintaining the length of each forward pointer. Suppose \(A\) and \(B\) are nodes in the skip list, where \(A\) is the \(a\)-th node and \(B\) is the \(b\)-th node \((a < b)\). If at a certain layer, \(A\)'s forward pointer points to \(B\), then the length of this forward pointer is \(b - a\).
Now, to access the \(k\)-th node in the skip list, start from the top layer and traverse horizontally until the current node's position plus the length of its forward pointer at that layer is greater than or equal to \(k\), then move down to the next layer. Repeat this process until reaching the first layer and no further operations can be performed. At this point, the current node is the \(k\)-th node in the skip list.
This allows fast access to the \(k\)-th element of the skip list. It can be proven that the time complexity of this operation is \(O(\log n)\).
References
本页面最近更新:,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:OI-wiki
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用