Tag Archives: Java

Finding the Start of a Loop in a Circular Linked List

A lot of people are familiar with the problem of detecting a loop in a linked list. The problem goes as follows: “Given a linked list, what is the algorithm to determine if it has any cycles (loops)?”

The algorithm is pretty straightforward:

  1. We start at the beginning of the linked list with two pointers.
  2. The first pointer is incremented through each node of the list. The second pointer moves twice as fast, and skips every other node.
  3. If the linked list contains a loop, these two pointers will eventually meet at the same node, thus indicating that the linked list contains a loop.

The algorithm is straightforward and it is relatively easy to create a mental model and get an intuitive sense of why it works.

Now, a slight twist to the same question asks: “Given a circular linked list, what is the algorithm to find the first node of the loop.” For instance, in the circular list A->B->C->D->E->C, the first node of the loop is node C. The first part of the algorithm is identical to the algorithm for finding if there is a loop (above). Once a loop has been found, the following additional steps will give us the starting node of the loop:

  1. Once a loop as been detected (step-3 above), move one of the pointers to the beginning (head) of the linked list. The second pointer remains where it was at the end of step-3.
  2. Increment both pointers one node at a time. The node at which the two pointers meet will be the starting node of the loop!

This algorithm isn’t too difficult compared to the algorithm for detecting a loop. However, the mental model seems a bit trickier. Why and how does it always find the start of the loop?


How does the Algorithm work? An intuitive explanation:

Here’s some explanation which would hopefully help you intuitively understand why the algorithm works, without going into a lot of mathematical detail.

First, meeting point of two pointers in a loop

Consider two pointers: a slow pointer S that increments by one node at each step, and a fast pointer F that increments by two nodes at each step (i.e. it is twice as fast as S). Both pointers start at the same time from the beginning of an n-node loop. In the time S covers n nodes. F will have covered 2n nodes and they will both meet at the start of the loop.

Now, let us say that the slow pointer S starts at the beginning of the loop, and the fast pointer F starts at node k (where k < n) of the loop. As these two pointers move along the loop, they will meet at node (n-x).

What we really need to do is figure out x, as it will give us the node at which the two pointers meet inside the loop.

  1. When S takes n/2 steps, it will be at node n/2. During the same time, F will have taken 2(n/2) = n steps, and it will be at node (k+n). Since the we are inside a loop, F will be effectively back at node k.
  2. In order for the two pointers to meet at node (n-x), S needs to take a further (n-x-n/2)=(n/2-x) steps and it will end up at node n-x. During the same time, F will have taken 2*(n/2-x)=(n-2x) steps and will be at node k+(n-2x). Given our assumption that both S and F meet at the same node:
		n-x = k+n-2x
	=>	  x = k

This means that if S starts from the start of the loop, and F starts k nodes into the loop, both of them will meet at node (n-k), i.e k nodes from the end of the loop. This is a key insight.

Circular Linked List

Now, coming back to the linked list that contains a loop. Suppose the start of the loop is m (e.g. m=3) nodes from the start of the linked list. Both S and F start at the beginning of the linked list [Figure-1].

Figure-1: Circular linked list with S and F pointers at the start

Figure-1: Circular linked list with S and F pointers at the start

 

By the time S gets to node m (i.e. start of loop), F will be at node 2m [Figure-2]. This means that S will be at the start of the loop and F will be m nodes *into the loop*.

Figure-2: Circular linked list, with S at the start of loop and F m nodes into the loop

Figure-2: Circular linked list, with S at the start of loop and F m nodes into the loop

 

Based on the discussion above, we already know that if S begins from the start of the loop and F starts from node m, they will meet m nodes from the end of the loop (i.e. the orange-node in [Figure-3]).

Figure-3: Both F and S meet m nodes from the end of the loop

Figure-3: Both F and S meet m nodes from the end of the loop

 

