I was solving this problem for implementing LinkedList
and ListNode
classes, and Insert
and Remove
methods for LinkedList
. I was wondering if I can get any code review and feedback.
class ListNode: def __init__(self, value=None): self.value = value self.next = None self.prev = None def __repr__(self): """Return a string representation of this node""" return 'Node({})'.format(repr(self.value)) class LinkedList(object): def __init__(self, iterable=None): """Initialize this linked list and append the given items, if any""" """Best case Omega(1)""" """Worst case O(n)""" self.head = None self.tail = None self.size = 0 self.length = 0 if iterable: for item in iterable: self.append(item) def __repr__(self): """Return a string representation of this linked list""" # this actually helps me to see what's inside linkedList return 'LinkedList({})'.format(self.as_list()) def setHead(self,head): self.head = head def getNext(self): return self.next def setNext(self,next): self.next = next def size(self): """ Gets the size of the Linked List AVERAGE: O(1) """ return self.count def as_list(self): """Return a list of all items in this linked list""" items = [] current = self.head while current is not None: items.append(current.value) current = current.next return items def append(self, item): new_node = ListNode(item) if self.head is None: self.head = new_node # Otherwise insert after tail node else: self.tail.next = new_node # Update tail node self.tail = new_node # Update length self.size += 1 def get_at_index(self, index): """Return the item at the given index in this linked list, or raise ValueError if the given index is out of range of the list size. Best case running time: O(1) if it's head or no value, Worst case running time: O(n) if it's in the tail [TODO]""" if not (0 <= index < self.size): raise ValueError('List index out of range: {}'.format(index)) counter = self.head for i in range(index): counter = counter.next return counter.value def prepend(self, item): """Insert the given item at the head of this linked list""" """Best case Omega(1)""" """Worst case O(1)""" new_node = ListNode(item) # Insert before head node new_node.next = self.head # Update head node self.head = new_node # Check if list was empty if self.tail is None: self.tail = new_node # Update length self.size += 1 def insert(self, value, index): """ Inserts value at a specific index BEST: O(1) WORST: O(i -1) """ if not (0 <= index <= self.size): raise ValueError('List index out of range: {}'.format(index)) node = ListNode(value) prev = self.get_at_index(index) if index == 0: self.append(value) elif index == self.size: self.append(value) else: new_node = ListNode(value) node = self.head previous = None for i in range(index): previous = node node = node.next previous.next = new_node new_node.next = node self.size += 1 def remove(self, index): """Best case Omega(1)""" """Worst case O(n)""" previous = None current = self.head while current is not None: if current.value == self.get_at_index(index): if current is not self.head and current is not self.tail: previous.next = current.next if current is self.head: self.head = current.next if current is self.tail: if previous is not None: previous.next = None self.tail = previous return previous = current current = current.next return -1 def contains(self, value): """Return an item in this linked list if it's found""" """Best case Omega(1)""" """Worst case O(n)""" current = self.head # Start at the head node while current is not None: if value == current.value: return True current = current.next # Skip to the next node return False def test_linked_list(): ll = LinkedList() print(ll) print('Appending items:') ll.append('A') print(ll) ll.append('B') print(ll) ll.append('C') print(ll) print('head: {}'.format(ll.head)) print('testing: Getting items by index:') #ll = LinkedList(['A', 'B', 'C']) print(ll) ll.insert('AA', 0) print(ll) ll.remove(1) print(ll) if __name__ == '__main__': test_linked_list()
It also passes all of these tests:
# ############## TESTING ############### # ########################################################### from io import StringIO import sys # custom assert function to handle tests # input: count {List} - keeps track out how many tests pass and how many total # in the form of a two item array i.e., [0, 0] # input: name {String} - describes the test # input: test {Function} - performs a set of operations and returns a boolean # indicating if test passed # output: {None} def expect(count, name, test): if (count is None or not isinstance(count, list) or len(count) != 2): count = [0, 0] else: count[1] += 1 result = 'false' error_msg = None try: if test(): result = ' true' count[0] += 1 except Exception as err: error_msg = str(err) print(' ' + (str(count[1]) + ') ') + result + ' : ' + name) if error_msg is not None: print(' ' + error_msg + '\n') class Capturing(list): def __enter__(self): self._stdout = sys.stdout sys.stdout = self._stringio = StringIO() return self def __exit__(self, *args): self.extend(self._stringio.getvalue().splitlines()) sys.stdout = self._stdout # compare if two flat lists are equal def lists_equal(lst1, lst2): if len(lst1) != len(lst2): return False for i in range(0, len(lst1)): if lst1[i] != lst2[i]: return False return True print('ListNode Class') test_count = [0, 0] def test(): node = ListNode() return isinstance(node, object) expect(test_count, 'able to create an instance', test) def test(): node = ListNode() return hasattr(node, 'value') expect(test_count, 'has value property', test) def test(): node = ListNode() return hasattr(node, 'next') expect(test_count, 'has next property', test) def test(): node = ListNode() return node is not None and node.value is None expect(test_count, 'has default value set to None', test) def test(): node = ListNode(5) return node is not None and node.value == 5 expect(test_count, 'able to assign a value upon instantiation', test) def test(): node = ListNode() node.value = 5 return node is not None and node.value == 5 expect(test_count, 'able to reassign a value', test) def test(): node1 = ListNode(5) node2 = ListNode(10) node1.next = node2 return (node1 is not None and node1.next is not None and node1.next.value == 10) expect(test_count, 'able to point to another node', test) print('PASSED: ' + str(test_count[0]) + ' / ' + str(test_count[1]) + '\n\n') print('LinkedList Class') test_count = [0, 0] def test(): linked_list = LinkedList() return isinstance(linked_list, object) expect(test_count, 'able to create an instance', test) def test(): linked_list = LinkedList() return hasattr(linked_list, 'head') expect(test_count, 'has head property', test) def test(): linked_list = LinkedList() return hasattr(linked_list, 'tail') expect(test_count, 'has tail property', test) def test(): linked_list = LinkedList() return hasattr(linked_list, 'length') expect(test_count, 'has length property', test) def test(): linked_list = LinkedList() return linked_list is not None and linked_list.head is None expect(test_count, 'default head set to None', test) def test(): linked_list = LinkedList() return linked_list is not None and linked_list.tail is None expect(test_count, 'default tail set to None', test) def test(): linked_list = LinkedList() return linked_list is not None and linked_list.length == 0 expect(test_count, 'default length set to 0', test) print('PASSED: ' + str(test_count[0]) + ' / ' + str(test_count[1]) + '\n\n') print('LinkedList Contains Method') test_count = [0, 0] def test(): linked_list = LinkedList() return (hasattr(linked_list, 'contains') and callable(getattr(linked_list, 'contains'))) expect(test_count, 'has contains method', test) def test(): linked_list = LinkedList() linked_list.append(5) linked_list.append(10) linked_list.append(15) return linked_list.contains(15) is True expect(test_count, 'returns True if linked list contains value', test) def test(): linked_list = LinkedList() linked_list.append(5) linked_list.append(10) linked_list.append(15) return linked_list.contains(8) is False expect(test_count, 'returns False if linked list contains value', test) print('PASSED: ' + str(test_count[0]) + ' / ' + str(test_count[1]) + '\n\n')