Search code examples
javalinked-listnodes

How does .next work for Nodes? How does in some instance maintain its previous nodes and sometimes it does not?


I am a beginner in programming and I have a quick question on how the .next works for ListNodes. Here is my code below for one of the LeetCode problems:

class Solution 
{
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) 
    {
        ListNode finalHead = new ListNode(0);
        ListNode tempFinalHead = finalHead;

        while(list1 != null && list2 != null)
        {
            if(list1.val < list2.val)
            {
                tempFinalHead.next = list1;
                list1 = list1.next; //this line
            }
            else
            {
                tempFinalHead.next = list2;
                list2 = list2.next; //this line
            }

            tempFinalHead = tempFinalHead.next; //this line
        }

        if(list1 != null)
        {
            tempFinalHead.next = list1;
            list1 = list1.next;
        }

        if(list2 != null)
        {
            tempFinalHead.next = list2;
            list2 = list2.next;
        }

        return finalHead.next;
    }
}

I commented on 3 instances where we are updating the ListNode using .next. I was wondering, how is the tempFinalHead of code for "tempFinalHead = tempFinalHead.next;" previous nodes being maintained? To elaborate here is an example:

Say this is my input: Input: list1 = [1,2,4], list2 = [1,3,4] Output: [1,1,2,3,4,4]

After list1.next is ran, list1 will be: 2 -> 4 from 1 -> 2 -> 4 After list2.next is ran, list2 will be 3 - > 4 from 1 -> 3 -> 4

What I am confused about is when tempFinalHead.next is ran, wouldnt the previous nodes that it was holding be gone? How is it mainting the nodes previous?

The output ended up being correct but just don't understand how tempFinalHead.next maintains all previous nodes since we are replacing it everytime with .next.


Solution

  • After list1.next is ran, list1 will be: 2 -> 4 from 1 -> 2 -> 4 After list2.next is ran, list2 will be 3 - > 4 from 1 -> 3 -> 4

    Yes, list1 and list2 are references that walk forward and thereby reference linked lists that are shorter and shorter...

    What I am confused about is when tempFinalHead.next is ran, wouldnt the previous nodes that it was holding be gone? How is it mainting the nodes previous?

    Indeed, if we only could rely on tempFinalHead those nodes would be lost forever. But... we still have finalHead! That node reference has not moved, and allows us to traverse the merged list.

    It may help to visualise the process for the example input you have given. When the loop starts, we have list1, list2 and a newly created node, referenced by both finalHead and tempFinalHead:

                        list1
                          ↓
                        ┌───────────┐    ┌───────────┐    ┌───────────┐
    tempFinalHead       │ val:  1   │    │ val:  2   │    │ val:  4   │
    finalHead           │ next: ────────►│ next: ────────►│ next:null │
      ↓                 └───────────┘    └───────────┘    └───────────┘
    ┌───────────┐
    │ val: 0    │
    │ next:null │
    └───────────┘
                        ┌───────────┐    ┌───────────┐    ┌───────────┐
                        │ val:  1   │    │ val:  3   │    │ val:  4   │
                        │ next: ────────►│ next: ────────►│ next:null │
                        └───────────┘    └───────────┘    └───────────┘
                          ↑
                        list2
    

    After the first iteration, in which the else block was executed, three of the four references moved, and one next property was updated (rewired):

                        list1
                          ↓
                        ┌───────────┐    ┌───────────┐    ┌───────────┐
                        │ val:  1   │    │ val:  2   │    │ val:  4   │
    finalHead           │ next: ────────►│ next: ────────►│ next:null │
      ↓                 └───────────┘    └───────────┘    └───────────┘
    ┌───────────┐
    │ val: 0    │
    │ next: ────────┐
    └───────────┘   │
                    │   ┌───────────┐    ┌───────────┐    ┌───────────┐
                    │   │ val:  1   │    │ val:  3   │    │ val:  4   │
                    └──►│ next: ────────►│ next: ────────►│ next:null │
                        └───────────┘    └───────────┘    └───────────┘
                          ↑                ↑
                        tempFinalHead    list2
    

    It is important to see that when list2 was assigned to the 0-node's next property, this instantly made the list that starts at finalHead longer!

    We can look at the second iteration now. This time the if block executes, and we arrive in this situation:

                        tempFinalHead    list1
                          ↓                ↓
                        ┌───────────┐    ┌───────────┐    ┌───────────┐
                        │ val:  1   │    │ val:  2   │    │ val:  4   │
    finalHead         ┌►│ next: ────────►│ next: ────────►│ next:null │
      ↓               │ └───────────┘    └───────────┘    └───────────┘
    ┌───────────┐     │
    │ val: 0    │     └──────────────┐
    │ next: ────────┐                │
    └───────────┘   │                │
                    │   ┌───────────┐│   ┌───────────┐    ┌───────────┐
                    │   │ val:  1   ││   │ val:  3   │    │ val:  4   │
                    └──►│ next: ─────┘   │ next: ────────►│ next:null │
                        └───────────┘    └───────────┘    └───────────┘
                                           ↑
                                         list2
    

    At this point we can also see that tempFinalHead references the last node that was linked into its final position. We can traverse the list from finalHead -- which never moves -- and visit some nodes (0, 1, 1) which are in their final position. The first of these does not belong to the real data, and will be discarded at the end.

    The above process continues until all nodes have been wired into their correct position. Once the loop completes and also one of the two if blocks after it executes, we end with this:

                                                          tempFinalHead  list1 = null
                                                            ↓
                        ┌───────────┐    ┌───────────┐    ┌───────────┐
                        │ val:  1   │    │ val:  2   │    │ val:  4   │
    finalHead         ┌►│ next: ────────►│ next: ─────┐ ┌►│ next:null │
      ↓               │ └───────────┘    └───────────┘│ │ └───────────┘
    ┌───────────┐     │                               │ │
    │ val: 0    │     └──────────────┐ ┌──────────────┘ └──────────────┐
    │ next: ────────┐                │ │                               │
    └───────────┘   │                │ │                               │
                    │   ┌───────────┐│ │ ┌───────────┐    ┌───────────┐│ list2 = null
                    │   │ val:  1   ││ │ │ val:  3   │    │ val:  4   ││
                    └──►│ next: ─────┘ └►│ next: ────────►│ next: ─────┘
                        └───────────┘    └───────────┘    └───────────┘
    

    And finally finalHead moves one step forward, which results in discarding the dummy node that was created at the start (as it becomes unreachable). That reference is returned, and so the caller sees this:

                        ┌───────────┐    ┌───────────┐    ┌───────────┐
                        │ val:  1   │    │ val:  2   │    │ val:  4   │
                      ┌►│ next: ────────►│ next: ─────┐ ┌►│ next:null │
                      │ └───────────┘    └───────────┘│ │ └───────────┘
                      │                               │ │
                      └──────────────┐ ┌──────────────┘ └──────────────┐
                                     │ │                               │
                                     │ │                               │
                        ┌───────────┐│ │ ┌───────────┐    ┌───────────┐│
                        │ val:  1   ││ │ │ val:  3   │    │ val:  4   ││
           (returned)──►│ next: ─────┘ └►│ next: ────────►│ next: ─────┘
                        └───────────┘    └───────────┘    └───────────┘