From cb2e0ac6e0b39769f714632d7e95df4cbac4c2fb Mon Sep 17 00:00:00 2001 From: Ebrahim Beiaty Date: Thu, 16 Apr 2026 21:55:39 +0100 Subject: [PATCH 1/3] implement_skip_list --- Sprint-2/implement_skip_list/skip_list.py | 66 +++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 Sprint-2/implement_skip_list/skip_list.py diff --git a/Sprint-2/implement_skip_list/skip_list.py b/Sprint-2/implement_skip_list/skip_list.py new file mode 100644 index 0000000..7d7c75d --- /dev/null +++ b/Sprint-2/implement_skip_list/skip_list.py @@ -0,0 +1,66 @@ +import math + + +class SkipList: + def __init__(self): + self.data = [] # sorted list + self.skips = [] # list of skip pointers, each is a tuple (index, value) + + def rebuild_skips(self): + """Rebuild the skip pointer so we can jump over sqrt(n) elements.""" + n = len(self.data) + if n == 0: + self.skips = [] + return + + step = int(math.sqrt(n)) or 1 + self.skips = list(range(0, n, step)) + + def _find_position(self, value): + """Find the position to insert value using skip pointers.""" + if not self.data: + return 0 + + # Use skip pointers to find the range where value should be + for i in range(len(self.skips) - 1): + a = self.skips[i] + b = self.skips[i + 1] + if self.data[a] <= value < self.data[b]: + # linear search between a and b + for j in range(a, b): + if self.data[j] >= value: + return j + return b + + # Check the last skip pointer + start = self.skips[-1] + for j in range(start, len(self.data)): + if self.data[j] >= value: + return j + return len(self.data) + + def insert(self, value): + """Insert value into the skip list, maintaining sorted order.""" + pos = self._find_position(value) + + if pos < len(self.data) and self.data[pos] == value: + return # value already exists, do not insert duplicates + self.data.insert(pos, value) + self.rebuild_skips() + + def __contains__(self, value): + if not self.data: + return False + + for i in range(len(self.skips) - 1): + a = self.skips[i] + b = self.skips[i + 1] + if self.data[a] <= value < self.data[b]: + return value in self.data[a:b] + + start = self.skips[-1] + return value in self.data[start::] + + def to_list(self): + """Return the skip list as a regular sorted list.""" + return self.data From e2cf8895178217af9fcf794a41228c50ebf50d4a Mon Sep 17 00:00:00 2001 From: Ebrahim Beiaty Date: Sun, 17 May 2026 23:03:23 +0200 Subject: [PATCH 2/3] Update skip_list implementation with linked list approach --- Sprint-2/implement_skip_list/skip_list.py | 102 +++++++++++++++++----- 1 file changed, 82 insertions(+), 20 deletions(-) diff --git a/Sprint-2/implement_skip_list/skip_list.py b/Sprint-2/implement_skip_list/skip_list.py index 7d7c75d..14870f0 100644 --- a/Sprint-2/implement_skip_list/skip_list.py +++ b/Sprint-2/implement_skip_list/skip_list.py @@ -1,14 +1,30 @@ import math +class Node: + def __init__(self, value, next=None): + self.value = value + self.next = next + + class SkipList: def __init__(self): - self.data = [] # sorted list + self.head = None + self.length = 0 self.skips = [] # list of skip pointers, each is a tuple (index, value) + def _get_node(self, index): + """Get the node at the given index.""" + current = self.head + for _ in range(index): + if current is None: + return None + current = current.next + return current + def rebuild_skips(self): """Rebuild the skip pointer so we can jump over sqrt(n) elements.""" - n = len(self.data) + n = self.length if n == 0: self.skips = [] return @@ -18,49 +34,95 @@ def rebuild_skips(self): def _find_position(self, value): """Find the position to insert value using skip pointers.""" - if not self.data: + if self.length == 0: return 0 # Use skip pointers to find the range where value should be for i in range(len(self.skips) - 1): a = self.skips[i] b = self.skips[i + 1] - if self.data[a] <= value < self.data[b]: + + node_a = self._get_node(a) + node_b = self._get_node(b) + + if node_a.value <= value < node_b.value: # linear search between a and b - for j in range(a, b): - if self.data[j] >= value: - return j + idx = a + current = node_a + while idx < b and current: + if current.value >= value: + return idx + current = current.next + idx += 1 return b - # Check the last skip pointer start = self.skips[-1] - for j in range(start, len(self.data)): - if self.data[j] >= value: - return j - return len(self.data) + idx = start + current = self._get_node(start) + while current: + if current.value >= value: + return idx + current = current.next + idx += 1 + return self.length def insert(self, value): """Insert value into the skip list, maintaining sorted order.""" pos = self._find_position(value) - if pos < len(self.data) and self.data[pos] == value: - return # value already exists, do not insert duplicates - self.data.insert(pos, value) + if pos < self.length: + node_at_pos = self._get_node(pos) + if node_at_pos and node_at_pos.value == value: + return # value already exists, do not insert duplicates + # Insert the new node + new_node = Node(value) + if pos == 0: + new_node.next = self.head + self.head = new_node + else: + prev_node = self._get_node(pos - 1) + new_node.next = prev_node.next + prev_node.next = new_node + self.length += 1 self.rebuild_skips() def __contains__(self, value): - if not self.data: + if self.length == 0: return False for i in range(len(self.skips) - 1): a = self.skips[i] b = self.skips[i + 1] - if self.data[a] <= value < self.data[b]: - return value in self.data[a:b] + node_a = self._get_node(a) + node_b = self._get_node(b) + + if node_a.value <= value < node_b.value: + idx = a + current = node_a + while idx < b and current: + if current.value == value: + return True + current = current.next + idx += 1 + return False start = self.skips[-1] - return value in self.data[start::] + idx = start + current = self._get_node(start) + + while current: + if current.value == value: + return True + current = current.next + idx += 1 + + return False def to_list(self): """Return the skip list as a regular sorted list.""" - return self.data + result = [] + current = self.head + while current: + result.append(current.value) + current = current.next + return result From 16bb0d5bbe99954ca408dffb6710243347e15b7c Mon Sep 17 00:00:00 2001 From: Ebrahim Beiaty Date: Tue, 19 May 2026 15:12:09 +0100 Subject: [PATCH 3/3] fix the reviewer comment --- Sprint-2/implement_skip_list/skip_list.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement_skip_list/skip_list.py b/Sprint-2/implement_skip_list/skip_list.py index 14870f0..e5b9fe0 100644 --- a/Sprint-2/implement_skip_list/skip_list.py +++ b/Sprint-2/implement_skip_list/skip_list.py @@ -43,7 +43,10 @@ def _find_position(self, value): b = self.skips[i + 1] node_a = self._get_node(a) - node_b = self._get_node(b) + node_b = node_a + for _ in range(b - a): + if node_b: + node_b = node_b.next if node_a.value <= value < node_b.value: # linear search between a and b @@ -95,7 +98,10 @@ def __contains__(self, value): b = self.skips[i + 1] node_a = self._get_node(a) - node_b = self._get_node(b) + node_b = node_a + for _ in range(b - a): + if node_b: + node_b = node_b.next if node_a.value <= value < node_b.value: idx = a