Python - LinkedList confusion

78 Views Asked by At
class Node:
    def __init__(self, data=None, next=None):
        self.data = data
        self.next = next

class LinkedList:
    def __init__(self):
        self.head = None    

    def insert_at_end(self,data):   >>> this function is working
        print('self.head: ', self.head)
        if self.head is None:
            self.head = Node(data, None)
            return
        
        itr = self.head

        while itr.next != None:
            itr = itr.next

        itr.next = Node(data, None)
def insert_at_end(self,data):   >>> this function is NOT working
    n = self.head
    node = Node(data, None)
    if n is None:
        n = node
        return
    
    while n.next != None:
        n = n.next
    n.next = node

When I add a node at end, the function which is not working gives me an empty list but the function which is working gives me a list. I think I am missing a basic point but unable to understand. I am new to Python and learning DSA.

if __name__ == '__main__':
    ll = LinkedList()
    ll.insert_at_end(100)
    ll.insert_at_end(101)
    ll.print_ll()

The working function gave me 100-->101--> The non working function gave me empty linked list.

Below is the print function which I used in both cases.

    def print_ll(self):
        if self.head == None:
            print("Empty Linked List")
            return

        n = self.head
        strll = ''
        
        while n != None:
            strll += str(n.data) + '-->'
            print("linkedlist: ", strll)

            n = n.next
2

There are 2 best solutions below

0
Blckknght On

The issue you have is that:

n = self.head
n = node

Isn't the same thing as:

self.head = node

The first version just assigns two different values to the same local variable n, while the second modifies the head attribute of self in a way that will persist outside of the function.

0
Chris On

Blckknght has nicely identified the problem with your code, but you can also make things easier on yourself (and improve performance) by storing the last element in your list along with the head.

You'll probably also find it useful to implement __iter__ for your linked list.

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

class LinkedList:
    def __init__(self):
        self.head = None    
        self.last = None

    def insert_at_end(self, data):   
        if self.head is None:
            self.head = Node(data)
            self.last = self.head
            return
        
        n = Node(data)
        self.last.next = n
        self.last = n

    def __iter__(self):
        itr = self.head
        while itr != None:
            yield itr.data
            itr = itr.next

With __iter__ then you can implement __str__ with something like:

    def __str__(self):
        return ' --> '.join(str(x) for x in self)