|
1 | | -import math |
| 1 | +import random |
2 | 2 |
|
3 | 3 |
|
4 | 4 | class Node: |
5 | | - def __init__(self, value, next=None): |
| 5 | + def __init__(self, height, value): |
6 | 6 | self.value = value |
7 | | - self.next = next |
| 7 | + self.forward = [None] * height |
8 | 8 |
|
9 | 9 |
|
10 | 10 | class SkipList: |
| 11 | + MAX_HEIGHT = 16 |
| 12 | + P = 0.5 |
| 13 | + |
11 | 14 | def __init__(self): |
12 | | - self.head = None |
| 15 | + self.head = Node(self.MAX_HEIGHT, None) |
| 16 | + self.level = 1 |
13 | 17 | self.length = 0 |
14 | | - self.skips = [] # list of skip pointers, each is a tuple (index, value) |
15 | 18 |
|
16 | | - def _get_node(self, index): |
17 | | - """Get the node at the given index.""" |
| 19 | + def __len__(self): |
| 20 | + return self.length |
| 21 | + |
| 22 | + def random_height(self): |
| 23 | + height = 1 |
| 24 | + while random.random() < self.P and height < self.MAX_HEIGHT: |
| 25 | + height += 1 |
| 26 | + return height |
| 27 | + |
| 28 | + def _find_updated_path(self, value): |
| 29 | + update = [None] * self.MAX_HEIGHT |
18 | 30 | current = self.head |
19 | | - for _ in range(index): |
20 | | - if current is None: |
21 | | - return None |
22 | | - current = current.next |
23 | | - return current |
24 | | - |
25 | | - def rebuild_skips(self): |
26 | | - """Rebuild the skip pointer so we can jump over sqrt(n) elements.""" |
27 | | - n = self.length |
28 | | - if n == 0: |
29 | | - self.skips = [] |
30 | | - return |
| 31 | + for i in range(self.level - 1, -1, -1): |
| 32 | + while current.forward[i] and current.forward[i].value < value: |
| 33 | + current = current.forward[i] |
| 34 | + update[i] = current |
| 35 | + return update |
31 | 36 |
|
32 | | - step = int(math.sqrt(n)) or 1 |
33 | | - self.skips = list(range(0, n, step)) |
34 | | - |
35 | | - def _find_position(self, value): |
36 | | - """Find the position to insert value using skip pointers.""" |
37 | | - if self.length == 0: |
38 | | - return 0 |
39 | | - |
40 | | - # Use skip pointers to find the range where value should be |
41 | | - for i in range(len(self.skips) - 1): |
42 | | - a = self.skips[i] |
43 | | - b = self.skips[i + 1] |
44 | | - |
45 | | - node_a = self._get_node(a) |
46 | | - node_b = node_a |
47 | | - for _ in range(b - a): |
48 | | - if node_b: |
49 | | - node_b = node_b.next |
50 | | - |
51 | | - if node_a.value <= value < node_b.value: |
52 | | - # linear search between a and b |
53 | | - idx = a |
54 | | - current = node_a |
55 | | - while idx < b and current: |
56 | | - if current.value >= value: |
57 | | - return idx |
58 | | - current = current.next |
59 | | - idx += 1 |
60 | | - return b |
61 | | - # Check the last skip pointer |
62 | | - start = self.skips[-1] |
63 | | - idx = start |
64 | | - current = self._get_node(start) |
65 | | - while current: |
66 | | - if current.value >= value: |
67 | | - return idx |
68 | | - current = current.next |
69 | | - idx += 1 |
70 | | - return self.length |
| 37 | + def __contains__(self, value): |
| 38 | + current = self.head |
| 39 | + |
| 40 | + for i in range(self.level - 1, -1, -1): |
| 41 | + while current.forward[i] and current.forward[i].value < value: |
| 42 | + current = current.forward[i] |
| 43 | + |
| 44 | + current = current.forward[0] |
| 45 | + return current is not None and current.value == value |
71 | 46 |
|
72 | 47 | def insert(self, value): |
73 | | - """Insert value into the skip list, maintaining sorted order.""" |
74 | | - pos = self._find_position(value) |
75 | | - |
76 | | - if pos < self.length: |
77 | | - node_at_pos = self._get_node(pos) |
78 | | - if node_at_pos and node_at_pos.value == value: |
79 | | - return # value already exists, do not insert duplicates |
80 | | - # Insert the new node |
81 | | - new_node = Node(value) |
82 | | - if pos == 0: |
83 | | - new_node.next = self.head |
84 | | - self.head = new_node |
85 | | - else: |
86 | | - prev_node = self._get_node(pos - 1) |
87 | | - new_node.next = prev_node.next |
88 | | - prev_node.next = new_node |
89 | | - self.length += 1 |
90 | | - self.rebuild_skips() |
| 48 | + update = self._find_updated_path(value) |
| 49 | + forward_node = update[0].forward[0] |
91 | 50 |
|
92 | | - def __contains__(self, value): |
93 | | - if self.length == 0: |
94 | | - return False |
95 | | - |
96 | | - for i in range(len(self.skips) - 1): |
97 | | - a = self.skips[i] |
98 | | - b = self.skips[i + 1] |
99 | | - |
100 | | - node_a = self._get_node(a) |
101 | | - node_b = node_a |
102 | | - for _ in range(b - a): |
103 | | - if node_b: |
104 | | - node_b = node_b.next |
105 | | - |
106 | | - if node_a.value <= value < node_b.value: |
107 | | - idx = a |
108 | | - current = node_a |
109 | | - while idx < b and current: |
110 | | - if current.value == value: |
111 | | - return True |
112 | | - current = current.next |
113 | | - idx += 1 |
114 | | - return False |
115 | | - start = self.skips[-1] |
116 | | - idx = start |
117 | | - current = self._get_node(start) |
| 51 | + if forward_node and forward_node.value == value: |
| 52 | + return |
| 53 | + node_height = self.random_height() |
| 54 | + if node_height > self.level: |
| 55 | + for i in range(self.level, node_height): |
| 56 | + update[i] = self.head |
| 57 | + self.level = node_height |
118 | 58 |
|
119 | | - while current: |
120 | | - if current.value == value: |
121 | | - return True |
122 | | - current = current.next |
123 | | - idx += 1 |
| 59 | + new_node = Node(node_height, value) |
124 | 60 |
|
125 | | - return False |
| 61 | + for i in range(node_height): |
| 62 | + new_node.forward[i] = update[i].forward[i] |
| 63 | + update[i].forward[i] = new_node |
| 64 | + self.length += 1 |
126 | 65 |
|
127 | 66 | def to_list(self): |
128 | | - """Return the skip list as a regular sorted list.""" |
129 | 67 | result = [] |
130 | | - current = self.head |
| 68 | + current = self.head.forward[0] |
131 | 69 | while current: |
132 | 70 | result.append(current.value) |
133 | | - current = current.next |
| 71 | + current = current.forward[0] |
134 | 72 | return result |
0 commit comments