3

I was trying to solve the Partition List problem on LeetCode. The problem asks to sort an linked list given a target list node, so that all the list nodes having smaller value than the target will come before the target, while their original relative order remains unchanged.

I was able to come up a straightforward algorithm and to pass the online judge, basically creating two pointers and using them each to link either nodes < target or >= target while traversing the list.

public ListNode partition(ListNode head, int x) {
    ListNode ptr = head;
    ListNode small = new ListNode(0);
    ListNode big = new ListNode(0);
    ListNode dummy_1 = big;
    ListNode dummy_2 = small;
    int i = 1;
    while (ptr != null) {
        if (ptr.val < x) {
          small.next = ptr;
          small = small.next;
        } else {
          big.next = ptr;
          big = big.next;
        }
        ListNode help = ptr.next;
        ptr.next = null;
        ptr = help;
    }
    small.next = dummy_1.next;
    return dummy_2.next;
}

the following codes breaks the the link between ptr and ptr.next, and move the
ptr to original ptr.next.

ListNode help = ptr.next;
ptr.next = null;
ptr = help;

What I haven't quite figured out yet is that why this step is necessary, as we can move ptr to its next and directly update the reference later using small.next = ptr and big.next = ptr in the while-loop;

However when I simply used ptr = ptr.next instead of the three lines of code above, the online judge responded with error Memory Limit Exceeded.

I would really appreciate if anyone can explain this for me. What may cause the Memory Limit error as any cycled-list has seemed to be already avoided?

JavaHopper
  • 5,567
  • 1
  • 19
  • 27
GettingBetter
  • 178
  • 2
  • 13
  • are you writing this in Java or C++? Your code C++, but your tag is Java – JavaHopper Aug 04 '16 at 18:17
  • However, those 3 lines are required to reclaim the Memory. If you just advance the pointer, the nodes are not removed, rather the ptr would point to next node in chain – JavaHopper Aug 04 '16 at 18:21
  • @JavaHopper Thanks for your reply! The code is actually in java, sorry if the coding style confuses you. So I guess the algorithm might work, method-wise? It's just taking up unnecessary memory space? – GettingBetter Aug 04 '16 at 18:32
  • I have explained what makes the difference, in my answer. Let me know if its still not clear. If you understand the philosophy behind it, you may accept/upvote the answer – JavaHopper Aug 04 '16 at 21:45
  • No nodes from the original list should get released for garbage collection, the nodes are just getting reordered. It would seem that the issue is that by not setting the last node's next pointer to null, you end up with a circular list. – rcgldr Aug 04 '16 at 22:52
  • @rcgldr Thanks a lot! I went through the algorithm again and think this is it. If the list ends with a ‘small’ node, point it to the head of the big list would create a cycled list as the last node in the big list had never been pointed to null. Again, thanks! – GettingBetter Aug 04 '16 at 23:03
  • @GettingBetter - You can probably use ptr = ptr.next, then after small.next = dummy1.next, set big.next = null. I tested this and posted an answer. – rcgldr Aug 04 '16 at 23:59

2 Answers2

1

An object will not be eligible for Garbage Collection if it is pointed to by at least one reference. You may follow this post to build a brief understanding around this concept

Here is what happens in both cases

Case 1:

ptr = ptr.next

Assume the Linked List is in following state during first iteration

enter image description here

ptr is advanced, but the previous node having value 7 is still being referenced by head

enter image description here

ptr is advanced, but the previous node having value 1 is still being referenced by its previous node

enter image description here

ptr is advanced, but the previous node having value 3 is still being referenced by its previous node

enter image description here

And it continues till the end of loop while. If the list is of very huge size, then memory is not reclaimed. Like your judge said, it would result in error like Memory Limit Exceeded

Case 2:

    ListNode help = ptr.next;
    ptr.next = null;
    ptr = help;

Assume the Linked List is in following state during first iteration.

  • help points to next node pointed by ptr
  • ptr is re-referenced to point to help, in next step
  • Hence the node earlier pointed to by ptr (the one which had value 7) is eligible for Garbage Collection
  • And memory is reclaimed

enter image description here

  • help points to next node pointed by ptr
  • ptr is re-referenced to point to help, in next step
  • Hence the node earlier pointed to by ptr (the one which had value 1) is eligible for Garbage Collection
  • And memory is reclaimed

enter image description here

  • help points to next node pointed by ptr
  • ptr is re-referenced to point to help, in next step
  • Hence the node earlier pointed to by ptr (the one which had value 3) is eligible for Garbage Collection
  • And memory is reclaimed

enter image description here

  • help points to next node pointed by ptr
  • ptr is re-referenced to point to help, in next step
  • Hence the node earlier pointed to by ptr (the one which had value 2) is eligible for Garbage Collection
  • And memory is reclaimed

enter image description here

Community
  • 1
  • 1
JavaHopper
  • 5,567
  • 1
  • 19
  • 27
  • Thanks for this thorough explanation, @JavaHopper! This really helps me understand the memory handling. I still have one more question, that before breaking the link between ptr and ptr.next, inside the while loop we have actually made simple.next/big.net point to the node that the ptr points to. Since the node still has one reference point to it, the memory would not be reclaimed, right? So how would this be different from moving ptr without breaking? – GettingBetter Aug 04 '16 at 22:38
  • As you could see, if you move ptr without breaking the chain, the individual nodes are still connected with each other, hence not garbage collected after each iteration – JavaHopper Aug 05 '16 at 03:21
1

As commented, just setting big.next = null is working (I ran this using netbeans / java).

static ListNode partition(ListNode head, int x) {
    ListNode ptr = head;
    ListNode small = new ListNode(0);
    ListNode big = new ListNode(0);
    ListNode dummy_1 = big;
    ListNode dummy_2 = small;
    while (ptr != null) {
        if (ptr.val < x) {
          small.next = ptr;
          small = small.next;
        } else {
          big.next = ptr;
          big = big.next;
        }
        ptr = ptr.next;
    }
    small.next = dummy_1.next;
    big.next = null;
    return dummy_2.next;
}
rcgldr
  • 27,407
  • 3
  • 36
  • 61