This code is for finding the loop in a single linked list and i have learned about it from http://blog.ostermiller.org/find-loop-singly-linked-list but could not get my head around why the code has been written the way it has been written.
This solution was devised by Stephen Ostermiller and proven O(n) by Daniel Martin.
function boolean hasLoop(Node startNode){
Node currentNode = startNode;
Node checkNode = null;
int since = 0;
int sinceScale = 2;
do {
if (checkNode == currentNode) return true;
if (since >= sinceScale){
checkNode = currentNode;
since = 0;
sinceScale = 2*sinceScale;
}
since++;
} while (currentNode = currentNode.next());
return false;
}
At last this was mentioned as well:
This solution is O(n) because sinceScale grows linearly with the number of calls to next(). Once sinceScale is greater than the size of the loop, another n calls to next() may be required to detect the loop.
This is Brent's cycle-finding algorithm. https://en.wikipedia.org/wiki/Cycle_detection#Brent%27s_algorithm
I like it better than Floyd's algorithm for most purposes. It does indeed work in O(N) time:
currentNode
into the looping part of the list.since == sinceScale
, andcheckNode
is set tocurrentNode
checkNode
andcurrentNode
are both in the loop. AssinceScale
gets larger, the frequency at whichcheckNode
is reset decreases. When it's big enough,checkNode
will remain constant untilcurrentNode
goes all the way around the loop and the cycle is detected. ScalingsinceScale
by 2 every time ensures that this happens in O(N) as well.For finding cycles in a linked list, either Floyd's algorithm or Brent's algorithm work fine, but Brent's algorithm is more convenient in a lot of real-life situations when getting from the current state to the next state is expensive and it would be impractical to move the second "slow" pointer that Floyd's algorithm requires.