views:

2784

answers:

7

How can i find whether a singly linked list is circular/cyclic or not? I Tried searching but couldn't find a satisfactory solution. If possible, can you provide pseudocode or Java?

For Example 1 3 5 71 45 7 5 -stop , its a circular linked list

A: 

Start at one node and record it, then iterate through the entire list until you reach a null pointer or the node you started with.

Something like:

Node start = list->head;
Node temp = start->next;
bool circular = false;
while(temp != null && temp != start)
{
   if(temp == start)
   {
     circular = true;
     break;
   }
   temp = temp->next;
}
return circular

This is O(n), which is pretty much the best that you will able to get with a singly linked list (correct me if I'm wrong).

Or to find any cycles in the list (such as the middle), you could do:

Node[] array; // Use a vector or ArrayList to support dynamic insertions
Node temp = list->head;
bool circular = false;
while(temp != null)
{
   if(array.contains(temp) == true)
   {
     circular = true;
     break;
   }
   array.insert(temp);
   temp = temp->next;
}
return circular

This will be a little bit slower due to the insertion times of dynamic arrays.

samoz
That will fail if the circle starts in the middle.
Vilx-
Good, but that ignores the following scenario: A->B->C->B-C->B...The loop may happen after you start. This is why the double iteration from answers above is needed.
Autocracy
Are we talking about duplicate entries in the list?
kd304
For the most part though, circular lists are usually referring to the end being tied to the head, rather than in the middle; those are usually just referred to as cyclic.
samoz
Edited to reflect what other people interpret a circular list as.
samoz
samoz is right, considering the question asks specifically about **circular** linked-lists, not for cycles.
Bill the Lizard
@Bill Thank you :)
samoz
According to the most recent edit, this won't work, since he is indeed looking for cycles.
Thomas Owens
@Thomas The second algorithm should address that condition then.
samoz
+34  A: 

The standard answer is to take two iterators at the beginning, increment the first one once, and the second one twice. Check to see if they point to the same object. Then repeat until the one that is incrementing twice either hits the first one or reaches the end.

This algorithm finds any circular link in the list, not just that it's a complete circle.

Pseudo-code (not Java, untested -- of the top of my head)

bool hasCircle(List l)
{
   Iterator i = l.begin(), j = l.begin();
   while (true) {
      // increment the iterators, if either is at the end, you're done, no circle
      if (i.hasNext())  i = i.next(); else return false;

      // second iterator is travelling twice as fast as first
      if (j.hasNext())  j = j.next(); else return false;
      if (j.hasNext())  j = j.next(); else return false;

      // this should be whatever test shows that the two
      // iterators are pointing at the same place
      if (i.getObject() == j.getObject()) { 
          return true;
      } 
   }
}
Lou Franco
The good thing about this is it spots cycles which aren't necessarily at the start, whereas the "check until you reach head again" only spots a fully circular list.
Jon Skeet
Nice, hadn't thought of this before! :)
Vilx-
Does this approach have a name?
teabot
@teabot: It's called Floyd's Cycle-Finding Algorithm, but it's sometimes referred to as "The Tortoise and the Hare Algorithm".
Bill the Lizard
In math this algorithm is sometimes used for loop finding, for example in factoring large numbers. There it is called after the greek letter rho, for the similarity to the shape of the search space with an initial part and loop at the end (i.e. Pollard's rho algorithm).
starblue
This seems like it'd be really slow for long lists. Perhaps that's unavoidable...?
Alex Feinman
@Alex: It's actually really fast since it's just list traversal. O(n) is the best you can hope for.
Bill the Lizard
You should check for `i== j` after each increment of j or you might needlessly 'skip over' i and have to run though the loop again.
Michael Burr
if i!=j at the start of the loop, then i cannot equal j after the first increment of j because i is incremented first.
Lou Franco
Here's the wikipedia page for it- http://en.wikipedia.org/wiki/Cycle_detection
RichardOD
A: 

How hard have you searched? This is in C++, but it will be trivial to convert in Java.

kgiannakakis
A: 

@samoz has in my point of view the answer! Pseudo code missing. Would be something like

yourlist is your linked list

allnodes = hashmap
while yourlist.hasNext()
   node = yourlist.next()
   if(allnodes.contains(node))
      syso "loop found"
      break;
   hashmap.add(node)

sorry, code is very pseudo (do more scripting then java lately)

Basically new HashSet(llist).size() <> llist.size() ?
kd304
No, I think this might give you a infinit loop and a crash after some time. You have realy to iterate over it.
OK. It seemed that loopiness is defined by the list value itself, not the next-pointer within the list.
kd304
+1  A: 

Search for the Tortoise-Hare algorithm/description.

leppie
A: 

Here is a nice site on which the different solutions can copied.

find loop singly linked list

This is the winner on that site

// Best solution
function boolean hasLoop(Node startNode){
  Node slowNode = Node fastNode1 = Node fastNode2 = startNode;
  while (slowNode && fastNode1 = fastNode2.next() && fastNode2 = fastNode1.next()){
    if (slowNode == fastNode1 || slowNode == fastNode2) return true;
    slowNode = slowNode.next();
  }
  return false;
}

This solution is "Floyd's Cycle-Finding Algorithm" as published in "Non-deterministic Algorithms" by Robert W. Floyd in 1967. It is also called "The Tortoise and the Hare Algorithm".

Markus Lausberg
A: 

hey it will never terminate from the loop,

it con also be done in following solution

bool hasCircle(List l) { Iterator i = l.begin(), j = l.begin(); while (true) { // increment the iterators, if either is at the end, you're done, no circle if (i.hasNext()) i = i.next(); else return false;

  // second iterator is travelling twice as fast as first
  if (j.hasNext())  j = j.next(); else return false;
  if (j.hasNext())  j = j.next(); else return false;

  // this should be whatever test shows that the two
  // iterators are pointing at the same place
  if (i.getObject() == j.getObject()) { 
      return true;
  } 

if(i.next()==j) break; } }

ajay