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:
currentNodeinto the looping part of the list.since == sinceScale, andcheckNodeis set tocurrentNodecheckNodeandcurrentNodeare both in the loop. AssinceScalegets larger, the frequency at whichcheckNodeis reset decreases. When it's big enough,checkNodewill remain constant untilcurrentNodegoes all the way around the loop and the cycle is detected. ScalingsinceScaleby 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.