Skip to content

Commit ff49dd6

Browse files
committed
edit the code
1 parent 16bb0d5 commit ff49dd6

3 files changed

Lines changed: 56 additions & 116 deletions

File tree

Sprint-2/implement_linked_list/linked_list_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from linked_list import LinkedList
44

5+
56
class LinkedListTest(unittest.TestCase):
67
def test_pushes_then_pops(self):
78
l = LinkedList()
@@ -31,7 +32,7 @@ def test_remove_tail(self):
3132
l.remove(a)
3233
self.assertEqual(l.head, b)
3334
self.assertEqual(l.tail, b)
34-
self.assertIsNone(b.next)
35+
self.assertIsNone(b.forward)
3536
self.assertIsNone(b.previous)
3637

3738

Lines changed: 49 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,134 +1,72 @@
1-
import math
1+
import random
22

33

44
class Node:
5-
def __init__(self, value, next=None):
5+
def __init__(self, height, value):
66
self.value = value
7-
self.next = next
7+
self.forward = [None] * height
88

99

1010
class SkipList:
11+
MAX_HEIGHT = 16
12+
P = 0.5
13+
1114
def __init__(self):
12-
self.head = None
15+
self.head = Node(self.MAX_HEIGHT, None)
16+
self.level = 1
1317
self.length = 0
14-
self.skips = [] # list of skip pointers, each is a tuple (index, value)
1518

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
1830
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
3136

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
7146

7247
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]
9150

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
11858

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)
12460

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
12665

12766
def to_list(self):
128-
"""Return the skip list as a regular sorted list."""
12967
result = []
130-
current = self.head
68+
current = self.head.forward[0]
13169
while current:
13270
result.append(current.value)
133-
current = current.next
71+
current = current.forward[0]
13472
return result

Sprint-2/improve_with_precomputing/count_letters/count_letters_test.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from count_letters import count_letters
66

7+
78
class CommonPrefixTest(unittest.TestCase):
89
def test_only_upper(self):
910
self.assertEqual(count_letters("ABC"), 3)
@@ -25,10 +26,10 @@ def test_long_string(self):
2526
still_to_include = set(letter for letter in alphabet)
2627

2728
while len(s) < 10000000 or len(still_to_include) > 0:
28-
next = random.choice(alphabet)
29-
s += next
30-
if next in still_to_include:
31-
still_to_include.remove(next)
29+
forward = random.choice(alphabet)
30+
s += forward
31+
if forward in still_to_include:
32+
still_to_include.remove(forward)
3233

3334
self.assertEqual(count_letters(s), 5)
3435

0 commit comments

Comments
 (0)