At this point, keep the pointer F at the orange-node where the two pointers met (i.e. m-nodes from the start of the loop), and move the pointer S to the beginning of the linked list [Figure-4]. Now, if we increment both S and F *one node at a time*, it is obvious that they will meet at ‘Node-m’ (red-node) of the list, which is the start of the loop.

Figure-4: S at the start of linked list, F at the point they met. Both increment one at a time from here-on

Figure-4: S at the start of linked list, F at the point they met. Both increment one at a time from here-on

 

For the curious, here’s the Java code snippets for detecting a loop in a linked list and finding the starting node. The complete source code for my linked list project is at my Github page (https://github.com/umairsd/LinkedList-Java):

	/**
	 * Checks if the given linked list is a circular linked list (i.e. it
	 * contains a loop). This means a list in which a node's next pointer points
	 * to an earlier node, so as to make a loop in the linked list. For
	 * instance:
	 * 			A -> B -> C -> D -> E -> C
	 *
	 * @param linkedList
	 *            the linked list to be tested
	 * @return true if there is a loop, false if there isn't
	 */
	public static boolean hasLoop(LinkedList linkedList) {
		if (linkedList == null || linkedList.getHead() == null) {
			return false;
		}

		IntegerNode slow = linkedList.getHead();
		IntegerNode fast = linkedList.getHead();

		while (true) {
			slow = slow.getNext();

			if (fast.getNext() != null) {
				fast = fast.getNext().getNext();
			} else {
				return false;
			}

			if (slow == null || fast == null) {
				return false;
			}

			if (slow == fast) {
				return true;
			}
		}
	}

 


	/**
	 * Returns the node at the start of a loop in the given circular linked
	 * list. A circular list is one in which a node's next pointer points
	 * to an earlier node, so as to make a loop in the linked list. For
	 * instance:
	 *
	 * input: A -> B -> C -> D -> E -> C [the same C as earlier]
	 * output: C
	 *
	 * (CCI_0205)
	 *
	 * @param linkedList
	 *            list to be tested
	 * @return the node at the start of the loop if there is a loop, null
	 * otherwise
	 */
	public static IntegerNode findLoopStart(LinkedList linkedList) {
		if (linkedList == null || linkedList.getHead() == null) {
			return null;
		}

		IntegerNode loopStartNode = null;
		IntegerNode slow = linkedList.getHead();
		IntegerNode fast = linkedList.getHead();

		while (slow != null && fast != null) {
			slow = slow.getNext();
			if (fast.getNext() == null) {
				loopStartNode = null;
				break;
			}
			fast = fast.getNext().getNext();

			// If slow and fast point to the same node, it means that the
			// linkedList contains a loop.
			if (slow == fast) {

				slow = linkedList.getHead();

				while (slow != fast) {
					// Keep incrementing the two pointers until they both
					// meet again. When this happens, both the pointers will
					// point to the beginning of the loop
					slow = slow.getNext(); // Can't be null, as we have a loop
					fast = fast.getNext(); // Can't be null, as we have a loop
				}

				loopStartNode = slow;
				break;
			}
		}

		return loopStartNode;
	}

31 Comments

Filed under Algorithms, Java

Stern-Brocot Tree

Stern-Brocot tree is a tree data structure whose vertices correspond to the set of non-negative rational numbers. Thus, this tree provides a very elegant way for constructing the set of fractions m/n, where m and n are relatively prime. To construct the tree, the basic idea is to start with two fractions (0/1, 1/0) and then repeat the following operation:

Insert (m+m’)/(n+n’) between two adjacent fractions m/n and m’/n’

The first step gives us the entry 1/1 between 0/1 and 1/0. Similarly, the 2nd step gives us two more: 0/1,1/2,1/1,2/1,1/0

Continuing on like this results in an infinite binary search tree which preserves the usual ordering of rational numbers.

The figure below shows the 1st 4 levels of the Stern-Brocot tree.

Stern-Brocot.png

Finding the Path to k in Stern-Brocot Tree

The path from the root of the tree to a number k in the Stern-Brocot tree can be found using binary search. At each node, k will either be in the left half of the tree, or the right half. We continue down the left or right subtree until we finally find k.

  • Initialize the left fraction L to 0/1 and right fraction R to 1/0
  • Repeat the following until k is found:
    • Compute the mediant M (which is (m+m’)/(n+n’) )
    • If (k>M), then k is in the right half of the tree. L:=M and continue.
    • Else If (M>k), then k is in the left half of the tree. R:=M and continue.
    • Else k=M, terminate search.

Implementation

There’s a couple of things to tackle in our implementation. First, I need an easy way to represent fractions, so I create my own SternBrocotFraction class. I deliberately chose to make it very specific to this algorithm because I needed a special way to handle the fraction 1/0 (which by definition is greater than all other rationals).

Secondly, I needed a good way to represent the path from the root of the tree to k. I do this by using a StringBuilder, and at each step I append either the letter ‘L’ or ‘R’ depending on which sub-tree we take. When the search is finished, this gives us a String representation of the path from the root of the tree to the number k. This approach is similar to the approach advocated by ACM Programming Competitions for the “Stern-Brocot Number System” problem.

Here’s the code to find path to a number k:

package com.umairsaeed.algorithm;

public class SternBrocotPath {
	private static final char LEFT_SUB = 'L';
	private static final char RIGHT_SUB = 'R';

	public String findPathTo(SternBrocotFraction f) {
		SternBrocotFraction L = new SternBrocotFraction(0, 1);
		SternBrocotFraction R = new SternBrocotFraction(1, 0);

		StringBuilder results = new StringBuilder();
		SternBrocotPath.find(f, L, R, results);
		return results.toString();
	}

	public static void find(SternBrocotFraction f,
			SternBrocotFraction L,
			SternBrocotFraction R,
			StringBuilder results)
	{
		SternBrocotFraction M = L.add(R);

		if (M.compareTo(f) < 0) {
			L = M;
			results.append(RIGHT_SUB);
			SternBrocotPath.find(f, L, R, results);
		} else if (M.compareTo(f) > 0) {
			R = M;
			results.append(LEFT_SUB);
			SternBrocotPath.find(f, L, R, results);
		}
		return;
	}
}

The special SternBrocotFraction class is:

package com.umairsaeed.algorithm;

public class SternBrocotFraction implements
				Comparable<SternBrocotFraction> {
	private int numerator;
	private int denominator;

	public SternBrocotFraction(int numerator, int denominator) {
		if (denominator < 0) {
			numerator *= -1;
			denominator *= -1;
		}

		this.numerator = numerator;
		this.denominator = denominator;
	}

	public double doubleValue() {
		if (this.denominator == 0) {
			return Double.MAX_VALUE;
		} else {
			return (double) this.numerator /
						(double) this.denominator;
		}
	}

	public SternBrocotFraction add(SternBrocotFraction other) {
		return new SternBrocotFraction(
				this.numerator + other.numerator,
				this.denominator + other.denominator);
	}

	public int compareTo(SternBrocotFraction other) {
		if (this.doubleValue() < other.doubleValue()) {
			return -1;
		} else if (this.doubleValue() > other.doubleValue()) {
			return 1;
		}
		return 0;
	}
}

Finally, some test code to exercise my class:

package com.umairsaeed.algorithm;

public class SternBrocotTester {
	public static void main(String[] args) {
		testSternBrocotPath();
	}

	public static void testSternBrocotPath() {
		SternBrocotPath t = new SternBrocotPath();

		SternBrocotFraction f = new SternBrocotFraction(5, 7);
		System.out.println(t.findPathTo(f));

		f = new SternBrocotFraction(19, 101);
		System.out.println(t.findPathTo(f));

		f = new SternBrocotFraction(977, 331);
		System.out.println(t.findPathTo(f));

		f = new SternBrocotFraction(1049, 7901);
		System.out.println(t.findPathTo(f));
	}
}

2 Comments

Filed under Algorithms

Java Enum Puzzler

Recently, I ran into an interesting bit of code related to Java enumerations. Here’s a contrived minimal sample:

/*
 * Some arbitrary resource type
 */
interface Resource {
	public Resource getResource();
}

enum A implements Resource{
	ALPHA (B.BRAVO);
	
	private Resource res;
	private A (Resource res){ this.res = res; }
	public Resource getResource(){ return res; }
}

enum B implements Resource{
	BRAVO (C.CHARLIE);

	private Resource res;
	private B (Resource res){ this.res = res; }
	public Resource getResource(){ return res; }

}

enum C implements Resource{
	CHARLIE (A.ALPHA);

	private Resource res;
	private C (Resource res){ this.res = res; }
	public Resource getResource(){ return res; }
}


class EnumTester{
	public static void main(String [] args){
		System.out.println(A.ALPHA.getResource());	
		System.out.println(B.BRAVO.getResource());	
		System.out.println(C.CHARLIE.getResource());
	}
}

When this code is run, an intuitive expectation is to see the following printed to the console:

BRAVO
CHARLIE
ALPHA

However, when I actually run the code we see:

BRAVO
CHARLIE
null

While this may seem a bit funky, the key is to understand what enum constants mean in Java. The key question to address is: “when is the constructor for an enumerated type invoked”. To answer this, it is helpful to remember that enum constants are implicitly public static final. Java guarantees that:

  • Static variables in a class are initialized before any object of that class can be created
  • Static variables in a class are initialized before any static method of the class runs

Knowing this, the behavior of the above code snippet becomes clearer. Here’s what happens in the main method:

  1. The fun happens at line 35, when we print   A.ALPHA.getResource(). Behind the scene, the class loader loads enumeration A into memory (i.e. initializes A).
  2. Once A is loaded into memory, the enum constant ALPHA gets created via call to the constructor where B.BRAVO is passed in as the argument.
  3. At this point, enumeration B is initialized and enum constant BRAVO gets created via a call to the constructor where C.CHARLIE is passed in as the argument.
  4. Same as before, now enumeration C is initialized (i.e. loaded into memory). Now here’s where things become interesting.
  5. Immediately after the initialization of C, we create the enum constant CHARLIE via a call to the constructor and pass in A.ALPHA as the argument. However, A.ALPHA has not been instantiated yet, and therefore enum constant CHARLIE gets null as the value of its resource instance variable. 

This means that once the statement A.ALPHA.getResource() is evaluated, A, B and C are all loaded into memory and all the corresponding enum constants have already been instantiated. Lines 35-37 simply then print the corresponding resources for each enum constant.

A Possible Solution

It is obvious that the entire problem stems from the cyclic dependency between A, B and C. Usually (but not always), this is an indication of a bad design choice and the fix is to simply get rid of the cyclic dependency. Assuming we want to keep the dependency, what are our options then?

Our solutions lies in Java's ability to allow instance-specific methods on enumerations. This is shown in the code below.

Running the following code with the EnumTester main method above will give us the results we wanted, without the problems caused by the previous approach.

enum A implements Resource{
	ALPHA { public Resource getResource() {return B.BRAVO; } };
	
	public abstract Resource getResource();
}

enum B implements Resource{
	BRAVO { public Resource getResource() { return C.CHARLIE; } };
	
	public abstract Resource getResource();
}

enum C implements Resource{
	CHARLIE { public Resource getResource() { return A.ALPHA; }};
	
	public abstract Resource getResource();
}

What do you think? Do you know of any other ways to resolve the cyclic dependency? Have you seen any other weirdness related to Java’s Enums?

4 Comments

Filed under Java, Programming