Sunday, December 1, 2013

Find Cycles In A Directed Graph (DAG)


In the mathematical theory of directed graphs, a graph is said to be strongly connected if every vertex is reachable from every other vertex. Wikipedia

  • The condensation of G is a directed acyclic graph that has a vertex for every strongly connected component of G and an edge for every two components that are connected by an edge in G. Wikipedia

  • An arbitrary directed graph may also be transformed into a DAG, called its condensation, by contracting each of its strongly connected components into a single supervertex. Wikipedia


    The strongly connected components of a directed graph may be found using an algorithm that uses depth-first search in combination with two stacks, one to keep track of the vertices in the current component and the second to keep track of the current search pathWikipedia


  • One of the best known algorithm to find the strongly connected component is Tarjan's strongly connected components algorithm. Wikipedia

  • The basic algorithm steps are:

  • 1. Start from any arbitrary vertex.

  • 2. DFS from that vertex. For each node x, keep two numbers, dfs_index[x] and dfs_lowval[x].
  • dfs_index[x] stores when that node is visited, while dfs_lowval[x] = min( dfs_low[k]) where
  • k is all the children of x that is not the directly parent of x in the dfs-spanning tree.

  • 3. All nodes with the same dfs_lowval[x] are in the same strongly connected component.



  • 	    public void strongConnect(AdjMatrixDirectGraph<T> graph, Vertex<T> start) {
    	        start.index = index;
    	        start.lowval = index;
    	        index++;
    	        stack.push(start);
    	         
    	        List<Vertex<T>> neighbors = graph.getNeighbors(start);
    	         
    	        for(int i = 0; i < neighbors.size(); i++) {
    	        	Vertex<T> neighbor = neighbors.get(i);
    	             
    	            if(neighbor.index == null) {
    	            	strongConnect(graph, neighbor);
    	            	start.lowval = Math.min(start.lowval, neighbor.lowval);
    	            }
    	            else if(stack.contains(neighbor)) {
    	            	start.lowval = Math.min(start.lowval, neighbor.index);
    	            }
    	        }
    	         
    	        if(start.lowval == start.index) {
    	            List<Vertex<T>> subset = new ArrayList<Vertex<T>>();
    	            Vertex<T> neighbor = null;
    	             
    	            while(start != neighbor) {
    	            	neighbor = stack.pop();
    	            	subset.add(neighbor);
    	            }
    	             
    	            set.add(subset);
    	        }
    	         
    	    }
    	}
    
    







  • From the strongly connected component, we can construct a separate DAG, from which we can find all cycles using modified Hierholzer's algorithm. 

  • The key of the algorithm is to have two stacks, the first one is for storing the forward path and the other is for backtracking. The backtracking is needed to cover unvisited edges for vertexes with multiple unvisited edges. 








  • 		public List<Edge<T>> findCycle(List<Edge<T>> prefix, Vertex<T> start) {
    			Stack<Edge<T>> forward =new Stack<Edge<T>>();
    			Stack<Edge<T>> backtrack =new Stack<Edge<T>>();
    			Edge<T> e = getUnvisitedEdge(start);
    			while (e!=null) {
    				e.visited=true;
    				forward.push(e);
    				e = getUnvisitedEdge(e.end);
    			}
    			
    			while ( ( !forward.isEmpty() ) ) {
    				e = forward.pop();
    				backtrack.push(e);
    			}
    
    			List<Edge<T>> path = new LinkedList<Edge<T>>();
    			if (prefix!=null) {
    				for (Edge<T> e1 : prefix) {
    					path.add(e1);
    				}
    			}
    			while(!backtrack.isEmpty()) {
    				Edge<T> edge = backtrack.pop();
    				path.add(edge);
    			}
    			return path;
    		}
    


    Here is the entire source code with a test case:
    package com.stones333.algorithm.graph;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Queue;
    import java.util.Stack;
    
    
    /**
     * Find all cycles in DAG
     * 
     * @author stones
     *
     */
    
    public class GraphFindCycles {
    	
    	static private class Vertex<T> {
    		public T label;
    		public boolean visited=false;
    		public Integer index=null;
    		public Integer lowval=null;
    		public Vertex(T n) {
    			this.label=n;
    		}
    		@Override
    		public String toString() {
    			return "Vertex-" + label;
    		}
    
    		@Override
    		public int hashCode() {
    			final int prime = 31;
    			int result = 1;
    			result = prime * result + ((label == null) ? 0 : label.hashCode());
    			result = prime * result + (visited ? 1231 : 1237);
    			return result;
    		}
    		@Override
    		public boolean equals(Object obj) {
    			if (this == obj) return true;
    			if (obj == null) return false;
    			if (getClass() != obj.getClass()) return false;
    			Vertex other = (Vertex) obj;
    			if (label == null) {
    				if (other.label != null) return false;
    			} else if (!label.equals(other.label)) return false;
    			if (visited != other.visited) return false;
    			return true;
    		}
    	}
    
    	static private class Edge<T> {
    		public Vertex<T> start;
    		public Vertex<T> end;
    		public boolean visited=false;
    		public Edge(Vertex<T> start, Vertex<T> end) {
    			this.start=start;
    			this.end=end;
    		}
    		@Override
    		public String toString() {
    			return "Edge [start=" + start + ", end=" + end + ", visited="
    					+ visited + "]";
    		}
    		
    	}
    
    	
    	static private interface GraphInterface<T> {
    		public void addVertex(Vertex<T> n) ;
    		public boolean isVertexExist(Vertex<T> vertex);
    		public void addEdge(Vertex<T> start, Vertex<T> end, double weight) ;
    		public Vertex<T> getUnvisitedChildren(Vertex<T> n);
    		
    	}
    
    	static private abstract class Graph<T> implements GraphInterface<T> {
    		
    		//DFS traversal of a tree is performed by the dfs() function
    		public void dfs(Vertex<T> start) {
    			//DFS uses Stack data structure
    			Stack<Vertex<T>> stack =new Stack<Vertex<T>>();
    			start.visited=true;
    			stack.push(start);
    			printNode(start);
    			while(!stack.isEmpty()) {
    				Vertex<T> n= stack.peek();
    				Vertex<T> child=getUnvisitedChildren(n);
    				if(child!=null) {
    					child.visited=true;
    					stack.push(child);
    					printNode(child);
    				} else {
    					stack.pop();
    				}
    			}
    		}
    
    		//BFS traversal of a graph is performed by the bfs() function
    		public void bfs(Vertex<T> start)
    		{
    			//BFS uses Queue data structure
    			Queue<Vertex<T>> que=new LinkedList<Vertex<T>>();
    			start.visited=true;
    			que.add(start);
    			printNode(start);
    			
    			while(!que.isEmpty()) {
    				Vertex<T> n=(Vertex<T>)que.remove();
    				Vertex<T> child=null;
    				while((child=getUnvisitedChildren(n))!=null) {
    					child.visited=true;
    					que.add(child);
    					printNode(child);
    				}
    			}
    		}
    
    
    		public void printNode(Vertex<T> n) {
    			System.out.print(n.label+" ");
    		}
    	}
    
    	static public class DirectedGraphFindAllPath<T>  {
    		List<Edge<T>> edges=new ArrayList<Edge<T>>();
    		List<Vertex<T>> vetexes=new ArrayList<Vertex<T>>();
    
    		
    		public DirectedGraphFindAllPath (StronglyConnectedTarjan<T> scc, Vertex<T> start) {
    			List<WeightedEdge<T>> edges = scc.findStrongConnectEdges (start);
    			for (WeightedEdge<T> edge : edges ) {
    				this.addEdge(edge.start, edge.end);
    			}
    		}
    		
    		public DirectedGraphFindAllPath<T> addVetex(Vertex<T> n) {
    			vetexes.add(n);
    			return this;
    		}
    
    		public boolean isVetexExist(Vertex<T> vetex) {
    			return ( vetexes.indexOf(vetex) >=0 ) ;
    		}
    
    		public boolean isAllEdgeVisited() {
    			for (Edge<T> e : edges) {
    				if (! e.visited) return false;
    			}
    			return true;
    		}
    
    
    		public List<List<Edge<T>>> findCycles(Vertex<T> start) {
    			List<List<Edge<T>>> pathes = new LinkedList<List<Edge<T>>>();
    			
    			List<Edge<T>> cycle = findCycle(null, start);
    			pathes.add(cycle);
    			
    			List<Edge<T>> current = new LinkedList<Edge<T>>();
    			for (Edge<T> edge : cycle ) {
    				current.add(edge);
    				if ( hasUnvisitedEdge (edge.end) ) {
    					List<Edge<T>> p = findCycle(current, edge.end);
    					pathes.add(p);
    				}
    			}
    			return pathes;
    		}
    
    		
    		/**
    		 * The key of the algorithm is to have two stacks, 
    		 * the first one is for storing the forward path and the other is for backtracking. 
    		 * The backtracking is needed to cover unvisited edges for vertexes with multiple edges. 
    		 * 
    		 * @param prefix
    		 * @param start
    		 * @return
    		 */
    		public List<Edge<T>> findCycle(List<Edge<T>> prefix, Vertex<T> start) {
    			Stack<Edge<T>> forward =new Stack<Edge<T>>();
    			Stack<Edge<T>> backtrack =new Stack<Edge<T>>();
    			Edge<T> e = getUnvisitedEdge(start);
    			while (e!=null) {
    				e.visited=true;
    				forward.push(e);
    				e = getUnvisitedEdge(e.end);
    			}
    			
    			while ( ( !forward.isEmpty() ) ) {
    				e = forward.pop();
    				backtrack.push(e);
    			}
    
    			List<Edge<T>> path = new LinkedList<Edge<T>>();
    			if (prefix!=null) {
    				for (Edge<T> e1 : prefix) {
    					path.add(e1);
    				}
    			}
    			while(!backtrack.isEmpty()) {
    				Edge<T> edge = backtrack.pop();
    				path.add(edge);
    			}
    			return path;
    		}
    		
    		/**
    		 * 1. Choose any starting vertex v, and follow a trail of edges from that vertex until returning to v. 
    		 * It is not possible to get stuck at any vertex other than v, because the even degree of all vertices ensures that, 
    		 * when the trail enters another vertex w there must be an unused edge leaving w. 
    		 * The tour formed in this way is a closed tour, but may not cover all the vertices and edges of the initial graph.
    		 * 
    		 * 2. As long as there exists a vertex v that belongs to the current tour but that has adjacent edges not part of the tour, 
    		 * start another trail from v, following unused edges until returning to v, 
    		 * and join the tour formed in this way to the previous tour. 
    		 * 
    		 * @param start
    		 * @return
    		 */
    		public List<Edge<T>> findHierholzerPath(Vertex<T> start) {
    			Stack<Edge<T>> forward =new Stack<Edge<T>>();
    			Stack<Edge<T>> backtrack =new Stack<Edge<T>>();
    			Edge<T> e = getUnvisitedEdge(start);
    			while (e!=null) {
    				e.visited=true;
    				forward.push(e);
    				e = getUnvisitedEdge(e.end);
    			}
    			
    			while ( ( !forward.isEmpty() ) ) {
    				e = forward.pop();
    				backtrack.push(e);
    				e = getUnvisitedEdge(e.start);
    				while (e!=null) {
    					e.visited = true;
    					forward.push(e);
    					e = getUnvisitedEdge(e.end);
    				}
    			}
    
    			List<Edge<T>> path = new LinkedList<Edge<T>>();
    			while(!backtrack.isEmpty()) {
    				Edge<T> edge = backtrack.pop();
    				path.add(edge);
    			}
    
    			return path;
    		}
    
    		public void printPath(List<Edge<T>> path) {
    			for (int i=0; i<path.size(); i++) {
    				System.out.print(path.get(i).start.label + "->" + path.get(i).end.label + " ");
    			}
    		}
    
    		public List<Edge<T>> findHierholzerPath(Vertex<T> start, Vertex<T> end) {
    
    			List<Edge<T>> path = findHierholzerPath(start);
    			if (path==null || path.size()==0) {
    				System.out.println ("No Eulerian path found!");
    			} else {
    				if ( path.get(path.size()-1).end == end ) {
    					System.out.println ("Eulerian path found:");
    					this.printPath(path);		
    				} else {
    					System.out.println ("No Eulerian path found!");
    				}
    			}
    			return path;
    		}
    
    
    		//This method will be called to make connect two nodes
    		public DirectedGraphFindAllPath<T> addEdge(Vertex<T> start, Vertex<T> end, int weight ) {
    			if ( ! isVetexExist(start) ) addVetex(start);
    			if ( ! isVetexExist(end) ) addVetex(end);
    			
    			Edge<T> edge = new Edge<T>(start, end);
    			edges.add(edge);
    			return this;
    		}
    
    		
    		//This method will be called to make connect two nodes
    		public DirectedGraphFindAllPath<T> addEdge(Vertex<T> start, Vertex<T> end) {
    			if ( ! isVetexExist(start) ) addVetex(start);
    			if ( ! isVetexExist(end) ) addVetex(end);
    			
    			Edge<T> edge = new Edge<T>(start, end);
    			edges.add(edge);
    			return this;
    		}
    		
    		public Vertex<T> getUnvisitedChildren(Vertex<T> n) {
    			for (Edge<T> e : edges) {
    				if ( e.visited==false && e.start.equals(n) ) {
    					e.visited=true;
    					return e.end;
    				}
    			}
    			return null;
    		}
    
    		public boolean hasUnvisitedEdge(Vertex<T> n) {
    			for (Edge<T> e : edges) {
    				if ( e.visited==false && e.start.equals(n) ) {
    					return true;
    				}
    			}
    			return false;
    		}
    
    		
    		public Edge<T> getUnvisitedEdge(Vertex<T> n) {
    			for (Edge<T> e : edges) {
    				if ( e.visited==false && e.start.equals(n) ) {
    					e.visited=true;
    					return e;
    				}
    			}
    			return null;
    		}
    
    		
    		public void clearNodes() {
    			for ( Edge<T> e : edges)
    				e.visited=false;
    			
    			for ( Vertex<T> v : vetexes)
    				v.visited=false;
    
    		}
    	}
    
    	static private class AdjMatrixDirectGraph<T> extends Graph<T> implements GraphInterface<T> {
    		public ArrayList<Vertex<T>> vertexes=new ArrayList<Vertex<T>>();
    		public double[][] adjMatrix;
    
    		
    		public void addVertex(Vertex<T> n) {
    			vertexes.add(n);
    		}
    
    		public boolean isVertexExist(Vertex<T> vertex) {
    			return ( vertexes.indexOf(vertex) >=0 ) ;
    		}
    		
    		public List<Vertex<T>> getVertexes () {
    			return vertexes;
    		}
    
    		public void addEdge(Vertex<T> start, Vertex<T> end) {
    			addEdge(start, end, 1);
    		}
    
    		
    		//This method will be called to make connect two nodes
    		public void addEdge(Vertex<T> start, Vertex<T> end, double weight) {
    			if ( ! isVertexExist(start) ) addVertex(start);
    			if ( ! isVertexExist(end) ) addVertex(end); 
    
    			if ( initAdjMatrix() ) {
    				int startIndex=vertexes.indexOf(start);
    				int endIndex=vertexes.indexOf(end);
    				if (startIndex>=0 && endIndex>=0) {
    					adjMatrix[startIndex][endIndex]=weight;
    				}
    			}
    		}
    
    		public boolean initAdjMatrix() {
    			if (vertexes.size()<=0) return false;
    			adjMatrix=buildAdjMatrix(adjMatrix, vertexes.size());
    			return true;
    		}
    
    		private double [][] buildAdjMatrix(double[][] prevMatrix, int newSize) {
    			if (newSize==0) return null;
    			double[][] matrix=new double[newSize][newSize];
    			
    			for (int i=0; i<newSize; i++) 
    				for (int j=0; j<newSize; j++) 
    					matrix[i][j] = Double.POSITIVE_INFINITY;
    
    			if (prevMatrix!=null) {
    				for (int i=0; i<prevMatrix.length; i++) 
    					for (int j=0; j<prevMatrix[i].length; j++) 
    						matrix[i][j] = prevMatrix[i][j];
    			}
    			return matrix;
    		}
    		
    		
    		public List<Vertex<T>> getNeighbors(Vertex<T> n) {
    			List<Vertex<T>> list = new ArrayList <Vertex<T>>();
    			int index=vertexes.indexOf(n);
    			for (int j=0; j<vertexes.size(); j++) {
    				if( adjMatrix[index][j]!=Double.POSITIVE_INFINITY ) {
    					list.add((Vertex<T>)vertexes.get(j));
    				}
    			}
    			return list;
    		}
    		
    		public Vertex<T> getUnvisitedChildren(Vertex<T> n) {
    			
    			int index=vertexes.indexOf(n);
    			int j=0;
    			while(j<vertexes.size()) {
    				if( adjMatrix[index][j]!=Double.POSITIVE_INFINITY && vertexes.get(j).visited==false ) {
    					return (Vertex<T>)vertexes.get(j);
    				}
    				j++;
    			}
    			return null;
    		}
    
    		public List<WeightedEdge<T>> getEdges(Vertex<T> n) {
    			
    			List<WeightedEdge<T>> edges = new LinkedList<WeightedEdge<T>>();
    			int index=vertexes.indexOf(n);
    			int j=0;
    			while(j<vertexes.size()) {
    				if( adjMatrix[index][j]!=Double.POSITIVE_INFINITY  ) {
    					edges.add(new WeightedEdge<T> (n, vertexes.get(j),  adjMatrix[index][j]) );
    				}
    				j++;
    			}
    			return edges;
    		}
    
    		public List<WeightedEdge<T>> getEdges() {
    			List<WeightedEdge<T>> edges = new LinkedList<WeightedEdge<T>>();
    			for (int i=0; i<adjMatrix.length; i++) {
    				for (int j=0; j<adjMatrix[i].length; j++) {
    					if( adjMatrix[i][j]!=Double.POSITIVE_INFINITY  ) {
    						edges.add(new WeightedEdge<T> (vertexes.get(i), vertexes.get(j),  adjMatrix[i][j]) );
    					}
    				}
    			}
    			return edges;
    		}
    
    
    		public void printVertexes() {
    			for (int i=0; i<vertexes.size(); i++ ) {
    				System.out.print(vertexes.get(i) + " " );
    			}
    			System.out.println();
    		}
    
    		
    		
    		//Utility methods for clearing visited property of node
    		public void clearNodes() {
    			int i=0;
    			while(i<vertexes.size()) {
    				vertexes.get(i).visited=false;
    				i++;
    			}
    		}
    		
    	}
    
    	static private class WeightedEdge<T>  extends  Edge<T> {
    		public final double weight;
    		public boolean visited=false;
    		public WeightedEdge(Vertex<T> start, Vertex<T> end, double weight) {
    			super(start, end);
    			this.weight=weight;
    		}
    		
    
    		public int compareTo(WeightedEdge<T> that) {
    			if (this.weight < that.weight) 
    				return -1;
    			else if (this.weight > that.weight) 
    				return +1;
    			else 
    				return 0;
    		 }
    
    		@Override
    		public String toString() {
    			return "WeightedEdge [start=" + start + ", end=" + end
    					+ ", weight=" + weight + ", visited=" + visited + "]";
    		}
    	}
    
    	
    	static public class StronglyConnectedTarjan<T> {
    		public AdjMatrixDirectGraph<T> graph;
    		public int index;
    	    public Stack<Vertex<T>> stack;
    	    public List<List<Vertex<T>>> set;
    
    	    public void printConnected () {
    	    	  for(int i = 0; i < set.size(); i++) {
    	              System.out.println("Set " + i + ": " + Arrays.toString(set.get(i).toArray()));
    	    	  }
    	    }
    
    	    public StronglyConnectedTarjan(AdjMatrixDirectGraph<T> graph) {
    	    	this.graph = graph;
    	    	stack = new Stack<Vertex<T>> ();
    	    	set = new ArrayList<List<Vertex<T>>> ();
    	    	
    	    	for( Vertex<T> node : graph.vertexes) {
    	            if(node.index == null) 
    	            	strongConnect(graph, node);
    	        }
    	    }
    	    
    	    public List<WeightedEdge<T>> findStrongConnectEdges (Vertex<T> node) {
    	    	List<WeightedEdge<T>> edges = new ArrayList<WeightedEdge<T>>();
    	    	 for (List<Vertex<T>> c : set) {
    	    		 if ( c.contains(node) ) {
    	    			 for (int i=0; i<graph.adjMatrix.length; i++) {
    	    				 for (int j=0; j<graph.adjMatrix[i].length; j++) {
    	    					
    	    						if( graph.adjMatrix[i][j]!=Double.POSITIVE_INFINITY 
    	    								&& c.contains(graph.vertexes.get(i)) 
    	    								&& c.contains(graph.vertexes.get(j)) ) {
    	    							edges.add(new WeightedEdge<T> (graph.vertexes.get(i), graph.vertexes.get(j),  graph.adjMatrix[i][j]) );
    	    						}
    
    	    				 }
    	    			 }
    	    		 }
    	    	 }
    	    	
    	    	
    	    	return edges;
    	    }
    	    
    
    	    /**
    	     *
    	     * 1. Start from any arbitrary vertex.
    	     * 
    	     * 2. DFS from that vertex. For each node x, keep two numbers, dfs_index[x] and dfs_lowval[x]. 
    	     * dfs_index[x] stores when that node is visited, while dfs_lowval[x] = min( dfs_low[k]) where 
    	     * k is all the children of x that is not the directly parent of x in the dfs-spanning tree.
    	     * 
    	     * 3. All nodes with the same dfs_lowval[x] are in the same strongly connected component.
    	     * 
    	     * @param graph
    	     * @param start
    	     */
    	    public void strongConnect(AdjMatrixDirectGraph<T> graph, Vertex<T> start) {
    	        start.index = index;
    	        start.lowval = index;
    	        index++;
    	        stack.push(start);
    	         
    	        List<Vertex<T>> neighbors = graph.getNeighbors(start);
    	         
    	        for(int i = 0; i < neighbors.size(); i++) {
    	        	Vertex<T> neighbor = neighbors.get(i);
    	             
    	            if(neighbor.index == null) {
    	            	strongConnect(graph, neighbor);
    	            	start.lowval = Math.min(start.lowval, neighbor.lowval);
    	            }
    	            else if(stack.contains(neighbor)) {
    	            	start.lowval = Math.min(start.lowval, neighbor.index);
    	            }
    	        }
    	         
    	        if(start.lowval == start.index) {
    	            List<Vertex<T>> subset = new ArrayList<Vertex<T>>();
    	            Vertex<T> neighbor = null;
    	             
    	            while(start != neighbor) {
    	            	neighbor = stack.pop();
    	            	subset.add(neighbor);
    	            }
    	             
    	            set.add(subset);
    	        }
    	         
    	    }
    	}
    
    	public static void main(String[] args) {
    		System.out.println("testFindCycle -->");
    		testFindCycle();
    
    	}
    
    	private static void testFindCycle() {
    		Vertex<String> nA = new Vertex<String>("A");
    		Vertex<String> nB = new Vertex<String>("B");
    		Vertex<String> nC = new Vertex<String>("C");
    		Vertex<String> nD = new Vertex<String>("D");
    		Vertex<String> nE = new Vertex<String>("E");
    		Vertex<String> nF = new Vertex<String>("F");
    		Vertex<String> nG = new Vertex<String>("G");
    		Vertex<String> nH = new Vertex<String>("H");
    
    		//Create the graph, add nodes, create edges between nodes
    		AdjMatrixDirectGraph<String> g=new AdjMatrixDirectGraph<String>();
    		
    		g.addEdge(nA, nB); g.addEdge(nB, nC); g.addEdge(nC, nA); g.addEdge(nB, nA); 
    		g.addEdge(nD, nB); g.addEdge(nD, nC); g.addEdge(nD, nF);
    		g.addEdge(nF, nD); g.addEdge(nE, nC);
    		g.addEdge(nE, nG); g.addEdge(nG, nE);
    		g.addEdge(nH, nF); g.addEdge(nH, nH);
    
    		StronglyConnectedTarjan<String> scc = new StronglyConnectedTarjan<String>(g);
    //		scc.printConnected();
    //	    List<WeightedEdge<String>> edges = scc.findStrongConnectEdges (nA);
    //	    for (WeightedEdge<String> e: edges) {
    //	    	System.out.println(e);
    //	    }
    	    
    	    DirectedGraphFindAllPath<String> findCycle = new DirectedGraphFindAllPath<String> (scc, nA);
    		List<List<Edge<String>>> pathes = findCycle.findCycles(nA);
    		for (List<Edge<String>> path : pathes) {
    			System.out.println("");
    			System.out.print("cycle: ");
    			findCycle.printPath(path);
    		}
    
    		
    	}
    
    
    }
    
    
    
    


    The graph edges are
    (nA, nB), (nB, nC), (nC, nA), addEdge(nB, nA); (nD, nB), (nD, nC), (nD, nF); (nF, nD), (nE, nC), (nE, nG); (nG, nE), (nH, nF), (nH, nH);

    The output:
    cycle: A->B B->A 
    cycle: A->B B->C C->A 
    

    Enjoy the journey, have fun.

    Tuesday, November 19, 2013

    Find Eulerian Path In A Directed Graph

    An Eulerian path is a trail in a graph which visits every edge exactly once. There are many problems are in the category of finding Eulerian path. For example, given a stack of airplane (bus) ticket stubs, reconstruct the travel journey assuming we know where the journey starts.

    Hierholzer's algorithm is an elegant and efficient algorithm. It takes linear time.

    • Choose any starting vertex v, and follow a trail of edges from that vertex until returning to v. It is not possible to get stuck at any vertex other than v, because the even degree of all vertices ensures that, when the trail enters another vertex w there must be an unused edge leaving w. The tour formed in this way is a closed tour, but may not cover all the vertices and edges of the initial graph.

    • As long as there exists a vertex v that belongs to the current tour but that has adjacent edges not part of the tour, start another trail from v, following unused edges until returning to v, and join the tour formed in this way to the previous tour.

    The key of the algorithm is to have 2 stacks, the first one is for storing the forward path and the other is for backtracking. We need the backtracking to cover unvisited edges for vertexes with multiple edges.

        public List<Edge<T>> findHierholzerPath(Vertex<T> start) {
       Stack<Edge<T>> forward =new Stack<Edge<T>>();
       Stack<Edge<T>> backtrack =new Stack<Edge<T>>();
       Edge<T> e = getUnvisitedEdge(start);
       while (e!=null) {
        e.visited=true;
        forward.push(e);
        e = getUnvisitedEdge(e.end);
       }
       
       while ( ( !forward.isEmpty() ) ) {
        e = forward.pop();
        backtrack.push(e);
        e = getUnvisitedEdge(e.start);
        while (e!=null) {
         e.visited = true;
         forward.push(e);
         e = getUnvisitedEdge(e.end);
        }
       }
    
       List<Edge<T>> path = new LinkedList<Edge<T>>();
       while(!backtrack.isEmpty()) {
        Edge<T> edge = backtrack.pop();
        path.add(edge);
       }
    
       return path;
      }
    
    
    



    Here is the source code in it entirety with test cases:
    package com.stones333.algorithm;
    
    import java.util.ArrayList;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Queue;
    import java.util.Stack;
    
    /**
     * Java implementation of Hierholzer's algorithm to find an Eulerian path in a directed graph 
     * 
     * http://en.wikipedia.org/wiki/Eulerian_path
     * 
     * @author stones333
     *
     */
    public class EulerianPath {
     
     static private class Vertex<T> {
      public T label;
      public boolean visited=false;
      public Vertex(T n) {
       this.label=n;
      }
     }
    
     static private class Edge<T> {
      public Vertex<T> start;
      public Vertex<T> end;
      public boolean visited=false;
      public Edge(Vertex<T> start, Vertex<T> end) {
       this.start=start;
       this.end=end;
      }
     }
    
     
     static private interface GraphInterface<T> {
      public Graph addVetex(Vertex<T> n) ;
      public boolean isVetexExist(Vertex<T> vetex);
      public Graph addEdge(Vertex<T> start, Vertex<T> end) ;
      public Vertex<T> getUnvisitedChildren(Vertex<T> n);
      
     }
     
     static private abstract class Graph<T> implements GraphInterface<T> {
    
      
      //DFS traversal of a tree is performed by the dfs() function
      public void dfs(Vertex<T> start) {
       //DFS uses Stack data structure
       Stack<Vertex<T>> stack =new Stack<Vertex<T>>();
       start.visited=true;
       stack.push(start);
       printNode(start);
       while(!stack.isEmpty()) {
        Vertex<T> n= stack.peek();
        Vertex<T> child=getUnvisitedChildren(n);
        if(child!=null) {
         child.visited=true;
         stack.push(child);
         printNode(child);
        } else {
         stack.pop();
        }
       }
      }
    
      //BFS traversal of a graph is performed by the bfs() function
      public void bfs(Vertex<T> start)
      {
       //BFS uses Queue data structure
       Queue<Vertex<T>> que=new LinkedList<Vertex<T>>();
       start.visited=true;
       que.add(start);
       printNode(start);
       
       while(!que.isEmpty()) {
        Vertex<T> n=(Vertex<T>)que.remove();
        Vertex<T> child=null;
        while((child=getUnvisitedChildren(n))!=null) {
         child.visited=true;
         que.add(child);
         printNode(child);
        }
       }
      }
    
      public void printPath(List<Edge<T>> path) {
       for (int i=0; i<path.size(); i++) {
        System.out.print(path.get(i).start.label + "->" + path.get(i).end.label + " ");
       }
      }
      
      public void printEdge(Edge<T> e) {
       System.out.print(e.start.label + "->" + e.end.label );
      }
    
      public void printNode(Vertex<T> n) {
       System.out.print(n.label+" ");
      }
     }
    
     
     static private class DirectedGraph<T> extends Graph<T> implements GraphInterface<T> {
      List<Edge<T>> edges=new ArrayList<Edge<T>>();
      List<Vertex<T>> vetexes=new ArrayList<Vertex<T>>();
    
      public Graph addVetex(Vertex<T> n) {
       vetexes.add(n);
       return this;
      }
    
      public boolean isVetexExist(Vertex<T> vetex) {
       return ( vetexes.indexOf(vetex) >=0 ) ;
      }
    
      public boolean isAllEdgeVisited() {
       for (Edge<T> e : edges) {
        if (! e.visited) return false;
       }
       return true;
      }
    
      public List<Edge<T>> findHierholzerPath(Vertex<T> start) {
       Stack<Edge<T>> forward =new Stack<Edge<T>>();
       Stack<Edge<T>> backtrack =new Stack<Edge<T>>();
       Edge<T> e = getUnvisitedEdge(start);
       while (e!=null) {
        e.visited=true;
        forward.push(e);
        e = getUnvisitedEdge(e.end);
       }
       
       while ( ( !forward.isEmpty() ) ) {
        e = forward.pop();
        backtrack.push(e);
        e = getUnvisitedEdge(e.start);
        while (e!=null) {
         e.visited = true;
         forward.push(e);
         e = getUnvisitedEdge(e.end);
        }
       }
    
       List<Edge<T>> path = new LinkedList<Edge<T>>();
       while(!backtrack.isEmpty()) {
        Edge<T> edge = backtrack.pop();
        path.add(edge);
       }
    
       return path;
      }
    
      public List<Edge<T>> findHierholzerPath(Vertex<T> start, Vertex<T> end) {
    
       List<Edge<T>> path = findHierholzerPath(start);
       if (path==null || path.size()==0) {
        System.out.println ("\nNo Eulerian path found!");
       } else {
        if ( path.get(path.size()-1).end == end ) {
         System.out.println ("\nEulerian path found:");
         this.printPath(path);  
        } else {
         System.out.println ("\nNo Eulerian path found!");
        }
       }
       return path;
      }
    
    
    
      //This method will be called to make connect two nodes
      public Graph addEdge(Vertex<T> start, Vertex<T> end) {
       if ( ! isVetexExist(start) ) addVetex(start);
       if ( ! isVetexExist(end) ) addVetex(end);
       
       Edge<T> edge = new Edge<T>(start, end);
       edges.add(edge);
       return this;
      }
      
      public Vertex<T> getUnvisitedChildren(Vertex<T> n) {
       for (Edge<T> e : edges) {
        if ( e.visited==false && e.start.equals(n) ) {
         e.visited=true;
         return e.end;
        }
       }
       return null;
      }
    
      public Edge<T> getUnvisitedEdge(Vertex<T> n) {
       for (Edge<T> e : edges) {
        if ( e.visited==false && e.start.equals(n) ) {
         e.visited=true;
         return e;
        }
       }
       return null;
      }
    
      
      public void clearNodes() {
       for ( Edge<T> e : edges)
        e.visited=false;
       
       for ( Vertex<T> v : vetexes)
        v.visited=false;
    
      }
     }
     
     private static void testEulerianPathCase2() {
      //Lets create nodes as given as an example in the article
      Vertex<String> nA=new Vertex<String>("A"), nB=new Vertex<String>("B");
      Vertex<String> nC=new Vertex<String>("C"), nD=new Vertex<String>("D");
      Vertex<String> nE=new Vertex<String>("E"), nF=new Vertex<String>("F");
    
    
      DirectedGraph<String> g=new DirectedGraph<String>();
      
      g.addEdge(nA,nB); g.addEdge(nB,nC); g.addEdge(nC,nD); g.addEdge(nD,nE);
      g.addEdge(nB,nC); g.addEdge(nC,nF); g.addEdge(nF,nB);
      List<Edge<String>> path = g.findHierholzerPath(nA, nE);
     }
    
     private static void testEulerianPathCase1() {
      Vertex<String> nA=new Vertex<String>("A"), nB=new Vertex<String>("B");
      Vertex<String> nC=new Vertex<String>("C"), nD=new Vertex<String>("D");
      DirectedGraph<String> g=new DirectedGraph<String>();
    
      g.addEdge(nA,nB).addEdge(nB,nC).addEdge(nC,nD).addEdge(nD,nA).addEdge(nA,nC);
      
      List<Edge<String>> path = g.findHierholzerPath(nA, nC);
     }
    
     private static void testNegEulerianPathCase1() {
      Vertex<String> nA=new Vertex<String>("A"), nB=new Vertex<String>("B");
      Vertex<String> nC=new Vertex<String>("C"), nD=new Vertex<String>("D");
      DirectedGraph<String> g=new DirectedGraph<String>();
      
      g.addEdge(nA,nB).addEdge(nB,nC).addEdge(nC,nD).addEdge(nD,nA).addEdge(nA,nC);
      
      List<Edge<String>> path = g.findHierholzerPath(nA, nD);
     }
     
     public static void main(String[] args) {
    
      System.out.println ("\ntestEulerianPathCase1:");
      testEulerianPathCase1();
      
      System.out.println ("\ntestNegEulerianPathCase1:");
      testNegEulerianPathCase1();
      
      System.out.println ("\ntestEulerianPathCase2:");
      testEulerianPathCase2();
     }
    
    }
    
    
    
    


    Have fun and enjoy the journey.

    Monday, October 28, 2013

    Algorithms to sort negative and positive integer array

    Here is the problem: Given an array with n integers, which has both positive and negative integers. Sort the array in the way that, the negatives are placed before positives.

    i.e.

    Input :    [-1, 2, 1, 12, -9, 3, -4, 4, -3, 21, 52, 4, -2]
    Output : [-1, -9, -4, -3, -2, 2, 1, 12, 3, 4, 21, 52, 4]

    We will consider the following:
    1. Time complexity
    2. Space requirement
    3. Stability 

    If we treat negative numbers as 0 and positive numbers as 1, this is a 0-1 sorting problem.


    Algorithm 1: Loop through the array from both ends, swap negatives with positives if they are misplaced. 


    Time Complexity: O(N)
    Space Requirement: O(1)
    But not stable. 



       
    static public class NegativePositiveSwapSorter extends NegativePositiveBaseSorter implements Sorter {
    
      public void sort(int[] a) {
       if (a==null || a.length<=1)
        return;
    
       int i = 0, j = a.length-1;
       while (i<=j) {
        while (a[i]<0 && i<=j) i++;
        while (a[j]>0 && i<=j) j--;
        if (i<j ) swap(a, i, j);
        i++;
        j--;
       }
      }
     }
    
    
    


    Algorithm 2: Loop through the array, count the number of negatives (z). Scan the array the second time, and maintain two counters c0 and c1. c0 counting the number of negatives and c1 sums up the number positives to the left of the current position.

    If a[i]<0, final position is (a[i]<0 ? 0 : 1 ) * z + c0
    If a[i]<0, final position is (a[i]<0 ? 0 : 1 ) * z + c1

    Time Complexity: O(N)
    Space Requirement: O(N)
    Stable  



       static public class NegativePositiveCountSorter extends NegativePositiveBaseSorter implements Sorter {
    
      public void sort(int[] a) {
       if (a==null || a.length<=1) return;
       
       // z is count of negatives  
       int z=0;
       for (int i=0; i<a.length; i++) {
        if (a[i]<0) z++;
       }
       int c0=0, c1=0;
       
       int [] c = new int[a.length];
       for (int i=0; i<a.length; i++) {
        int idx=0;
        if (a[i]<0) {
         idx= (a[i]<0 ? 0 : 1 ) * z + c0;
         c0++;
        } else {
         idx= (a[i]<0 ? 0 : 1 )  * z + c1;
         c1++;
        }
        c[idx] = a[i];
       }
    
       System.arraycopy(c, 0, a, 0, a.length);
      }
     }
    
    
    
    



    Algorithm 3: Loop through the array, and swap negative number block and positive number block with rotating (Juggling)

    Time Complexity: O( N0 x N1 ) 
    Space Requirement: O(1)
    Stable  




        
    
     static public class NegativePositiveSorterViaRotationWithJuggling extends NegativePositiveBaseSorter implements Sorter {
    
    
      public void sort(int[] a) {
       if (a==null || a.length<=1)
        return;
    
       int start = 0, mid=0, end=0, num = 1;
       do {
        start = skipNegBlock(a, start);
        mid = skipPosBlock(a, end==0? start : end);
        end = skipNegBlock(a, mid);
        num = rotateleftByJuggling(a, start, mid-start, end-start);
       } while (num>0);
      }
     }
    
    
    
    
    


    Here is the transformation:


    Step: 1 Array: [-1, 2, 1, 12, -9, 3, -4, 4, -3, 21, 52, 4, -2]
    Step: 2 Array: [-1, -9, 2, 1, 12, 3, -4, 4, -3, 21, 52, 4, -2]
    Step: 3 Array: [-1, -9, -4, 2, 1, 12, 3, 4, -3, 21, 52, 4, -2]
    Step: 4 Array: [-1, -9, -4, -3, 2, 1, 12, 3, 4, 21, 52, 4, -2]
    Step: 5 Array: [-1, -9, -4, -3, -2, 2, 1, 12, 3, 4, 21, 52, 4]

    Step: 6 Array: [-1, -9, -4, -3, -2, 2, 1, 12, 3, 4, 21, 52, 4]



    Algorithm 4: Loop through the array, and swap negative number block and positive number block with double reverse
    Time Complexity: O( N0 * N1 )
    Space Requirement: O(1)
    Stable  


        
    
     static public class NegativePositiveSorterViaBlockSwapWithReverse extends NegativePositiveBaseSorter implements Sorter {
    
      public void sort(int[] a) {
       if (a==null || a.length<=1)
        return;
       
       int start = 0, mid=0, end=0, num = 1;
       do {
        start = skipNegBlock(a, start);
        mid = skipPosBlock(a, end==0? start : end);
        end = skipNegBlock(a, mid);
        num = swapBlockWithReverse(a, start, mid, end);
       } while (num>0);
      }
     }
    
    
    



    Here is the transformation: 
    Step: 1 Array: [-1, 2, 1, 12, -9, 3, -4, 4, -3, 21, 52, 4, -2]
    Step: 2 Array: [-1, -9, 2, 1, 12, 3, -4, 4, -3, 21, 52, 4, -2]
    Step: 3 Array: [-1, -9, -4, 2, 1, 12, 3, 4, -3, 21, 52, 4, -2]
    Step: 4 Array: [-1, -9, -4, -3, 2, 1, 12, 3, 4, 21, 52, 4, -2]
    Step: 5 Array: [-1, -9, -4, -3, -2, 2, 1, 12, 3, 4, 21, 52, 4]
    Step: 6 Array: [-1, -9, -4, -3, -2, 2, 1, 12, 3, 4, 21, 52, 4]



    Algorithm 5: Loop through the array, Loop through the array, and swap negative number block and positive number block with rotating. 

    Time Complexity: O( n log(n) )
    Space Requirement: O(1)
    Stable  




     
      public void sort(int[] a) {
       if (a==null || a.length<=1)
        return;
    
       int start = 0, mid=0, end=0, num = 1;
       do {
        start = skipNegBlock(a, start);
        mid = skipPosBlock(a, end==0? start : end);
        end = skipNegBlock(a, mid);
        num = rotateleft(a, start, mid-start, end-start);
       } while (num>0);
      }
    


    Here is the transformation: 
    Step: 1 Array: [-1, 2, 1, 12, -9, 3, -4, 4, -3, 21, 52, 4, -2]
    Step: 2 Array: [-1, -9, 2, 1, 12, 3, -4, 4, -3, 21, 52, 4, -2]
    Step: 3 Array: [-1, -9, -4, 2, 1, 12, 3, 4, -3, 21, 52, 4, -2]
    Step: 4 Array: [-1, -9, -4, -3, 2, 1, 12, 3, 4, 21, 52, 4, -2]
    Step: 5 Array: [-1, -9, -4, -3, -2, 2, 1, 12, 3, 4, 21, 52, 4]
    Step: 6 Array: [-1, -9, -4, -3, -2, 2, 1, 12, 3, 4, 21, 52, 4]

    Here is the entire source code:

     
    
    package com.lei.algorithm;
    
    import java.util.Arrays;
    
    /**
     *
     * Algorithms to sort negatives in front of positives for an integer array
     * 
     * @author stones333
     *
     */
    public class NegativePositiveIntergerSorter {
    
    
     /**
      * Sorter interface
      *
      */
     static public interface Sorter {
      void sort(int[] a);
      void print(int[] a);
     }
    
     /**
      * Base class for Sorter with utility methods   
      * 
      * @author stones333
      *
      */
     static public abstract class NegativePositiveBaseSorter implements Sorter {
      
      /**
       * swap array item position i and j
       *  
       * @param a
       * @param i
       * @param j
       */
      public void swap(int[] a, int i, int j) {
       a[i] = a[i] + a[j];
       a[j] = a[i] - a[j];
       a[i] = a[i] - a[j];
      }
    
      /**
       * reverse the array a[] between position i and j. 
       * @param a
       * @param i, inclusive 
       * @param j, exclusive 
       */
      public void reverse(int[] a, int i, int j) {
       while (i<j) {
        swap(a, i, j);
        i++;
        j--;
       }
      }
    
      /**
       * advance array index by n position.  
       * 
       * @param a
       * @param start
       * @param n
       * @return
       */
      public int advance(int[] a, int start, int n) {
       return ( (start+n)>a.length) ? a.length : (start+n);
      }
    
      /**
       * 
       * swap array block of n item starting from position i and j
       * 
       * @param a
       * @param i
       * @param j
       * @param n
       */
      public void swap(int[] a, int i, int j, int n) {
       if (i==j|| n==0) return;
       for (;n>0; n--) 
        swap(a, i++, j++);
    
      }
    
      
      /**
       * skip the negative block until positive number
       * 
       * @param a
       * @param begin
       * @return
       */
      public int skipNegBlock(int[] a, int begin) {
       int start=begin;
       while (start<a.length && a[start]<0 ) start++;
       return start;
      }
    
      /**
       * skip the positive block until negative  number
       * 
       * @param a
       * @param begin
       * @return
       */
      public int skipPosBlock(int[] a, int begin) {
       int start=begin;
       while (start<a.length && a[start]>0 ) start++;
       return start;
      }
      
      /**
       * swap the blocks, the first from start to mid-1, with the second from mid to end-1 
       * 
       * @param a
       * @param start
       * @param mid
       * @param end
       * @return
       */
      public int swapBlockWithReverse(int[] a, int start, int mid, int end) {
       reverse(a, start, mid-1);
       reverse(a, mid, end-1);
       reverse(a, start, end-1);
       return end-mid;
      }
    
      public void pickAndSwapBlock(int[] a, int start, int mid, int end) {
       
       while (start<mid && a[start]<0 ) start++;
       int start2=mid;
       while (start2<end && a[start2]<0 ) start2++;
       if (start<=mid && start2>=mid && start2<=end) {
        swapBlockWithReverse(a, start, mid, start2);
       }
      }
    
    
      /**
       * print the array content 
       * 
       * @param a
       */
      public void print(int[] a) {
       System.out.println( "Array: " + Arrays.toString(a) );
      }
    
      
      /**
       * print the array content with step number 
       * 
       * @param step
       * @param a
       */
      public void print(int step, int[] a) {
       System.out.println( "Step: " + step + " Array: " + Arrays.toString(a) );
      }
    
     }
     
     
     /**
      *
      * Algorithm 1: Loop through the array from both ends, swap negatives with positives if they are misplaced.
      * 
      * Time Complexity: O(N)
      * Space Requirement: O(1)
      * Not stable  
      * 
      * @author stones333
      *
      */
     static public class NegativePositiveSwapSorter extends NegativePositiveBaseSorter implements Sorter {
    
      public void sort(int[] a) {
       if (a==null || a.length<=1)
        return;
    
       int i = 0, j = a.length-1;
       while (i<=j) {
        while (a[i]<0 && i<=j) i++;
        while (a[j]>0 && i<=j) j--;
        if (i<j ) swap(a, i, j);
        i++;
        j--;
       }
      }
     }
     
    
     /**
      *
      * Algorithm 2: Loop through the array, count the number of negatives (z). Scan the array the second time, and maintain two counters c0 and c1. 
      * c0 counting the number of negatives and c1 sums up the number positives to the left of the current position.
      *
      * If a[i]<0, final position is (a[i]<0 ? 0 : 1 ) * z + c0
      * If a[i]<0, final position is (a[i]<0 ? 0 : 1 ) * z + c1
      * 
      * 
      * Time Complexity: O(N)
      * Space Requirement: O(N)
      * Stable  
      * 
      * @author stones333
      *
      */
     static public class NegativePositiveCountSorter extends NegativePositiveBaseSorter implements Sorter {
    
      public void sort(int[] a) {
       if (a==null || a.length<=1) return;
       
       // z is count of negatives  
       int z=0;
       for (int i=0; i<a.length; i++) {
        if (a[i]<0) z++;
       }
       int c0=0, c1=0;
       
       int [] c = new int[a.length];
       for (int i=0; i<a.length; i++) {
        int idx=0;
        if (a[i]<0) {
         idx= (a[i]<0 ? 0 : 1 ) * z + c0;
         c0++;
        } else {
         idx= (a[i]<0 ? 0 : 1 )  * z + c1;
         c1++;
        }
        c[idx] = a[i];
       }
    
       System.arraycopy(c, 0, a, 0, a.length);
      }
     }
    
     /**
      *
      * Algorithm 3: Loop through the array, and swap negative number block and positive number block with rotating (Juggling)
      * 
      * Time Complexity: O( N0 x N1 ) 
      * Space Requirement: O(1)
      * Stable  
      * 
      * @author stones333
      *
      */
     static public class NegativePositiveSorterViaRotationWithJuggling extends NegativePositiveBaseSorter implements Sorter {
    
      /**
       * return gcd of i and j
       * 
       * @param i
       * @param j
       * @return
       */
      public int gcd( int i, int j ) {
       if ( i == 0 ) return j;
       if ( j == 0 ) return i;
       while ( i != j ) {
        if ( i > j ) 
               i -= j;
              else        
               j -= i;
       }
       return i;
      }
    
      /**
       * 
       * rotates array a[] of size n by d elements, start from position st
       * 
       * Steps: 
       * 1. A is the left subarray, B is the right subarray — that is, the starting point is AB
       * 2. If A is shorter, divide B into Bl and Br, such that length of Br equals the length of A
       * 3. Swap A and Br to change ABlBr into BrBlA
       * 4. Recur on the two pieces of B
       * 5. Once A and B are of equal lengths, swap A and B
       * 
       * @param a
       * @param st
       * @param d
       * @param n
       * @return number of items rotated 
       */
      public int rotateleftByJuggling(int a[], int st, int d, int n) {
       
       if (d == 0 || d == n)
        return 0;
    
       int i, j, k, temp;
       for (i =0; i < gcd(d-st, n-st); i++)
       {
        /* move i-th values of blocks */
        temp = a[i+st];
        j = i;
        while(true)
        {
         k = j + d;
         if (k >= n) 
          k = k - n;
         if (k == i) break;
         a[j+st] = a[k+st];
         j = k;
        }
        a[j+st] = temp;
       }
       return d;
      }
    
      public void sort(int[] a) {
       if (a==null || a.length<=1)
        return;
    
       int step=1;
       this.print(step++, a);
       
       int start = 0, mid=0, end=0, num = 1;
       do {
        start = skipNegBlock(a, start);
        mid = skipPosBlock(a, end==0? start : end);
        end = skipNegBlock(a, mid);
        num = rotateleftByJuggling(a, start, mid-start, end-start);
        this.print(step++, a);
       } while (num>0);
      }
     }
    
     /**
      *
      * Algorithm 4: Loop through the array, and swap negative number block and positive number block with double reverse
      * 
      * Time Complexity: O( N0 x N1 ) 
      * Space Requirement: O(1)
      * Stable  
      * 
      * @author stones333
      *
      */
     static public class NegativePositiveSorterViaBlockSwapWithReverse extends NegativePositiveBaseSorter implements Sorter {
    
      public void sort(int[] a) {
       if (a==null || a.length<=1)
        return;
       
       int start = 0, mid=0, end=0, num = 1;
       do {
        start = skipNegBlock(a, start);
        mid = skipPosBlock(a, end==0? start : end);
        end = skipNegBlock(a, mid);
        num = swapBlockWithReverse(a, start, mid, end);
       } while (num>0);
      }
     }
    
    
    
     /**
      *
      * Algorithm 5: Loop through the array, and swap negative number block and positive number block with rotating 
      * 
      * Time Complexity: O( N0 x N1 ) 
      * Space Requirement: O(1)
      * Stable  
      * 
      * @author stones333
      *
      */
     static public class NegativePositiveSorterViaRotationWithBlockSwap extends NegativePositiveBaseSorter implements Sorter {
    
      /**
       * 
       * rotates array a[] of size n by d elements, start from st
       * 
       * Steps: 
       * 1. A is the left subarray, B is the right subarray — that is, the starting point is AB
       * 2. If A is shorter, divide B into Bl and Br, such that length of Br equals the length of A
       * 3. Swap A and Br to change ABlBr into BrBlA
       * 4. Recur on the two pieces of B
       * 5. Once A and B are of equal lengths, swap A and B
       * 
       * @param a
       * @param st
       * @param d
       * @param n
       * @return number of items rotated 
       */
      public int rotateleftByBlockSwap(int a[], int st, int d, int n) {
       
       if(d == 0 || d == n)
        return 0;
       
       int i, j;
       i = d;
       j = n - d;
       while (i != j)
       {
        if (i < j)  {  // A is shorter
         swap(a, st+d-i, st+d+j-i, i);
         j -= i;
        }
        else { // B is shorter
         swap(a, st+d-i, st+d, j);
         i -= j;
        }
       }
       // swap block swap A and B
       swap(a, st+d-i, st+d, i);
       return d;
      }
     
    
      public void sort(int[] a) {
       if (a==null || a.length<=1)
        return;
    
       int start = 0, mid=0, end=0, num = 1;
       do {
        start = skipNegBlock(a, start);
        mid = skipPosBlock(a, end==0? start : end);
        end = skipNegBlock(a, mid);
        num = rotateleftByBlockSwap(a, start, mid-start, end-start);
       } while (num>0);
      }
     }
    
     
    
     
    
     /**
      * Algorithm 6 is based on lg(N) blocking.
      * 
      * 
      * @author stones333
      *
      */
     
     static public class NegativePositiveSorterViaBlockSwap extends NegativePositiveBaseSorter implements Sorter {
    
      public void sort(int[] a) {
       if (a==null || a.length<=1)
        return;
    
       int num=2;
       int start, mid, end;  
    
       while (num<a.length) {
        start = 0;
        mid= advance(a, start, num/2); 
        end = advance(a, start, num);  
        while (start<end) {
         pickAndSwapBlock(a, start, mid, end);
         start=end;
         mid= advance(a, start, num/2);
         end = advance(a, start, num);  
        }
        num = num * 2;
       }
       mid= advance(a, 0, num/2);
       end = advance(a, 0, num);  
       pickAndSwapBlock(a, 0, mid, end);
      }
     }
    
     // test code for NegativePositiveSorterViaRotationWithJuggling
     public static void testNegativePositiveSorterViaRotationWithJuggling() {
      Sorter sorter = new NegativePositiveSorterViaRotationWithJuggling();
      int[] a = new int[] { -1, 2, 1, 12, -9, 3, -4, 4, -3, 21, 52, 4, -2 };
      sorter.sort(a);
      sorter.print(a);
     }
    
     // test code for NegativePositiveSorterViaRotationWithBlockSwap
     public static void testNegativePositiveSorterViaRotationWithBlockSwap() {
      Sorter sorter = new NegativePositiveSorterViaRotationWithBlockSwap();
      int[] a = new int[] { -1, 2, 1, 12, -9, 3, -4, 4, -3, 21, 52, 4, -2 };
      sorter.sort(a);
      sorter.print(a);
     }
    
     // test code for NegativePositiveSorterViaBlockSwapWithReverse
     public static void testNegativePositiveSorterWithBlockSwapViaReverse() {
      Sorter sorter = new NegativePositiveSorterViaBlockSwapWithReverse();
      int[] a = new int[] { -1, 2, 1, 12, -9, 3, -4, 4, -3, 21, 52, 4, -2 };
      sorter.sort(a);
      sorter.print(a);
      
     }
    
     // test code for NegativePositiveCountSorter
     public static void testNegativePositiveCountSorter() {
      Sorter sorter = new NegativePositiveCountSorter();
      int[] a = new int[] { -1, 2, 1, 12, -9, 3, -4, 4, -3, 21, 52, 4, -2 };
      sorter.sort(a);
      sorter.print(a);
      
     }
    
     // test code NegativePositiveSwapSorter
     public static void testNegativePositiveSwapSorter() {
      Sorter sorter = new NegativePositiveSwapSorter();
      int[] a = new int[] { -1, 2, 1, 12, -9, 3, -4, 4, -3, 21, 52, 4, -2 };
      sorter.sort(a);
      sorter.print(a);
      
     }
    
     // test code NegativePositiveSorterViaBlockSwap
     public static void testNegativePositiveSorterViaBlockSwap () {
      Sorter sorter = new NegativePositiveSorterViaBlockSwap();
      int[] a = new int[] { -1, 2, 1, 12, -9, 3, -4, 4, -3, 21, 52, 4, -2 };
      sorter.sort(a);
      sorter.print(a);
      
     }
    
     
     public static void main(String[] args) {
      testNegativePositiveSwapSorter();
      testNegativePositiveCountSorter();
      testNegativePositiveSorterWithBlockSwapViaReverse();
      testNegativePositiveSorterViaRotationWithBlockSwap();
      testNegativePositiveSorterViaRotationWithJuggling();
      
      testNegativePositiveSorterViaBlockSwap();
     }
    }
    
    
    
    



    Enjoy. 




    Sunday, September 22, 2013

    Java Object Pool Implementations and Comparison


    I was looking for a Java solution for Object Pool implementation. Focus on high throughput and low latency, especially under multiple thread i.e. high concurrency environment. 

    Below are possible solutions that I am looking at:
    I have tested multiple implementations under high concurrency. Here is the comparison chart.





    Implementation with Java ConcurrentLinkedQueue:
        
    import java.util.Queue;
    import java.util.concurrent.ConcurrentLinkedQueue;
    
    /**
     * 
     * Implementation with Java ConcurrentLinkedQueue
     * 
     * @author stones333 
     *
     */
    final public class PoolWithConcurrentLinkedQueue<T> implements ObjectPoolInterface<T> {
    	
    	public static interface ObjectPoolFactory<T>
    	{
    		public T create();
    	}
    
    	final private Queue<T> objects;
        private ObjectPoolFactory<T> factory=null;
    
        public PoolWithConcurrentLinkedQueue(ObjectPoolFactory<T> objFactory) {
        	this.factory = objFactory;
            this.objects = new ConcurrentLinkedQueue<T>();
        }
    
        public PoolWithConcurrentLinkedQueue(ObjectPoolFactory<T> objFactory, long count) {
        	this.factory = objFactory;
            this.objects = new ConcurrentLinkedQueue<T>();
            for (long i=0; i<count; i++) {
            	objects.add( factory.create() );
            }
        }
    
        public T addObject() {
            T t = factory.create();
            objects.add(t);
            return t;
        }
    
        public T borrowObject() {
            T t;
            if ((t = objects.poll()) == null) {
                t = factory.create();
                objects.add(t);
            }
            return t;
        }
    
        public void returnObject(T object) {
            this.objects.offer(object);   
        }
        
        public int size() { return objects.size(); };
    }
    
    
    
    
    


    Implementation with Java LinkedBlockingQueue :
    import java.util.Queue;
    import java.util.concurrent.ConcurrentLinkedQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    
    
    
    /**
     * 
     * Implementation with Java LinkedBlockingQueue
     * 
     * @author stones333 
     *
     */
    public class PoolWithLinkedBlockingQueue<T> implements ObjectPoolInterface<T> {
    	
    	public static interface ObjectPoolFactory<T>
    	{
    		public T create();
    	}
    
    
    	final private LinkedBlockingQueue<T> objects;
        private ObjectPoolFactory<T> factory=null;
    
        
        
        public PoolWithLinkedBlockingQueue(ObjectPoolFactory<T> objFactory) {
        	this.factory = objFactory;
            this.objects = new LinkedBlockingQueue<T>();
        }
    
        public PoolWithLinkedBlockingQueue(ObjectPoolFactory<T> objFactory, long count) {
        	this.factory = objFactory;
            this.objects = new LinkedBlockingQueue<T>();
            for (long i=0; i<count; i++) {
            	objects.add( factory.create() );
            }
        }
    
    
        public T addObject() {
            T t = factory.create();
            objects.add(t);
            return t;
        }
    
        public T borrowObject() {
            T t;
            if ((t = objects.poll()) == null) {
                t = factory.create();
                objects.add(t);
            }
            return t;
        }
    
        //
        public void returnObject(T object) {
            this.objects.offer(object);   
        }
        
        
        public int size() { return objects.size(); };
    }
    
    
    
    
    


    Implementation with Java BlockingQue: 
    import java.util.Collection;
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    
    
    
    /**
     * 
     * Implementation with Java BlockingQueue
     * 
     * @author stones333 
     *
     */
    public final class PoolWithBlockingQue <T> implements ObjectPoolInterface<T> {
    	
    	public static interface ObjectPoolFactory<T>
    	{
    		public T create();
    	}
    
        private final BlockingQueue<T> objects;
        private ObjectPoolFactory<T> factory = null;
        
        public PoolWithBlockingQue(ObjectPoolFactory<T> objFactory) {
        	this.factory = objFactory;
            this.objects = new LinkedBlockingQueue<T>();
        }
    
        public PoolWithBlockingQue(ObjectPoolFactory<T> objFactory, long count) {
        	this.factory = objFactory;
            this.objects = new LinkedBlockingQueue<T>();
            for (long i=0; i<count; i++) {
            	objects.add( factory.create() );
            }
        }
    
        public PoolWithBlockingQue(ObjectPoolFactory<T> objFactory,  Collection<? extends T> objects) {
        	this.factory = objFactory;
            this.objects = new ArrayBlockingQueue<T>(objects.size(), false, objects);
        }
    
    
        public PoolWithBlockingQue(Collection<? extends T> objects) {
        	this(null,  objects);
        }
    
        public T borrowObject() throws InterruptedException {
            T t = this.objects.take();
            if (t==null) {
            	t = (factory!=null) ? factory.create() : null;
            	if (t!=null) objects.add(t);
            }
            return t;
        }
    
        public void returnObject(T object) throws InterruptedException {
            this.objects.put(object);
        }
    }
    
    
    
    
    

    Java Test Code:
    
    /**
     * 
     * MultiThread Test code for Object Pool implementations  
     * 
     * @author stones333 
     *
     */
    
    public class ObjectPoolTest {
    	
    	private ObjectPoolInterface<StringBuffer> objectPool = null;
    	
    	
    	public ObjectPoolInterface<StringBuffer> getObjectPool() {
    		return objectPool;
    	}
    
    
    	public void setObjectPool(ObjectPoolInterface<StringBuffer> objectPool) {
    		this.objectPool = objectPool;
    	}
    
    
    	public Object fetchObject() throws RuntimeException, InterruptedException {
    		StringBuffer obj = objectPool.borrowObject();
    		objectPool.returnObject(obj);
    		return obj;
    	}
    
    	
    	public Object fetchObjects() throws RuntimeException, InterruptedException {
    		
    		Object obj = null;
    		for (int i=0; i<10000; i++) {
    			obj = fetchObject();
    			if (obj==null) {
    				throw new RuntimeException ("object from pool is null");
    			}
    		}
    		return obj;
    	}
    
    
    
    }
    
    
    
    MultiThread Test code for Object Pool implementation with LinkedBlockingQueue:
    /**
     * 
     * MultiThread Test code for Object Pool implementation with LinkedBlockingQueue  
     * 
     * @author stones333 
     *
     */
    
    public class PoolWithLinkedBlockingQueueTest extends ObjectPoolTest {
    
    	public static class TestPoolFactory<T> implements PoolWithLinkedBlockingQueue.ObjectPoolFactory<T>  {
    
    		@Override
    		public T create() {
    			StringBuffer obj = new StringBuffer();
    			return (T) obj;
    		}
    	}
    	
    	static private ObjectPoolInterface<StringBuffer> objects = new PoolWithLinkedBlockingQueue<StringBuffer>( new TestPoolFactory<StringBuffer>(), 1000000);
    	
    	public PoolWithLinkedBlockingQueueTest () {
    		super.setObjectPool(objects);
    	}
    
    
    }
    
    
    Test code for other Java Object Pool implementations are obvious and omitted here.

    Wednesday, August 28, 2013

    MapReduce with Hadoop 1.2.1 Part One - Install Hadoop on Mac, Run MapReduce job to count words and produce sorted output


    I’ve done a bit of work with Hadoop and MapReduce in the past years, and would like to use this blog post to share my experience. 

    MapReduce is a software framework introduced by Google to support distributed computing on large data sets on clusters of computers. MapReduce offers an attractive, easy computational model that is data scalable. "Programs written in this functional style are automatically parallelized and executed on a large cluster of commodity machines. The run-time system takes care of the details of partitioning the input data, scheduling the program’s execution across a set of machines, handling machine failures, and managing the required inter-machine communication. This allows programmers without any experience with parallel and distributed systems to easily utilize the resources of a large distributed system."

    Apache Hadoop is an open-source software framework that supports data-intensive distributed applications, licensed under the Apache v2 license. It supports the running of applications on large clusters of commodity hardware. 

    Here is an illustration of how MapReduce works:






    A Mapper
        Accepts (key,value) pairs from the input
        Produces intermediate (key,value) pairs, which are then shuffled
    A Reducer
        Accepts intermediate (key,value) pairs
        Produces final (key,value) pairs for the output
    A driver
        Specifies which inputs to use, where to put the outputs
        Chooses the mapper and the reducer to use






    Install Hadoop 1.2.1 on Mac


    Step 1: Enable SSH to localhost

    Go to System Preferences > Sharing.
    Make sure “Remote Login” is checked.

    $ ssh-keygen -t rsa
    $ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

    Make sure in the end you can ssh to the localhost 
    $ ssh localhost


    Step 2: Install Hadoop

    Download the latest Hadoop core (Hadoop hadoop-1.2.1.tar.gz), untag it and move to 
    /usr/local

    $ tar xvfz hadoop-1.2.1.tar.gz 
    $ mv hadoop-1.2.1 /usr/local/

    Most likely, you need the root privilege to do the mv . 
    $ sudo mv hadoop-1.2.1 /usr/local/ 


    Step 3: Configure Hadoop

    Change directory to the  where Hadoop is installed and configure the Hadoop. 

    $ cd /usr/local/hadoop-1.2.1
    $ mkdir /usr/local/hadoop-1.2.1/dfs/

    Add the following to conf/core-site.xml

    <property>
        <name>fs.default.name</name>
        <value>hdfs://localhost:9000</value>
    </property>


    Add the following to conf/hdfs-site.xml

    <configuration>

    <property>
    <name>dfs.name.dir</name>
            <value>/usr/local/hadoop-1.2.1/dfs/name</value>
            <description>Path on the local filesystem where the NameNode stores the namespace and transactions logs persistently</description>
    </property>


    <property>
            <name>dfs.data.dir</name>
            <value>/usr/local/hadoop-1.2.1/dfs/data</value>
            <description>Comma separated list of paths on the local filesystem of a DataNode where it should store its blocks.</description>
    </property>

    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>

    </configuration>


    Add the following to conf/mapred-site.xml

    <property>
        <name>mapred.job.tracker</name>
        <value>localhost:9001</value>
    </property>


    Add the followings to conf/hadoop-env.sh

    export HADOOP_OPTS="-Djava.security.krb5.realm= -Djava.security.krb5.kdc="
    export JAVA_HOME=/Library/Java/Home



    Step 4: Configure environment variables for Hadoop

    Edit ~/.bash_profile, to add the followings : 

    ## set Hadoop environment 
    export HADOOP_HOME=/usr/local/hadoop-1.2.1
    export HADOOP_CONF_DIR=/usr/local/hadoop-1.2.1/conf
    export PATH=$PATH:$HADOOP_HOME/bin


    Step 5: Format Hadoop filesystem

    Run the hadoop command to format the HDFS system. 

    $ hadoop namenode -format

    Step 6: Start Hadoop

    Run the start-all.sh command to start the Hadoop. 

    $ start-all.sh

    To verify that all Hadoop processes are running:

    $ jps
    9460 Jps
    9428 TaskTracker
    9344 JobTracker
    9198 DataNode
    9113 NameNode
    9282 SecondaryNameNode



    To run a sample Hadoop MapReduce job (calculating Pi) that comes from hadoop-examples-1.2.1.jar:
    $ hadoop jar /usr/local/hadoop-1.2.1/./hadoop-examples-1.2.1.jar pi 10 100


    To take a look at hadoop logs:
    $ ls -altr /usr/local/hadoop-1.2.1/logs/


    To stop hadoop:
    $ stop-all.sh 

    Web UI for Hadoop NameNode: http://localhost:50070/
    Web UI for Hadoop JobTracker: http://localhost:50030/



    Run MapReduce job to count words and produce sorted output 


    Use mvn to start a Hadoop MapReduce Java project:
    $ mvn archetype:generate -DgroupId=com.lei.hadoop -DartifactId=MapReduceWithHadoop -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false 


    $ cd MapReduceWithHadoop/


    Add the following Hadoop dependency to pom.xml: 
    <dependency>
         <groupId>org.apache.hadoop</groupId>
         <artifactId>hadoop-core</artifactId>
         <version>1.2.1</version>
    </dependency>


    To build the target jar: 
    $ mvn clean compile package 


    To generate eclipse project: 
    $ mvn eclipse:eclipse 


    To run MapReduce job that counts words in text files at local folder wordcount_input, and generate result in sorted format: 
    $ hadoop jar ./target/MapReduceWithHadoop-1.0-SNAPSHOT.jar com.lei.hadoop.countword.CountWordsV2 ./wordcount_input ./wordcount_output 


    To see the result from output folder wordcount_output: 
    $ tail wordcount_output/part-00000
    5 Apache
    5 a
    6 distributed
    8 data
    8 to
    8 of
    10 and
    10 Hadoop
    11 for
    12 A



    Mapper for WordCount:
        
      // Maper to send <word, 1> to OutputCollector
      public void map(LongWritable key, Text value, 
        OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException {
       String line = (caseSensitive) ? value.toString() : value.toString().toLowerCase();
       for (String pattern : patternsToSkip) {
        line = line.replaceAll(pattern, "");
       }
         
       StringTokenizer tokenizer = new StringTokenizer(line);
       while (tokenizer.hasMoreTokens()) {
        word.set(tokenizer.nextToken());
        output.collect(word, one);
        reporter.incrCounter(Counters.INPUT_WORDS, 1);
       }
         
       if ((++numRecords % 100) == 0) {
        reporter.setStatus("Finished processing " + numRecords + " records " + "from the input file: " + inputFile);
       }
      }
    


    Reducer for WordCount:
        
     public static class CountWordsV2Reduce extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable> {
      // Reducer to sum up word count, and send them to  OutputCollector
      public void reduce(Text key, Iterator<IntWritable> values, 
        OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException {
       int sum = 0;
       while (values.hasNext()) {
        sum += values.next().get();
       }
       output.collect(key, new IntWritable(sum));
      }
     }
    
    

    Mapper for WordSort:
        
    
     /**
      * 
      * @author stones333
      *
      */
     public static class SortWordsMap extends MapReduceBase 
      implements Mapper<LongWritable, Text, IntWritable, Text> {
      @Override
      public void map(LongWritable key, Text value, 
        OutputCollector<IntWritable, Text> collector, 
        Reporter reporter) throws IOException 
      {
       String line = value.toString();
       StringTokenizer stringTokenizer = new StringTokenizer(line);
    
       int number = 0; 
       String word = "";
    
       if(stringTokenizer.hasMoreTokens())
       {
        String strWord= stringTokenizer.nextToken();
        word = strWord.trim();
       }
    
       if( stringTokenizer.hasMoreElements())
       {
        String strNum = stringTokenizer.nextToken();
        number = Integer.parseInt(strNum.trim());
       }
    
       collector.collect(new IntWritable(number), new Text(word));
    
      }
     }
    
    


    Reducer for WordSort:
        
     /**
      * 
      * @author stones333
      *
      */
     public static class SortWordsReduce extends MapReduceBase implements Reducer<IntWritable, Text, IntWritable, Text> {
      
      public void reduce(IntWritable key, Iterator<Text> values, OutputCollector<IntWritable, Text> output, Reporter reporter) throws IOException
         {
             while((values.hasNext()))
             {
              output.collect(key, values.next());
             }
    
         }
     }
    
    

    You can access the code from https://github.com/leizou123/MapReduceWithHadoop

     $ git clone https://github.com/leizou123/MapReduceWithHadoop


    Have fun and enjoy the journey.


    Monday, April 15, 2013

    Simple Java Demo to show how to wait threads to finish

    Here is a small program that illustrate how to use CountDownLatch to wait Java threads to finish. The example is self-explanatory.
        
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    
    /**
     * small demo to use CountDownLatch to wait for multiple threads to finish   
     * 
     * @author stones333
     *
     */
    public class FixedThreadPool {
    
     private CountDownLatch countDownLatch=null;
     
     /**
      * 
      * @param count
      */
        public void startParallelWork(int count) {
            ExecutorService executorService = Executors.newFixedThreadPool( count );
     
            countDownLatch=new CountDownLatch(count); 
            for (int i = 0; i < count; i++) {
                Worker worker = new Worker(this.countDownLatch, i); 
                executorService.execute(worker);
            }
            executorService.shutdown();
        }
    
        /**
         * 
         * @throws InterruptedException
         */
        public void waitForThreadstoFinish() throws InterruptedException {
        
         System.out.println("START WAITING");
         if (countDownLatch!=null) {
          countDownLatch.await();
         }
         System.out.println("DONE WAITING");
        }
    
        
        static public class Worker implements Runnable {
         private CountDownLatch countDownLatch;
         private int sleepTime;
         
         
         /**
          * 
          * @param countDownLatch
          * @param sleepTime in second
          */
            public Worker(CountDownLatch countDownLatch, int sleepTime) {
       super();
       this.countDownLatch = countDownLatch;
       this.sleepTime = sleepTime;
      }
    
    
    
      @Override
            public void run() {
             
             System.out.println("Start-" + Thread.currentThread().getName());
             try {
        Thread.sleep( (long) sleepTime * 1000);
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
             System.out.println("End-" + Thread.currentThread().getName());
             if (this.countDownLatch!=null) {
              this.countDownLatch.countDown();
             }
            }
    
        }
    
        public static void main(String[] args) throws Exception {
         FixedThreadPool fixedThreadPool = new FixedThreadPool();
         fixedThreadPool.startParallelWork(10);
         fixedThreadPool.waitForThreadstoFinish();
        }
    }