linked_list.py (3298B)
1 #!/usr/bin/env python3 2 # vim: foldmethod=marker 3 # File : linked_list.py 4 # Description: Linked list example with generator function for __iter__ 5 # Copyright 2022 Harvard University. All Rights Reserved. 6 import copy 7 8 9 # Node {{{1 10 class Node: 11 def __init__(self, key, *, data=None, next=None): 12 self.key = key 13 self.data = data 14 self.next = next 15 16 17 # LinkedList {{{1 18 class LinkedList: 19 # List creation {{{2 20 def __init__(self, key, data, *, reverse=False): 21 start = Node(key[0], data=data[0]) # create root node 22 end = start 23 for k, d in zip(key[1:], data[1:]): 24 if reverse: 25 end = self._prepend(end, Node(k, data=d)) 26 else: 27 end = self._append(end, Node(k, data=d)) 28 self.first = end if reverse else start 29 30 @staticmethod 31 def _append(anchor, node): 32 anchor.next = node 33 return node 34 35 @staticmethod 36 def _prepend(anchor, node): 37 node.next = anchor 38 return node 39 40 # Sequence properties {{{2 41 def __getitem__(self, key): 42 _, node = self._getitem(key) 43 return node 44 45 def __len__(self): 46 node = self.first 47 count = 0 48 while node != None: 49 count += 1 50 node = node.next 51 return count 52 53 def __str__(self): 54 node = self.first 55 pretty = "" 56 while node != None: 57 pretty += f"node: {hex(id(node))} : key={node.key} : data={node.data}\n" 58 node = node.next 59 return pretty 60 61 def _getitem(self, key): 62 """Private method to retrieve a list element given a key. 63 Arguments: 64 key: identifies the node 65 Returns: 66 Tuple with reference to predecessor node and reference to node 67 with given key 68 """ 69 node = self.first 70 prev = node 71 while node != None: 72 if node.key == key: 73 return (prev, node) 74 prev = node 75 node = node.next 76 raise KeyError(f"Key '{key}' not found") 77 78 # Node insertion {{{2 79 def insert(self, key, node, *, before=False): 80 anchor = self.__getitem__(key) 81 if before: # insert before 82 tmp = copy.copy(anchor) # beware! 83 anchor.key = node.key 84 anchor.data = node.data 85 node = tmp 86 anchor.next = node 87 else: # insert after 88 assert anchor is not None 89 node.next = anchor.next 90 anchor.next = node 91 return node 92 93 # Node removal {{{2 94 def remove(self, key): 95 if self.first.key == key: 96 del_node = self.first 97 self.first = self.first.next 98 else: 99 prev, del_node = self._getitem(key) 100 prev.next = del_node.next 101 del del_node 102 103 # Iterator {{{2 104 def __iter__(self): 105 node = self.first 106 while node != None: 107 yield node 108 node = node.next 109 110 111 # main() {{{1 112 def main(): 113 # create a list 114 linked_list = LinkedList(range(5), list('abcde')) 115 116 # iter(ll) returns a generator object 117 print(type(iter(linked_list))) 118 for node in linked_list: 119 print(f'{node} : key={node.key} value={node.data}') 120 121 122 if __name__ == "__main__": 123 main()