0

I have started studying linkedlist and I couldnt figure out what does .next does. I understand it is pointing to next object but how it is doing that ? for example below is the code to insert new node to linked list.

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

def insertEnd(value):
    newnode = Node(value)
    currentNode = l.head
    while(currentNode.next):
        currentNode = currentNode.next
    currentNode.next = newnode

if __name__ == '__main__':
    l = ll()
    l.head = Node(6)
    second = Node(2)
    l.head.next = second
    insertEnd(9)


So how is thing happening. Kindly help me to understand.

  • Does this answer your question? [Python Linked List](https://stackoverflow.com/questions/280243/python-linked-list) – ekhumoro Sep 21 '22 at 13:08

1 Answers1

1

It may help to go through the program and visualise the state of the linked list:

When l = ll() is executed, the constructor runs and l gets to reference that data structure:

 l
 ↓
┌────────────┐ 
│ head: None │
└────────────┘

Then l.head = Node(6) will run the Node constructor, and then assign the reference it gets from that to the above pictured head member.

 l
 ↓
┌────────────┐ 
│ head: ─┐   │
└────────│───┘
         │
         ▼
┌────────────┐ 
│ data: 6    │
│ next: None │
└────────────┘

A similar thing happens with second = Node(2), but now the returned reference is assigned to a name, not an attribute:

 l
 ↓
┌────────────┐ 
│ head: ─┐   │
└────────│───┘
         │         second
         ▼          ↓
┌────────────┐    ┌────────────┐ 
│ data: 6    │    │ data: 2    │
│ next: None │    │ next: None │
└────────────┘    └────────────┘

With l.head.next = second the next attribute of the first node gets a reference to the second node:

 l
 ↓
┌────────────┐ 
│ head: ─┐   │
└────────│───┘
         │         second
         ▼          ↓
┌────────────┐    ┌────────────┐ 
│ data: 6    │    │ data: 2    │
│ next: ─────────►│ next: None │
└────────────┘    └────────────┘

Now the more challenging insertEnd(9) call is made. In insertEnd, newnode = Node(value) creates a new node and assigns its reference to a local name:

 l
 ↓
┌────────────┐ 
│ head: ─┐   │
└────────│───┘
         │         second            newNode (local)
         ▼          ↓                 ↓
┌────────────┐    ┌────────────┐    ┌────────────┐ 
│ data: 6    │    │ data: 2    │    │ data: 9    │
│ next: ─────────►│ next: None │    │ next: None │
└────────────┘    └────────────┘    └────────────┘

Another local name gets a reference to the first node that is already in the list: currentNode = l.head:

 l
 ↓
┌────────────┐ 
│ head: ─┐   │
└────────│───┘
         │         second            newNode (local)
         ▼          ↓                 ↓
┌────────────┐    ┌────────────┐    ┌────────────┐ 
│ data: 6    │    │ data: 2    │    │ data: 9    │
│ next: ─────────►│ next: None │    │ next: None │
└────────────┘    └────────────┘    └────────────┘
  ↑
 current (local)

Then the loop starts. It will make one iteration where it updates the local name to get another reference: currentNode = currentNode.next

 l
 ↓
┌────────────┐ 
│ head: ─┐   │
└────────│───┘
         │         second            newNode (local)
         ▼          ↓                 ↓
┌────────────┐    ┌────────────┐    ┌────────────┐ 
│ data: 6    │    │ data: 2    │    │ data: 9    │
│ next: ─────────►│ next: None │    │ next: None │
└────────────┘    └────────────┘    └────────────┘
                    ↑
                   current (local)

At this point the loop condition is no longer true, so the loop exits. At this point we can be sure that current references the tail node in the linked list. Finally, that tail node gets an update to its next attribute, so it links to the new node: currentNode.next = newnode

 l
 ↓
┌────────────┐ 
│ head: ─┐   │
└────────│───┘
         │         second            newNode (local)
         ▼          ↓                 ↓
┌────────────┐    ┌────────────┐    ┌────────────┐ 
│ data: 6    │    │ data: 2    │    │ data: 9    │
│ next: ─────────►│ next: ─────────►│ next: None │
└────────────┘    └────────────┘    └────────────┘
                    ↑
                   current (local)

The insertEnd function returns, so all its local names are discarded, and the main program sees this:

 l
 ↓
┌────────────┐ 
│ head: ─┐   │
└────────│───┘
         │         second
         ▼          ↓
┌────────────┐    ┌────────────┐    ┌────────────┐ 
│ data: 6    │    │ data: 2    │    │ data: 9    │
│ next: ─────────►│ next: ─────────►│ next: None │
└────────────┘    └────────────┘    └────────────┘
trincot
  • 317,000
  • 35
  • 244
  • 286
  • Ty, you have explained it so beautifully. I had the question of how next stores another object. For example how to node with data 6 stored second node. is it node inside node inside node or is it storing the address of second node and data of second node. and similarly second node is storing data and address of third node. – Shekhar lohach Sep 22 '22 at 11:10
  • Thanks. So the next node is not stored inside the previous one. You can think of it is an *address* that is stored in the `next` attribute, although the Python documentation would speak of the object's [identifier](https://docs.python.org/3/library/functions.html?highlight=id#id) – trincot Sep 22 '22 at 11:25