0

I have the following code for detecting a cycle in a linked list:

public Class Node {
    Object data;
    Node next = null;
}

boolean containCycle() {
    boolean retVal = true;
    Node head = this;
    Node slower = head;
    Node faster = head;

    if(faster != null && faster.next != null) {
        faster = faster.next;
    } else {    // there is only one element or zero element
        retVal = false;
    }

    if (faster.next != null) {
        faster = faster.next;
    } else {    // there are only 2 elements
        retVal = false;
    }

    while (slower != faster && slower != null && faster != null) {
        faster = (faster.next != null && faster.next.next != null) ? faster.next.next : null;
        slower = (slower.next != null) ? slower.next : null;
    }

    if (slower == faster) {
        retVal = true;
        System.out.printf("The two pointers meet at: %d\n", faster.data);
    } else {
        retVal = false;
    }

    if (retVal) {    // this is the part for detecting where the loop begins
        slower = head;
        while(slower.next != faster.next) {
            slower = slower.next;
            faster = faster.next;
        }
        System.out.println("The cycle starts at: " + slower.data);
    }

    return retVal;
}

This code runs fine up until the part where I actually start detecting where the loop begins, which I commented in the code. Somehow, this runs into an infinite loop.

I suspect that this is somehow related to pass by reference in Java? Am I updating the value that head refers to while I was detecting the loop? I am really out of ideas here. Please help!

nhahtdh
  • 55,989
  • 15
  • 126
  • 162
Enzo
  • 969
  • 1
  • 8
  • 23

1 Answers1

0

I dont know the exact algorithm, but you could use the following way to find the meeting point.

Let us call the Node at which slower and faster meet as meeting point.

Have two pointers one starting from head, another starting from meeting point . And keep count of how many nodes you need to traverse from head to meeting point(let us call this count as a) and meeting point's next node to meeting point. (Lets call this count b)

Now the difference |a-b| in these two counts represents the common part -right? (ie part between the start of the loop and the meeting point of slower and faster).

So now again start afresh.Reset the two pointers, one to head and other to meeting point + 1.

for example if a>b, move pointer from head |a-b| times else move pointer from meeting piont + 1 |a-b| times.

Now move two pointers together till they meet.

ANOTHER Way of explaining this

Since what you are looking for is similar to the case where you have two linked lists and they merge at some node and you need to identify that node. All you have is the starting points of the two linked lists.

So you start from head1 and count till end of list. Next you start from head2 and count till end of list.

The calculate the diff in the lengths. Increment the longer path diff times. And then start moving pointers starting from shorter paths head and the diff till the two pointers meet.

This is essentially the same thing what you are doing in the other case.

smk
  • 5,340
  • 5
  • 27
  • 41
  • This is the exact algorithm I am using, it's just that somehow my implementation for the second half(finding head of loop) is not working, and it results in an infinite loop. I tried a lot of different things and they all didn't work properly, so I am wondering what exactly is going on... – Enzo Feb 21 '13 at 05:28
  • But you are incremeting both slower and faster and that doesnt make sense. – smk Feb 21 '13 at 05:29
  • Sorry if their names are confusing, it's because that I used them in the first part to detect if there is actually a loop or not. Once I confirm the existence of a cycle, I move the slower one to head, keeping faster at the meeting place, and move them both by one each step. This is what your algorithm describes. – Enzo Feb 21 '13 at 05:41
  • I understood that. But what I dont understand is why are you moving both slower(starting from head) and faster(starting from meeting place) simulatneously 1 by 1. They will never meet - correct? – smk Feb 21 '13 at 05:45
  • My algo says to first move slower from head to meeting place, take count. Then move faster from meeting place +1 to meeting place, take count. Then calc the diff , and finally move them together , till they merge. – smk Feb 21 '13 at 05:46