From 4c37eb7d07b62efb84b535712972a1fa5e657218 Mon Sep 17 00:00:00 2001 From: Hanif Ali Date: Sun, 10 Nov 2019 13:47:04 +0500 Subject: [PATCH] Improved on Singly Linked List Programs (#1558) * Improved Singly Linked List Added String Representations of Nodes and Linked Lists Added support for indexing and changing of Node data using indices. * Added a few comments to Linked Lists * Reformatted to conform to PEP8 * Added from_sequence.py Convert a Python List to Linked List comprising of Nodes and return head. * Added print_reverse.py Recursive program to print the elements of a Linked List in reverse. * Change 'is not None' for more Pythonicness --- data_structures/linked_list/from_sequence.py | 45 +++++++++++++ data_structures/linked_list/print_reverse.py | 55 ++++++++++++++++ .../linked_list/singly_linked_list.py | 65 ++++++++++++++++--- 3 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 data_structures/linked_list/from_sequence.py create mode 100644 data_structures/linked_list/print_reverse.py diff --git a/data_structures/linked_list/from_sequence.py b/data_structures/linked_list/from_sequence.py new file mode 100644 index 000000000..e6d335e81 --- /dev/null +++ b/data_structures/linked_list/from_sequence.py @@ -0,0 +1,45 @@ +# Recursive Prorgam to create a Linked List from a sequence and +# print a string representation of it. + +class Node: + def __init__(self, data=None): + self.data = data + self.next = None + + def __repr__(self): + """Returns a visual representation of the node and all its following nodes.""" + string_rep = "" + temp = self + while temp: + string_rep += f"<{temp.data}> ---> " + temp = temp.next + string_rep += "" + return string_rep + + + +def make_linked_list(elements_list): + """Creates a Linked List from the elements of the given sequence + (list/tuple) and returns the head of the Linked List.""" + + # if elements_list is empty + if not elements_list: + raise Exception("The Elements List is empty") + + # Set first element as Head + head = Node(elements_list[0]) + current = head + # Loop through elements from position 1 + for data in elements_list[1:]: + current.next = Node(data) + current = current.next + return head + + + +list_data = [1,3,5,32,44,12,43] +print(f"List: {list_data}") +print("Creating Linked List from List.") +linked_list = make_linked_list(list_data) +print("Linked List:") +print(linked_list) diff --git a/data_structures/linked_list/print_reverse.py b/data_structures/linked_list/print_reverse.py new file mode 100644 index 000000000..6572ccd8f --- /dev/null +++ b/data_structures/linked_list/print_reverse.py @@ -0,0 +1,55 @@ +# Program to print the elements of a linked list in reverse + +class Node: + def __init__(self, data=None): + self.data = data + self.next = None + + def __repr__(self): + """Returns a visual representation of the node and all its following nodes.""" + string_rep = "" + temp = self + while temp: + string_rep += f"<{temp.data}> ---> " + temp = temp.next + string_rep += "" + return string_rep + + + +def make_linked_list(elements_list): + """Creates a Linked List from the elements of the given sequence + (list/tuple) and returns the head of the Linked List.""" + + # if elements_list is empty + if not elements_list: + raise Exception("The Elements List is empty") + + # Set first element as Head + head = Node(elements_list[0]) + current = head + # Loop through elements from position 1 + for data in elements_list[1:]: + current.next = Node(data) + current = current.next + return head + +def print_reverse(head_node): + """Prints the elements of the given Linked List in reverse order""" + + # If reached end of the List + if head_node is None: + return None + else: + # Recurse + print_reverse(head_node.next) + print(head_node.data) + + + +list_data = [14,52,14,12,43] +linked_list = make_linked_list(list_data) +print("Linked List:") +print(linked_list) +print("Elements in Reverse:") +print_reverse(linked_list) diff --git a/data_structures/linked_list/singly_linked_list.py b/data_structures/linked_list/singly_linked_list.py index 73b982316..7137f4e66 100644 --- a/data_structures/linked_list/singly_linked_list.py +++ b/data_structures/linked_list/singly_linked_list.py @@ -3,8 +3,11 @@ class Node: # create a Node self.data = data # given data self.next = None # given next to None + def __repr__(self): # String Representation of a Node + return f"" -class Linked_List: + +class LinkedList: def __init__(self): self.head = None # Initialize head to None @@ -13,36 +16,36 @@ class Linked_List: self.insert_head(data) # If this is first node, call insert_head else: temp = self.head - while temp.next != None: # traverse to last node + while temp.next: # traverse to last node temp = temp.next temp.next = Node(data) # create node & link to tail def insert_head(self, data): newNod = Node(data) # create a new node - if self.head != None: + if self.head: newNod.next = self.head # link newNode to head self.head = newNod # make NewNode as head def printList(self): # print every node data temp = self.head - while temp is not None: + while temp: print(temp.data) temp = temp.next def delete_head(self): # delete from head temp = self.head - if self.head != None: + if self.head: self.head = self.head.next temp.next = None return temp def delete_tail(self): # delete from tail temp = self.head - if self.head != None: + if self.head: if self.head.next is None: # if head is the only Node in the Linked List self.head = None else: - while temp.next.next is not None: # find the 2nd last element + while temp.next.next: # find the 2nd last element temp = temp.next temp.next, temp = ( None, @@ -69,9 +72,47 @@ class Linked_List: # Return prev in order to put the head at the end self.head = prev + def __repr__(self): # String representation/visualization of a Linked Lists + current = self.head + string_repr = "" + while current: + string_repr += f"{current} ---> " + current = current.next + # END represents end of the LinkedList + string_repr += "END" + return string_repr + + # Indexing Support. Used to get a node at particaular position + def __getitem__(self, index): + current = self.head + + # If LinkedList is Empty + if current is None: + raise IndexError("The Linked List is empty") + + # Move Forward 'index' times + for _ in range(index): + # If the LinkedList ends before reaching specified node + if current.next is None: + raise IndexError("Index out of range.") + current = current.next + return current + + # Used to change the data of a particular node + def __setitem__(self, index, data): + current = self.head + # If list is empty + if current is None: + raise IndexError("The Linked List is empty") + for i in range(index): + if current.next is None: + raise IndexError("Index out of range.") + current = current.next + current.data = data + def main(): - A = Linked_List() + A = LinkedList() print("Inserting 1st at head") a1 = input() A.insert_head(a1) @@ -98,6 +139,14 @@ def main(): A.reverse() print("\nPrint List : ") A.printList() + print("\nString Representation of Linked List:") + print(A) + print("\n Reading/Changing Node Data using Indexing:") + print(f"Element at Position 1: {A[1]}") + p1 = input("Enter New Value: ") + A[1] = p1 + print("New List:") + print(A) if __name__ == "__main__":