2

I have a class:

class ListNode {
     int val;
     ListNode next;
     ListNode(int x) { val = x; }
}

And the function to print the LinkedList is :

public static void printLinkedNode(ListNode l){
        while(l != null){
            System.out.print(l.val+" ");
            l = l.next;
        }
        System.out.println(" ");
    }

In my main function, I create a ListNode called test:

ListNode test = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
head.next.next.next = new ListNode(4);

If I do A:

ListNode fast = head, slow = head;
fast = fast.next.next;
printLinkedNode(head); // I get 1->2->3->4

If I do B:

ListNode fast = head, slow = head;
fast.next = fast.next.next;
printLinkedNode(head); // I get 1->3->4

I am confused at why in A, the head is 1->2->3->4, but not 3->4? I have read some posts about Is Java “pass-by-reference” or “pass-by-value”?, but still can't figure it out..

If I do C:

            ListNode fast = head, slow = head;
            fast = fast.next.next;
            printLinkedNode(fast);   //3->4
            printLinkedNode(head);   //1->2->3->4
            fast.next = new ListNode(5);
            printLinkedNode(fast);   //3->5
            printLinkedNode(head);   //1->2->3->5, why the head will change?

I am confused at why the head will change when we do fast.next = new ListNode(5); I think fast is not assign with head?

user6142261
  • 627
  • 1
  • 8
  • 14
  • `head` still references the same object. In A you let `fast` reference the same instance as `head` and then change that reference to the next node while keeping the reference `head` unchanged. Java is pass-by-value in that the "value" of a reference is copied and passed (not the address of or the pointer to a reference). Think of Java references as some kind of pointer: `fast = head` means you have two "pointers" pointing to the same address (they have the same value) and when you do `fast = xxx` you let `fast` point to some other address (you change the value of that pointer only). – Thomas Sep 05 '17 at 15:24

2 Answers2

9

When you assign a variable, you make it point (reference) to a specific object. When you reassign it, you make it point (reference) to another object, you don't overwrite the reference value it is holding:

ListNode fast = head, slow = head; // fast has a reference to head.
fast = fast.next.next;             // fast has a reference to fast.next.next. You are not overwriting head, just fast.
printLinkedNode(head); // I get 1->2->3->4

Instead, if you edit something inside a referenced object, you'll edit the original object:

ListNode fast = head, slow = head; // fast has a reference to head
fast.next = fast.next.next;        // by editing fast.next, you edit head.next
printLinkedNode(head); // I get 1->3->4

Update for usecase C:

ListNode fast = head, slow = head; // fast = head = (1)
fast = fast.next.next;             // fast = fast.next.next = (3). head is still (1)
printLinkedNode(fast);             // 3->4 -> because fast points to head.next.next (3)
printLinkedNode(head);             // 1->2->3->4 -> head wasn't modified by any of the previous instructions

// here fast points to head.next.next. So fast.next is the same as head.next.next.next (4).
fast.next = new ListNode(5);       // Overwrites fast.next, it was (4), becomes (5)
printLinkedNode(fast);             // 3->5
printLinkedNode(head);             // 1->2->3->5

To make it easier to understand:

Let's say we have objects a, b and c of type ListNode:

ListNode a = new ListNode(1);
ListNode b = new ListNode(2);
ListNode c = new ListNode(3);

ListNode d = a; // variable d now points to object a
d.next = b;     // since d points to a, this statement modifies a.next
d = c           // This does *not* modify a. It just makes d point to c.
BackSlash
  • 21,927
  • 22
  • 96
  • 136
0

Great question, I get mess up with ListNode reference/assigning too.

Try below use case, which would help you understand it. This example could provide a comparison to ListNode.

List<Integer> listA = new ArrayList<>();
listA.add(20);
List<Integer> listB = new ArrayList<>();
listB.add(30);
System.out.println("listA: " + listA);
System.out.println("listB: " + listB);

// assign list and it has a reference to listA
List<Integer> list = listA;

// re-assign list and it has a reference to listB now
list = listB;

/* modify list, listB will be changed too. Similar in ListNode class, e.g. ListNode dummy = head;
if you do dummy.next = ListNodeC or dummy.val = xxx, head's pointer and value will be changed too. */
list.add(88);

// you could see here listA is not changed since we have re-assign it with listB, now it points to listB.
System.out.println("listA: " + listA);
System.out.println("listB: " + listB);
System.out.println("list:  " + list);
Zhou Haibo
  • 1,681
  • 1
  • 12
  • 32