More abstract data types
Linked Lists
Let’s say we want a type that has the following operations:
- append(value)
- stores a value
- nth(n)
- retrieve the n-th value stored
- remove(n)
- remove the nt-th value stored
These operations should sound familiar: they are the core operations on Python’s lists. These are also the operations on another abstract data type, which we might call a Sequence. We saw a similar type in Pyret: Pyret’s lists, defined as
data List: | empty | link(fst, rst :: List) end
Python’s lists are implemented using contiguous chunks of memory. Pyret’s lists are different: they are constructed as a linked structure. Could we build something similar in Python? Yes–similar to binary search trees?
Linked list code
Here’s the implementation of linked lists that we developed in class:
class ListNode: def __init__(self, data, parent=None): self.data = data self.parent = parent self.next = None class LinkedList: def __init__(self): self.fst = None def append(self, data): if not self.fst: self.fst = ListNode(data) else: node = self.fst while node.next: node = node.next node.next = ListNode(data, node) def find_nth(self, n: int) -> ListNode: node = self.fst while node: if n == 0: return node n -= 1 raise IndexError("Index out of bounds") def nth(self, n: int): return self.find_nth(n).data def remove_node(self, node): node.parent.next = node.next node.next.parent = node.parent def remove(self, index: int): self.remove_node(self.find_nth(index))
Here’s a version with recursive methods:
class ListNode: def __init__(self, data, parent=None): self.data = data self.parent = parent self.next = None class LinkedList: def __init__(self): self.fst = None def append_to(self, node: ListNode, data): if not node.next: node.next = ListNode(node, data) else: self.append_to(node.next, data) def append(self, data): if not self.fst: self.fst = ListNode(data) else: self.append_to(self.fst, data) def find_nth_after(self, node: ListNode, n: int) -> ListNode: if not node: raise IndexError("Index out of bounds") if n == 0: return node return self.find_nth_after(node.next, n - 1) def find_nth(self, n: int) -> ListNode: return self.find_nth_after(self.root, n) def nth(self, n: int): return self.find_nth(n).data def remove_node(self, node): if node.parent: node.parent.next = node.next if node.next: node.next.parent = node.parent def remove(self, index: int): self.remove_node(self.find_nth(index))