Search code examples
pythonooplinked-list

Linked List in python is not showing the correct results


I want my code to print numbers from 0 to 5, instead it prints only 0 as output. Can anyone correct the code. code:

class Node:
  def __init__(self, value):
    self.value = value
    self.next = None

class LinkedList:
  def __init__(self):
    self.head = None
  def display(self):
    ptr = self.head
    while ptr is not None:
      print(ptr.value)
      ptr = ptr.next

l1 = LinkedList()
ptr = l1
ptr.head = Node(0)
ptr.head.next = None
a = [1, 2, 3, 4, 5]

for i in a:
    dummy = Node(i)
    ptr.next = dummy
    ptr = ptr.next

# Displaying the linked list
l1.display()

I tried to build a simple linked list in python and was trying to print the numbers that were stored in the linked list, but there is something wrong with my code and it isn't working as I wanted it to be.


Solution

  • You already have an answer, but I wanted to point out that you initialised ptr as an instance of LinkedList, but then in the loop deal with it as if it is an instance of Node. But as ptr is a LinkedList, it does not have a next attribute, and so the first iteration of the loop is actually adding a next attribute to the ptr object, and the rest of the values are chained to that.

    Before the first iteration, we have:

     l1  ptr
      ↓   ↓ 
    ┌─[LinkedList]─┐   ┌─[Node]─────┐
    │ head: ──────────►│ value: 0   │
    │              │   │ next: None │
    └──────────────┘   └────────────┘
    

    After the first iteration, we have accidentally created next in the linked list instance:

     l1 
      ↓ 
    ┌─[LinkedList]─┐   ┌─[Node]─────┐
    │ head: ──────────►│ value: 0   │
    │ next: ─┐     │   │ next: None │
    └────────│─────┘   └────────────┘
             │ ┌─[Node]─────┐
             └►│ value: 1   │
               │ next: None │
               └────────────┘
                 ↑
                ptr
    

    And when all iterations have been done:

     l1 
      ↓ 
    ┌─[LinkedList]─┐   ┌─[Node]─────┐
    │ head: ──────────►│ value: 0   │
    │ next: ─┐     │   │ next: None │
    └────────│─────┘   └────────────┘
             │ ┌─[Node]───┐ ┌─[Node]───┐ ┌─[Node]───┐ ┌─[Node]───┐ ┌─[Node]─────┐
             └►│ value: 1 │ │ value: 2 │ │ value: 3 │ │ value: 4 │ │ value: 5   │
               │ next: ────►│ next: ────►│ next: ────►│ next: ────►│ next: None │
               └──────────┘ └──────────┘ └──────────┘ └──────────┘ └────────────┘
                                                                     ↑
                                                                    ptr
    

    But as the display function will (correctly) start from head and not from next, it will only find the node with value 0.

    Other Remarks

    Methods of your class should not have print -- except while debugging. Instead of a display method, it is better practice to define a method that returns a string, and leave it to the caller to print it. You could even define the __repr__ method for this, so that when the caller calls print with a linked list as argument, this method will return the string for it.

    And we can still improve. We could move the loop from display into a method called __iter__, so that a linked list is iterable. That feature can then be used for building the string in __repr__, but also for other purposes.

    Finally, it would be nice if the linked list constructor could already take the values for it as arguments, and insert these values immediately. In the loop that adds these values, you could also consider to do it backwards, while passing the next link to the constructor as an extra argument. I find this quite elegant, as you don't have the need for a separate ptr variable then.

    So all that leads to this code:

    class Node:
        def __init__(self, value, nextnode=None):  # Added parameter
            self.value = value
            self.next = nextnode
        
    class LinkedList:
        def __init__(self, *values):  # Allow to immediately populate
            self.head = None
            for value in reversed(values):
                self.insert(value)
    
        def insert(self, value):
            self.head = Node(value, self.head)
    
        def __iter__(self):
            ptr = self.head
            while ptr:
                yield ptr.value
                ptr = ptr.next
    
        def __repr__(self):
            return " ".join(map(str, self))  # Relying on __iter__
        
    l1 = LinkedList(1, 2, 3, 4, 5)  # Pass values immediately
    print(l1)  # Relying on __repr__