Find number of unique routes to specific node using Depth First Search - java

I have a directed graph with vertexes 123456. Using a depth first search, if I wanted to be able to find the number of unique routes from 1-4 (for example), how would I go about doing it? Here is my current DFS.
private final Map<Character, Node> mNodes;
private final List<Edge> mEdges;
private List<Node> mVisited = new ArrayList<>();
int weight;
int numberOfPaths;
public DepthFirstSearch(Graph graph){
mNodes = graph.getNodes();
mEdges = new ArrayList<>(graph.getEdges());
for(Node node : mNodes.values()){
node.setVisited(false);
}
}
public void depthFirstSearch(Node source){
source.setVisited(true);
List<Edge> neighbours = source.getNeighbouringEdges(mEdges);
for(Edge edge : neighbours){
System.out.println(edge.getFrom().getName()+"-"+edge.getTo().getName());
if(!edge.getTo().isVisited()){
mVisited.add(edge.getTo());
weight += edge.getWeight();
depthFirstSearch(edge.getTo());
}
}
}

Since cycles aren't allowed, you have actually a DAG (directed acyclid graph).
These are some questions related to this topic:
Number of paths between two nodes in a DAG
Topological sort to find the number of paths to t
Basically, the idea is get a topological sort of the DAG, then iterate the nodes starting from the destination node backwards to the source node, calculating how many paths are from that node.
Since the array haven't cycles and the nodes are topological sorted, when you visit a node, all nodes that can be reached from that node appears latter in the sort and are already visited. So, the count of paths from an node to the target is the sum of the counts of the nodes that are adjacent to it.
Models:
class Graph
{
private List<Node> nodes;
private List<Edge> edges;
public Graph() {
nodes = new ArrayList<>();
edges = new ArrayList<>();
}
public List<Node> getNodes() { return nodes; }
public List<Edge> getEdges() { return edges; }
public void addNode(Node node) { nodes.add(node); }
public void addEdge(Edge edge) {
edges.add(edge);
edge.getFrom().addEdge(edge);
edge.getTo().addEdge(edge);
}
}
class Node
{
private List<Edge> outgoings, incomings;
public Node() {
outgoings = new ArrayList<>();
incomings = new ArrayList<>();
}
public List<Edge> getOutgoings() { return outgoings; }
public List<Edge> getIncomings() { return incomings; }
public void addEdge(Edge edge) {
if (edge.getFrom() == this) outgoings.add(edge);
if (edge.getTo() == this) incomings.add(edge);
}
}
class Edge
{
private Node from, to;
public Edge(Node from, Node to) {
this.from = from;
this.to = to;
}
public Node getFrom() { return from; }
public Node getTo() { return to; }
}
Algorithm:
static int countPaths(Graph graph, Node source, Node target)
{
List<Node> nodes = topologicalSort(graph);
int[] counts = new int[nodes.size()];
int srcIndex = nodes.indexOf(source);
int tgtIndex = nodes.indexOf(target);
counts[tgtIndex] = 1;
for (int i = tgtIndex; i >= srcIndex; i--) {
for (Edge edge : nodes.get(i).getOutgoings())
counts[i] += counts[nodes.indexOf(edge.getTo())];
}
return counts[srcIndex];
}
static List<Node> topologicalSort(Graph g)
{
List<Node> result = new ArrayList<>();
Set<Node> visited = new HashSet<>();
Set<Node> expanded = new HashSet<>();
for (Node node: g.getNodes())
explore(node, g, result, visited, expanded);
return result;
}
static void explore(Node node, Graph g, List<Node> ordering, Set<Node> visited, Set<Node> expanded) {
if (visited.contains(node)) {
if (expanded.contains(node)) return;
throw new IllegalArgumentException("Graph contains a cycle.");
}
visited.add(node);
for (Edge edge: node.getIncomings())
explore(edge.getFrom(), g, ordering, visited, expanded);
ordering.add(node);
expanded.add(node);
}
Usage:
Graph g = new Graph();
Node a = new Node();
Node b = new Node();
Node c = new Node();
Node d = new Node();
Node e = new Node();
Edge ab = new Edge(a, b);
Edge bc = new Edge(b, c);
Edge cd = new Edge(c, d);
Edge ad = new Edge(a, d);
Edge ae = new Edge(a, e);
Edge ed = new Edge(e, d);
Edge be = new Edge(b, e);
Edge ec = new Edge(e, c);
g.addNode(a);
g.addNode(b);
g.addNode(c);
g.addNode(d);
g.addNode(e);
g.addEdge(ab);
g.addEdge(bc);
g.addEdge(cd);
g.addEdge(ad);
g.addEdge(ae);
g.addEdge(ed);
g.addEdge(be);
g.addEdge(ec);
int count = countPaths(g, a, d);
//count: 6
// Paths:
//1. A->B->C->D
//2. A->D
//3. A->E->D
//4. A->B->E->C->D
//5. A->B->E->D
//6. A->E->C->D
But, if you want to do it using a BFS, you can try doing a backtrack resetting the visited nodes:
static int countPaths(Graph graph, Node source, Node target)
{
Set<Node> visiteds = new HashSet<>();
return BFS(source, target, visiteds);
}
static int BFS(Node current, Node target, Set<Node> visiteds) {
if (current == target) return 1;
else
{
int count = 0;
visiteds.add(current);
for (Edge edge : current.getOutgoings())
if (!visiteds.contains(edge.getTo()))
count += BFS(edge.getTo(), target, visiteds);
visiteds.remove(current);
return count;
}
}
However, to increase the performance, you can implement some kind of memoization:
static int countPaths(Graph graph, Node source, Node target)
{
Set<Node> visiteds = new HashSet<>();
Map<Node, Integer> memoize = new HashMap<>();
for (Node node : graph.getNodes())
memoize.put(node, -1);
memoize.put(target, 1);
return BFS(source, visiteds, memoize);
}
static int BFS(Node current, Set<Node> visiteds, Map<Node, Integer> memoize) {
if (memoize.get(current) != -1) return memoize.get(current);
else
{
int count = 0;
visiteds.add(current);
for (Edge edge : current.getOutgoings())
if (!visiteds.contains(edge.getTo()))
count += BFS(edge.getTo(), visiteds, memoize);
visiteds.remove(current);
memoize.put(current, count);
return count;
}
}

(Assuming directed acyclic graph)
All you need to do is to run your DFS and count every discovered route which leads to the destination node.
The mistake in your code is that your setVisited() and isVisited() state is global. This means that whenever you encounter node C you mark it as visited and it stays marked so for the whole DFS run -- even for paths where it actually has not been visited yet.
An example DFS run (given simple graph A -> B, B -> C, A -> C):
(Step 1 -- path A) Visit A, mark A visited
(Step 1.1 -- path A -> B) Visit B, mark B visited
(Step 1.1.1 -- path A -> B -> C) Visit C, mark C visited
(Step 1.2 -- path A -> C) Here you skip this route as C is marked as visited from step 1.1.1 (which is wrong)
You need to trace visited nodes correctly by e.g.:
trust the caller that the input graph really is acyclic and do not trace visited nodes at all (as there is no way to visit a single node twice in an acyclic graph). You risk that your program enter infinite recursion for wrong input
use simpler/cheaper cycle detection. You can trace the depth of recursion and when it gets deeper than the total number of nodes in the graph raise an exception
reset the node visited state right after the visit (this is what #Arturo Menchaca suggests in his great answer)
keep a separate visited state for each route being processed
Example java code which traces visited nodes in a list (this way you can print the discovered routes):
package test.java.so;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class So37503760 {
public static class Graph {
private final Map<Character, Node> nodes = new TreeMap<Character, Node>();
public Node addNode(char c) {
Node existingNode = nodes.get(c);
if(existingNode!=null) {
return existingNode;
}
Node newNode = new Node(c);
nodes.put(c, newNode);
return newNode;
}
public void addEdge(char f, char t) {
addNode(f).addChild(addNode(t));
}
public Node getNode(char name) {
Node ret = nodes.get(name);
if(ret==null) {
throw new RuntimeException("No such node " + name);
}
return ret;
}
}
public static class Node {
private final char name;
private final ArrayList<Node> children = new ArrayList<Node>();
public Node(char c) {
this.name=c;
}
public void addChild(Node childNode) {
children.add(childNode);
}
public ArrayList<Node> getChildren() {
return children;
}
public char getName() {
return name;
}
}
public static void main(String[] args) {
Graph graph = new Graph();
graph.addEdge('A', 'B');
graph.addEdge('A', 'C');
graph.addEdge('B', 'C');
graph.addEdge('C', 'D');
graph.addEdge('C', 'E');
graph.addEdge('D', 'E');
int numberOfPaths = depthFirstSearch(graph, 'A', 'E');
System.out.println("Found " + numberOfPaths + " paths");
}
public static int depthFirstSearch(Graph graph, char startNode, char destinationNode){
return depthFirstSearch(graph, graph.getNode(startNode), graph.getNode(destinationNode), new ArrayList<Node>());
}
public static int depthFirstSearch(Graph graph, Node startNode, Node destinationNode, List<Node> currentPath){
if(currentPath.contains(startNode)) {
currentPath.add(startNode);
throw new RuntimeException("Cycle detected: " + pathToString(currentPath));
}
currentPath.add(startNode);
try {
// System.out.println("Progress: " + pathToString(currentPath));
if(startNode==destinationNode) {
System.out.println("Found path: " + pathToString(currentPath));
return 1;
}
int ret=0;
for(Node nextNode : startNode.getChildren()){
ret += depthFirstSearch(graph, nextNode, destinationNode, currentPath);
}
return ret;
} finally {
currentPath.remove(currentPath.size()-1);
}
}
private static String pathToString(List<Node> path) {
StringBuilder b = new StringBuilder();
boolean printArrow=false;
for(Node n : path) {
if(printArrow) {
b.append(" -> ");
}
b.append(n.getName());
printArrow=true;
}
return b.toString();
}
}

It really depends on the edges of your graph. If all of your vertices are connected to one another it would be very simple because you'd get the same number of paths every time (1->4, 1->2->4, 1->3->4, 1->5->4,...,1->6->5->3->2->4 [going with the paths from 1 to 4 example). It would look very similar given any n->m path (given the fact that you want no cycles), and there would be the same number of paths each time.
However, if there are any vertices that aren't connected to other vertices, that's where it would get interesting. You'd probably want to use a modified Djikstra's algorithm that would then give you the different answers (I'm kind of guessing you're looking for) for number of unique paths.

Related

How to perform different basic traversals of graphs?

I am trying to perform an iterative breadth first traversal, iterative depth first traversal, and recursive depth first traversal of a given graph (using an adjacency matrix).
In its current state, my program outputs various wrong answers.
Here's some examples.
I am expecting
From Node A
DFS (iterative): A B H C D E I F G
DFS (recursive): A B H C D E I F G
BFS (iterative): A B D I H C E F G
but am instead getting
From Node A
DFS (iterative): A I D B H C F G E
DFS (recursive): A B H C F D E I G
BFS (iterative): A B D I H C E F G
I'm unsure if the problem with my program lies within the implementation of the traversals, or my implementation of some other part of the program. To be more specific, I'm not sure if my implementation connectNode or getNeighbors method is what is causing the incorrect output, or if it is my implementation of the traversals.
EDIT: Neighbors are supposed to be chosen in ascending order, if that's important. Perhaps this is part of the problem?
EDIT2: I added the new line of code, thanks to #HylianPikachu's suggestion. I now get full answers, but they are still not in the correct order.
EDIT3: I added the code to make it so the root node is checked as visited for bfs and recursive dfs. I think. I should also note that I was given parts of this code and told to fill in the rest. The use of the stack and queue are what I was told to use, even though there might be better options.
EDIT4: Added what was suggested, and now, the Iterative BFS works and gets the correct result. However, both DSF searches still do not work. I modified the results of the program above, to show this.
import java.util.*;
public class GraphM {
public Node rootNode;
public List<Node> nodes = new ArrayList<Node>(); // nodes in graph
public int[][] adjMatrix; // adjacency Matrix
public void setRootNode(Node n) {
rootNode = n;
}
public Node getRootNode() {
return rootNode;
}
public void addNode(Node n) {
nodes.add(n);
}
// This method connects two nodes
public void connectNode(Node src, Node dst) {
if(adjMatrix == null) {
adjMatrix = new int[nodes.size()][nodes.size()];
}
adjMatrix[nodes.indexOf(src)][nodes.indexOf(dst)] = 1;
adjMatrix[nodes.indexOf(dst)][nodes.indexOf(src)] = 1;
}
// Helper method to get one unvisited node from a given node n.
private Node getUnvisitedChildNode(Node n) {
int index = nodes.indexOf(n);
int size = adjMatrix.length;
for (int j = 0; j < size; j++)
if (adjMatrix[index][j] == 1 && ((Node) nodes.get(j)).visited == false)
return nodes.get(j);
return null;
}
// get all neighboring nodes of node n.
public List<Node> getNeighbors(Node n) {
List<Node> neighbors = new ArrayList<Node>();
for(int i = 0; i < nodes.size(); i ++) {
if (adjMatrix[nodes.indexOf(n)][i] == 1) {
neighbors.add(nodes.get(i));
}
Collections.sort(neighbors);
}
return neighbors;
}
// Helper methods for clearing visited property of node
private void reset() {
for (Node n : nodes)
n.visited = false;
}
// Helper methods for printing the node label
private void printNode(Node n) {
System.out.print(n.label + " ");
}
// BFS traversal (iterative version)
public void bfs() {
Queue<Node> queue = new LinkedList<Node>();
queue.add(rootNode);
while(!queue.isEmpty()) {
Node node = queue.poll();
printNode(node);
node.visited = true;
List<Node> neighbors = getNeighbors(node);
for ( int i = 0; i < neighbors.size(); i ++) {
Node n = neighbors.get(i);
if (n != null && n.visited != true) {
queue.add(n);
n.visited = true;
}
}
}
}
// DFS traversal (iterative version)
public void dfs() {
Stack<Node> stack = new Stack<Node>();
stack.add(rootNode);
while(!stack.isEmpty()){
Node node = stack.pop();
if(node.visited != true) {
printNode(node);
node.visited = true;
}
List<Node> neighbors = getNeighbors(node);
for (int i = 0; i < neighbors.size(); i++) {
Node n = neighbors.get(i);
if(n != null && n.visited != true) {
stack.add(n);
}
}
}
}
// DFS traversal (recursive version)
public void dfs(Node n) {
printNode(n);
n.visited = true;
List<Node> neighbors = getNeighbors(n);
for (int i = 0; i < neighbors.size(); i ++) {
Node node = neighbors.get(i);
if(node != null && node.visited != true) {
dfs(node);
}
}
}
// A simple Node class
static class Node implements Comparable<Node> {
public char label;
public boolean visited = false;
public Node(char label) {
this.label = label;
}
public int compareTo(Node node) {
return Character.compare(this.label, node.label);
}
}
// Test everything
public static void main(String[] args) {
Node n0 = new Node('A');
Node n1 = new Node('B');
Node n2 = new Node('C');
Node n3 = new Node('D');
Node n4 = new Node('E');
Node n5 = new Node('F');
Node n6 = new Node('G');
Node n7 = new Node('H');
Node n8 = new Node('I');
// Create the graph (by adding nodes and edges between nodes)
GraphM g = new GraphM();
g.addNode(n0);
g.addNode(n1);
g.addNode(n2);
g.addNode(n3);
g.addNode(n4);
g.addNode(n5);
g.addNode(n6);
g.addNode(n7);
g.addNode(n8);
g.connectNode(n0, n1);
g.connectNode(n0, n3);
g.connectNode(n0, n8);
g.connectNode(n1, n7);
g.connectNode(n2, n7);
g.connectNode(n2, n3);
g.connectNode(n3, n4);
g.connectNode(n4, n8);
g.connectNode(n5, n6);
g.connectNode(n5, n2);
// Perform the DFS and BFS traversal of the graph
for (Node n : g.nodes) {
g.setRootNode(n);
System.out.print("From node ");
g.printNode(n);
System.out.print("\nDFS (iterative): ");
g.dfs();
g.reset();
System.out.print("\nDFS (recursive): ");
g.dfs(g.getRootNode());
g.reset();
System.out.print("\nBFS (iterative): ");
g.bfs();
g.reset();
System.out.println("\n");
}
}
}
So, we already covered the first part of your question, but I'll restate it here for those who follow. Whenever working with graphs and an adjacency matrix, probably the best way to initialize elements in the array is "both ways."
Instead of just using the following, which would require a specific vertex be listed first in order to find the neighbors:
adjMatrix[nodes.indexOf(src)][nodes.indexOf(dst)] = 1;
Use this, which leads to searches that are agnostic of the vertex order:
adjMatrix[nodes.indexOf(src)][nodes.indexOf(dst)] = 1;
adjMatrix[nodes.indexOf(dst)][nodes.indexOf(src)] = 1;
Now, for ordering. You want the vertices to be outputted in order from "least" letter to "greatest" letter. We'll address each one of your data structures individually.
In BFS (iterative), you use a Queue. Queues are "first in, first out." In other words, the element that was least recently added to the Queue will be outputted first whenever you call queue.poll(). Thus, you need to add your nodes from least to greatest.
In DFS (iterative), you use a Stack. Stacks are "last in, first out." In other words, the element that was most recently added to the Stack will be outputted first whenever you call stack.pop(). Thus, you need to add your nodes from greatest to least.
In DFS (recursive), you use a List. Lists have no "in-out" ordering per se, as we can poll them in whatever order we want, but the easiest thing to do would just be to sort the List from least to greatest and output them in order.
With this in mind, we need to introduce protocol for sorting the graph. All three protocols use getNeighbors(), so we'll sort the outputted List immediately after we call that function. Lists can be ordered with the function Collections.sort(List l) from java.utils.Collections, but we first need to modify your nodes class so Java knows how to sort the Nodes. For further reading about the details of what I'm doing, you can look here, but this post is getting way longer than I intended already, so I'm going to just show the code here and let the interested explore the link themselves.
You would first tweak your Node class by implementing Comparable<Node> and adding the compareTo() function.
static class Node implements Comparable<Node>{
public char label;
public boolean visited = false;
public Node(char label) {
this.label = label;
}
#Override
public int compareTo(Node that) {
return Character.compare(this.label, that.label);
}
}
Then, in the cases in which we want to order the List from least to greatest, we can use Collections.sort(neighbors). When we want it from greatest to least, we can use Collections.sort(neighbors, Collections.reverseOrder()). Our final code will look like this:
// BFS traversal (iterative version)
public void bfs() {
Queue<Node> queue = new LinkedList<Node>();
queue.add(rootNode);
while(!queue.isEmpty()) {
Node node = queue.poll();
printNode(node);
node.visited = true;
List<Node> neighbors = getNeighbors(node);
//NEW CODE: Sort our neighbors List!
Collections.sort(neighbors);
for ( int i = 0; i < neighbors.size(); i ++) {
Node n = neighbors.get(i);
if (n != null && n.visited != true) {
queue.add(n);
n.visited = true;
}
}
}
}
// DFS traversal (iterative version)
public void dfs() {
Stack<Node> stack = new Stack<Node>();
stack.add(rootNode);
while(!stack.isEmpty()){
Node node = stack.pop();
if(node.visited != true) {
printNode(node);
node.visited = true;
}
List<Node> neighbors = getNeighbors(node);
//NEW CODE: Sort our neighbors List in reverse order!
Collections.sort(neighbors, Collections.reverseOrder());
for (int i = 0; i < neighbors.size(); i++) {
Node n = neighbors.get(i);
if(n != null && n.visited != true) {
stack.add(n);
}
}
}
}
// DFS traversal (recursive version)
public void dfs(Node n) {
printNode(n);
n.visited = true;
List<Node> neighbors = getNeighbors(n);
//NEW CODE: Sort our neighbors List!
Collections.sort(neighbors);
for (int i = 0; i < neighbors.size(); i ++) {
Node node = neighbors.get(i);
if(node != null && node.visited != true) {
dfs(node);
}
}
}
I would suggest splitting up your problem into smaller parts.
If you want to write a class for an undirected graph, first do that and test it a bit.
If you want to look if you can implement traversal, make sure your graph works first. You can also use guava, which lets you use MutableGraph (and lots more). Here is how to install it in case you're using IntelliJ and here is how to use graphs from guava.
Also remember to use a debugger to find out were your code goes wrong.

How to represent a unweight directed graph and find the shortest path? Java

What is the best way to represent graph in Java ? I did it in this way:
public class Node<T> {
public T data;
public LinkedList<Node> children;
public Node(T data) {
this.data = data;
this.children = new LinkedList<Node>(); //here there are the connected nodes of the node
}
public T getData() {
return this.data;
}
public void addArch(Node n) {
children.add(n);
}
public class Graph <T> {
private Node<T> source = new Node(null);
private Node<T> target = new Node(null);
private ArrayList<Node> nodes = new ArrayList<Node>();
public Graph() {}
public void addNode(T v) {
boolean visto = false;
for (Node n: nodes) {
if (n.getData().equals(v)) {
visto = true;
}
}
if (visto == false) {
nodes.add(new Node(v));
}
}
public void addEdge(T p, T a) throws NoSuchNodeException {
boolean visto = false;
boolean visto_secondo = false;
for (Node n: nodes) {
if (n.getData().equals(p)) {
visto = true;
}
}
for (Node n: nodes) {
if (n.getData().equals(a)) {
visto_secondo = true;
}
}
if (visto == false || visto_secondo == false) {
throw new NoSuchNodeException();
}
else {
for (Node n : nodes) {
if (p.equals(n.getData())) {
System.out.print(a);
n.addArch(new Node(a));
}
}
}
}
I have to find the shortest path but it seems like the archs are not added,why ? I did also the set and get of source and target. However I have to find the shortest path between this source and target,what is the algorithm to use? I need to use a bfs to get the shortest path but my problem is how to iterate over archs,I need to do a recursive function I think
The best algorithm for finding the shortest path to a goal node is Iterative Deepening A*.
It finds the shortest path to the goal node provided the heuristic value is admissible, meaning it doesn't overestimate.
Here is the pseudocode:
node current node
g the cost to reach current node
f estimated cost of the cheapest path (root..node..goal)
h(node) estimated cost of the cheapest path (node..goal)
cost(node, succ) step cost function
is_goal(node) goal test
successors(node) node expanding function, expand nodes ordered by g + h(node)
procedure ida_star(root)
bound := h(root)
loop
t := search(root, 0, bound)
if t = FOUND then return bound
if t = ∞ then return NOT_FOUND
bound := t
end loop
end procedure
function search(node, g, bound)
f := g + h(node)
if f > bound then return f
if is_goal(node) then return FOUND
min := ∞
for succ in successors(node) do
t := search(succ, g + cost(node, succ), bound)
if t = FOUND then return FOUND
if t < min then min := t
end for
return min
end function
The g represents the number of moves to get to the current state and h represents the estimated number of moves to get to the goal state. f := g + h(node). The closer the heuristic value is to the actual number of moves, the faster the algorithm

How to find largest common subtrees in a multi tree

Recently, I encounter a algorithm problem: the tree is defined as
public class Node
{
int id;
private final List<Node> children;
Node(int id) {
this.id = id;
this.children = new ArrayList<>();
}
}
Two subtrees are in common if their structure is identical. The largest common subtrees maximizes the number of nodes in each individual subtrees. So how to find the maxmum common subtree(the id of each node does not matter, just the structure of the subtrees be the same). If there are separate groups of subtrees that are in common with the same maximal size, then we should should return the root nodes from all of the subtrees.
My idea is to serialize each subtree into unique string using BFS. After we get all strings, sort them, and compare which two are equal. So below is my code. My question is because the serialization each subtree cause much overhead, is there any other idea to solve this problem in a better time complexity.
public static List<Node> getLargestCommonSubtrees(Node root) {
HashMap<String, ArrayList<Node>> map = new HashMap<String, ArrayList<Node>>();
LinkedList<Node> queue = new LinkedList<Node>();
queue.add(root);
while (!queue.isEmpty()) {
Node cur = queue.pollFirst();
String sig = serialize(cur);
if (map.containsKey(sig)) {
ArrayList<Node> list = map.get(sig);
list.add(cur);
map.put(sig, list);
} else {
ArrayList<Node> list = new ArrayList<Node>();
list.add(cur);
map.put(sig, list);
}
for (int i = 0; i < cur.children.size(); i++) {
if (cur.children.get(i) != null) {
queue.add(cur.children.get(i));
}
}
}
int max = Integer.MIN_VALUE;
ArrayList<Node> ans = new ArrayList<Node>();
for (Entry<String, ArrayList<Node>> e : map.entrySet()) {
if (e.getKey().length() >= max) {
if (e.getKey().length() > max) {
ans.clear();
}
ans.addAll(e.getValue());
}
}
return ans;
}
private static String serialize(Node n) {
String signature = "";
LinkedList<Node> q = new LinkedList<Node>();
q.add(n);
if (n.children.size() == 0) {
signature = "0";
return signature;
}
Node curr = null;
while (!q.isEmpty()) {
curr = q.peek();
q.poll();
signature += String.valueOf(curr.children.size());
for (int i = 0; i < curr.children.size(); i++) {
q.offer(curr.children.get(i));
}
}
return signature;
}
JoJo, there might already exist an efficient algorithm out there for this or a similar problem. However, here is how I would do it.
import java.util.ArrayList;
import java.util.List;
public class Node
{
//signature = number of Node's children + signature of each child = total number of all nodes below this Node (including children and children's children...etc)
//
// for example, a tree would have it's signature as
// 13
// 1 5 4
// 0 1 2 1 1
// 0 0 0 0 0
//
private int signature;
private int id;
private final List<Node> children;
private Node parent;
public Node(int id, Node parent) {
this.id = id;
this.children = new ArrayList<Node>();
this.parent = parent;
}
//updates signature, should be called every time there is a change to Node.
private void updateSignature() {
signature = children.size();
for(Node childNode : children) {
signature += childNode.signature;
}
//tell parent to update it's signature
if(parent != null) {
parent.updateSignature();
}
}
//compares two trees to check if their structure is similar
private boolean hasSameStructureAs(Node otherNode) {
return otherNode != null && signature == otherNode.signature;
}
}

Java Printing a Binary Tree using Level-Order in a Specific Format

Okay, I have read through all the other related questions and cannot find one that helps with java. I get the general idea from deciphering what i can in other languages; but i am yet to figure it out.
Problem: I would like to level sort (which i have working using recursion) and print it out in the general shape of a tree.
So say i have this:
1
/ \
2 3
/ / \
4 5 6
My code prints out the level order like this:
1 2 3 4 5 6
I want to print it out like this:
1
2 3
4 5 6
Now before you give me a moral speech about doing my work... I have already finished my AP Comp Sci project and got curious about this when my teacher mentioned the Breadth First Search thing.
I don't know if it will help, but here is my code so far:
/**
* Calls the levelOrder helper method and prints out in levelOrder.
*/
public void levelOrder()
{
q = new QueueList();
treeHeight = height();
levelOrder(myRoot, q, myLevel);
}
/**
* Helper method that uses recursion to print out the tree in
* levelOrder
*/
private void levelOrder(TreeNode root, QueueList q, int curLev)
{
System.out.print(curLev);
if(root == null)
{
return;
}
if(q.isEmpty())
{
System.out.println(root.getValue());
}
else
{
System.out.print((String)q.dequeue()+", ");
}
if(root.getLeft() != null)
{
q.enqueue(root.getLeft().getValue());
System.out.println();
}
if(root.getRight() != null)
{
q.enqueue(root.getRight().getValue());
System.out.println();
curLev++;
}
levelOrder(root.getLeft(),q, curLev);
levelOrder(root.getRight(),q, curLev);
}
From what i can figure out, i will need to use the total height of the tree, and use a level counter... Only problem is my level counter keeps counting when my levelOrder uses recursion to go back through the tree.
Sorry if this is to much, but some tips would be nice. :)
Here is the code, this question was asked to me in one of the interviews...
public void printTree(TreeNode tmpRoot) {
Queue<TreeNode> currentLevel = new LinkedList<TreeNode>();
Queue<TreeNode> nextLevel = new LinkedList<TreeNode>();
currentLevel.add(tmpRoot);
while (!currentLevel.isEmpty()) {
Iterator<TreeNode> iter = currentLevel.iterator();
while (iter.hasNext()) {
TreeNode currentNode = iter.next();
if (currentNode.left != null) {
nextLevel.add(currentNode.left);
}
if (currentNode.right != null) {
nextLevel.add(currentNode.right);
}
System.out.print(currentNode.value + " ");
}
System.out.println();
currentLevel = nextLevel;
nextLevel = new LinkedList<TreeNode>();
}
}
This is the easiest solution
public void byLevel(Node root){
Queue<Node> level = new LinkedList<>();
level.add(root);
while(!level.isEmpty()){
Node node = level.poll();
System.out.print(node.item + " ");
if(node.leftChild!= null)
level.add(node.leftChild);
if(node.rightChild!= null)
level.add(node.rightChild);
}
}
https://github.com/camluca/Samples/blob/master/Tree.java
in my github you can find other helpful functions in the class Tree like:
Displaying the tree
****......................................................****
42
25 65
12 37 43 87
9 13 30 -- -- -- -- 99
****......................................................****
Inorder traversal
9 12 13 25 30 37 42 43 65 87 99
Preorder traversal
42 25 12 9 13 37 30 65 43 87 99
Postorder traversal
9 13 12 30 37 25 43 99 87 65 42
By Level
42 25 65 12 37 43 87 9 13 30 99
Here is how I would do it:
levelOrder(List<TreeNode> n) {
List<TreeNode> next = new List<TreeNode>();
foreach(TreeNode t : n) {
print(t);
next.Add(t.left);
next.Add(t.right);
}
println();
levelOrder(next);
}
(Was originally going to be real code - got bored partway through, so it's psueodocodey)
Just thought of sharing Anon's suggestion in real java code and fixing a couple of KEY issues (like there is not an end condition for the recursion so it never stops adding to the stack, and not checking for null in the received array gets you a null pointer exception).
Also there is no exception as Eric Hauser suggests, because it is not modifying the collection its looping through, it's modifying a new one.
Here it goes:
public void levelOrder(List<TreeNode> n) {
List<TreeNode> next = new ArrayList<TreeNode>();
for (TreeNode t : n) {
if (t != null) {
System.out.print(t.getValue());
next.add(t.getLeftChild());
next.add(t.getRightChild());
}
}
System.out.println();
if(next.size() > 0)levelOrder(next);
}
Below method returns ArrayList of ArrayList containing all nodes level by level:-
public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) {
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
if(root == null) return result;
Queue q1 = new LinkedList();
Queue q2 = new LinkedList();
ArrayList<Integer> list = new ArrayList<Integer>();
q1.add(root);
while(!q1.isEmpty() || !q2.isEmpty()){
while(!q1.isEmpty()){
TreeNode temp = (TreeNode)q1.poll();
list.add(temp.val);
if(temp.left != null) q2.add(temp.left);
if(temp.right != null) q2.add(temp.right);
}
if(list.size() > 0)result.add(new ArrayList<Integer>(list));
list.clear();
while(!q2.isEmpty()){
TreeNode temp = (TreeNode)q2.poll();
list.add(temp.val);
if(temp.left != null) q1.add(temp.left);
if(temp.right != null) q1.add(temp.right);
}
if(list.size() > 0)result.add(new ArrayList<Integer>(list));
list.clear();
}
return result;
}
The answer is close....the only issue I could see with it is that if a tree doesn't have a node in a particular position, you would set that pointer to null. What happens when you try to put a null pointer into the list?
Here is something I did for a recent assignment. It works flawlessly. You can use it starting from any root.
//Prints the tree in level order
public void printTree(){
printTree(root);
}
public void printTree(TreeNode tmpRoot){
//If the first node isn't null....continue on
if(tmpRoot != null){
Queue<TreeNode> currentLevel = new LinkedList<TreeNode>(); //Queue that holds the nodes on the current level
Queue<TreeNode> nextLevel = new LinkedList<TreeNode>(); //Queue the stores the nodes for the next level
int treeHeight = height(tmpRoot); //Stores the height of the current tree
int levelTotal = 0; //keeps track of the total levels printed so we don't pass the height and print a billion "null"s
//put the root on the currnt level's queue
currentLevel.add(tmpRoot);
//while there is still another level to print and we haven't gone past the tree's height
while(!currentLevel.isEmpty()&& (levelTotal< treeHeight)){
//Print the next node on the level, add its childen to the next level's queue, and dequeue the node...do this until the current level has been printed
while(!currentLevel.isEmpty()){
//Print the current value
System.out.print(currentLevel.peek().getValue()+" ");
//If there is a left pointer, put the node on the nextLevel's stack. If there is no ponter, add a node with a null value to the next level's stack
tmpRoot = currentLevel.peek().getLeft();
if(tmpRoot != null)
nextLevel.add(tmpRoot);
else
nextLevel.add(new TreeNode(null));
//If there is a right pointer, put the node on the nextLevel's stack. If there is no ponter, add a node with a null value to the next level's stack
tmpRoot = currentLevel.remove().getRight();
if(tmpRoot != null)
nextLevel.add(tmpRoot);
else
nextLevel.add(new TreeNode(null));
}//end while(!currentLevel.isEmpty())
//populate the currentLevel queue with items from the next level
while(!nextLevel.isEmpty()){
currentLevel.add(nextLevel.remove());
}
//Print a blank line to show height
System.out.println("");
//flag that we are working on the next level
levelTotal++;
}//end while(!currentLevel.isEmpty())
}//end if(tmpRoot != null)
}//end method printTree
public int height(){
return height(getRoot());
}
public int height(TreeNode tmpRoot){
if (tmpRoot == null)
return 0;
int leftHeight = height(tmpRoot.getLeft());
int rightHeight = height(tmpRoot.getRight());
if(leftHeight >= rightHeight)
return leftHeight + 1;
else
return rightHeight + 1;
}
I really like the simplicity of Anon's code; its elegant. But, sometimes elegant code doesn't always translate into code that is intuitively easy to grasp. So, here's my attempt to show a similar approach that requires Log(n) more space, but should read more naturally to those who are most familiar with depth first search (going down the length of a tree)
The following snippet of code sets nodes belonging to a particular level in a list, and arranges that list in a list that holds all the levels of the tree. Hence the List<List<BinaryNode<T>>> that you will see below. The rest should be fairly self explanatory.
public static final <T extends Comparable<T>> void printTreeInLevelOrder(
BinaryTree<T> tree) {
BinaryNode<T> root = tree.getRoot();
List<List<BinaryNode<T>>> levels = new ArrayList<List<BinaryNode<T>>>();
addNodesToLevels(root, levels, 0);
for(List<BinaryNode<T>> level: levels){
for(BinaryNode<T> node: level){
System.out.print(node+ " ");
}
System.out.println();
}
}
private static final <T extends Comparable<T>> void addNodesToLevels(
BinaryNode<T> node, List<List<BinaryNode<T>>> levels, int level) {
if(null == node){
return;
}
List<BinaryNode<T>> levelNodes;
if(levels.size() == level){
levelNodes = new ArrayList<BinaryNode<T>>();
levels.add(level, levelNodes);
}
else{
levelNodes = levels.get(level);
}
levelNodes.add(node);
addNodesToLevels(node.getLeftChild(), levels, level+1);
addNodesToLevels(node.getRightChild(), levels, level+1);
}
Following implementation uses 2 queues. Using ListBlokcingQueue here but any queue would work.
import java.util.concurrent.*;
public class Test5 {
public class Tree {
private String value;
private Tree left;
private Tree right;
public Tree(String value) {
this.value = value;
}
public void setLeft(Tree t) {
this.left = t;
}
public void setRight(Tree t) {
this.right = t;
}
public Tree getLeft() {
return this.left;
}
public Tree getRight() {
return this.right;
}
public String getValue() {
return this.value;
}
}
Tree tree = null;
public void setTree(Tree t) {
this.tree = t;
}
public void printTree() {
LinkedBlockingQueue<Tree> q = new LinkedBlockingQueue<Tree>();
q.add(this.tree);
while (true) {
LinkedBlockingQueue<Tree> subQueue = new LinkedBlockingQueue<Tree>();
while (!q.isEmpty()) {
Tree aTree = q.remove();
System.out.print(aTree.getValue() + ", ");
if (aTree.getLeft() != null) {
subQueue.add(aTree.getLeft());
}
if (aTree.getRight() != null) {
subQueue.add(aTree.getRight());
}
}
System.out.println("");
if (subQueue.isEmpty()) {
return;
} else {
q = subQueue;
}
}
}
public void testPrint() {
Tree a = new Tree("A");
a.setLeft(new Tree("B"));
a.setRight(new Tree("C"));
a.getLeft().setLeft(new Tree("D"));
a.getLeft().setRight(new Tree("E"));
a.getRight().setLeft(new Tree("F"));
a.getRight().setRight(new Tree("G"));
setTree(a);
printTree();
}
public static void main(String args[]) {
Test5 test5 = new Test5();
test5.testPrint();
}
}
public class PrintATreeLevelByLevel {
public static class Node{
int data;
public Node left;
public Node right;
public Node(int data){
this.data = data;
this.left = null;
this.right = null;
}
}
public void printATreeLevelByLevel(Node n){
Queue<Node> queue = new LinkedList<Node>();
queue.add(n);
int node = 1; //because at root
int child = 0; //initialize it with 0
while(queue.size() != 0){
Node n1 = queue.remove();
node--;
System.err.print(n1.data +" ");
if(n1.left !=null){
queue.add(n1.left);
child ++;
}
if(n1.right != null){
queue.add(n1.right);
child ++;
}
if( node == 0){
System.err.println();
node = child ;
child = 0;
}
}
}
public static void main(String[]args){
PrintATreeLevelByLevel obj = new PrintATreeLevelByLevel();
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
Node node5 = new Node(5);
Node node6 = new Node(6);
Node node7 = new Node(7);
Node node8 = new Node(8);
node4.left = node2;
node4.right = node6;
node2.left = node1;
// node2.right = node3;
node6.left = node5;
node6.right = node7;
node1.left = node8;
obj.printATreeLevelByLevel(node4);
}
}
Try this, using 2 Queues to keep track of the levels.
public static void printByLevel(Node root){
LinkedList<Node> curLevel = new LinkedList<Node>();
LinkedList<Node> nextLevel = curLevel;
StringBuilder sb = new StringBuilder();
curLevel.add(root);
sb.append(root.data + "\n");
while(nextLevel.size() > 0){
nextLevel = new LinkedList<Node>();
for (int i = 0; i < curLevel.size(); i++){
Node cur = curLevel.get(i);
if (cur.left != null) {
nextLevel.add(cur.left);
sb.append(cur.left.data + " ");
}
if (cur.right != null) {
nextLevel.add(cur.right);
sb.append(cur.right.data + " ");
}
}
if (nextLevel.size() > 0) {
sb.append("\n");
curLevel = nextLevel;
}
}
System.out.println(sb.toString());
}
A - Solution
I've written direct solution here. If you want the detailed answer, demo code and explanation, you can skip and check the rest headings of the answer;
public static <T> void printLevelOrder(TreeNode<T> root) {
System.out.println("Tree;");
System.out.println("*****");
// null check
if(root == null) {
System.out.printf(" Empty\n");
return;
}
MyQueue<TreeNode<T>> queue = new MyQueue<>();
queue.enqueue(root);
while(!queue.isEmpty()) {
handleLevel(queue);
}
}
// process each level
private static <T> void handleLevel(MyQueue<TreeNode<T>> queue) {
int size = queue.size();
for(int i = 0; i < size; i++) {
TreeNode<T> temp = queue.dequeue();
System.out.printf("%s ", temp.data);
queue.enqueue(temp.left);
queue.enqueue(temp.right);
}
System.out.printf("\n");
}
B - Explanation
In order to print a tree in level-order, you should process each level using a simple queue implementation. In my demo, I've written a very minimalist simple queue class called as MyQueue.
Public method printLevelOrder will take the TreeNode<T> object instance root as a parameter which stands for the root of the tree. The private method handleLevel takes the MyQueue instance as a parameter.
On each level, handleLevel method dequeues the queue as much as the size of the queue. The level restriction is controlled as this process is executed only with the size of the queue which exactly equals to the elements of that level then puts a new line character to the output.
C - TreeNode class
public class TreeNode<T> {
T data;
TreeNode<T> left;
TreeNode<T> right;
public TreeNode(T data) {
this.data = data;;
}
}
D - MyQueue class : A simple Queue Implementation
public class MyQueue<T> {
private static class Node<T> {
T data;
Node next;
public Node(T data) {
this(data, null);
}
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
}
private Node head;
private Node tail;
private int size;
public MyQueue() {
head = null;
tail = null;
}
public int size() {
return size;
}
public void enqueue(T data) {
if(data == null)
return;
if(head == null)
head = tail = new Node(data);
else {
tail.next = new Node(data);
tail = tail.next;
}
size++;
}
public T dequeue() {
if(tail != null) {
T temp = (T) head.data;
head = head.next;
size--;
return temp;
}
return null;
}
public boolean isEmpty() {
return size == 0;
}
public void printQueue() {
System.out.println("Queue: ");
if(head == null)
return;
else {
Node<T> temp = head;
while(temp != null) {
System.out.printf("%s ", temp.data);
temp = temp.next;
}
}
System.out.printf("%n");
}
}
E - DEMO : Printing Tree in Level-Order
public class LevelOrderPrintDemo {
public static void main(String[] args) {
// root level
TreeNode<Integer> root = new TreeNode<>(1);
// level 1
root.left = new TreeNode<>(2);
root.right = new TreeNode<>(3);
// level 2
root.left.left = new TreeNode<>(4);
root.right.left = new TreeNode<>(5);
root.right.right = new TreeNode<>(6);
/*
* 1 root
* / \
* 2 3 level-1
* / / \
* 4 5 6 level-2
*/
printLevelOrder(root);
}
public static <T> void printLevelOrder(TreeNode<T> root) {
System.out.println("Tree;");
System.out.println("*****");
// null check
if(root == null) {
System.out.printf(" Empty\n");
return;
}
MyQueue<TreeNode<T>> queue = new MyQueue<>();
queue.enqueue(root);
while(!queue.isEmpty()) {
handleLevel(queue);
}
}
// process each level
private static <T> void handleLevel(MyQueue<TreeNode<T>> queue) {
int size = queue.size();
for(int i = 0; i < size; i++) {
TreeNode<T> temp = queue.dequeue();
System.out.printf("%s ", temp.data);
queue.enqueue(temp.left);
queue.enqueue(temp.right);
}
System.out.printf("\n");
}
}
F - Sample Input
1 // root
/ \
2 3 // level-1
/ / \
4 5 6 // level-2
G - Sample Output
Tree;
*****
1
2 3
4 5 6
public void printAllLevels(BNode node, int h){
int i;
for(i=1;i<=h;i++){
printLevel(node,i);
System.out.println();
}
}
public void printLevel(BNode node, int level){
if (node==null)
return;
if (level==1)
System.out.print(node.value + " ");
else if (level>1){
printLevel(node.left, level-1);
printLevel(node.right, level-1);
}
}
public int height(BNode node) {
if (node == null) {
return 0;
} else {
return 1 + Math.max(height(node.left),
height(node.right));
}
}
First of all, I do not like to take credit for this solution. It's a modification of somebody's function and I tailored it to provide the solution.
I am using 3 functions here.
First I calculate the height of the tree.
I then have a function to print a particular level of the tree.
Using the height of the tree and the function to print the level of a tree, I traverse the tree and iterate and print all levels of the tree using my third function.
I hope this helps.
EDIT: The time complexity on this solution for printing all node in level order traversal will not be O(n). The reason being, each time you go down a level, you will visit the same nodes again and again.
If you are looking for a O(n) solution, i think using Queues would be a better option.
I think we can achieve this by using one queue itself. This is a java implementation using one queue only. Based on BFS...
public void BFSPrint()
{
Queue<Node> q = new LinkedList<Node>();
q.offer(root);
BFSPrint(q);
}
private void BFSPrint(Queue<Node> q)
{
if(q.isEmpty())
return;
int qLen = q.size(),i=0;
/*limiting it to q size when it is passed,
this will make it print in next lines. if we use iterator instead,
we will again have same output as question, because iterator
will end only q empties*/
while(i<qLen)
{
Node current = q.remove();
System.out.print(current.data+" ");
if(current.left!=null)
q.offer(current.left);
if(current.right!=null)
q.offer(current.right);
i++;
}
System.out.println();
BFSPrint(q);
}
the top solutions only print the children of each node together. This is wrong according to the description.
What we need is all the nodes of the same level together in the same line.
1) Apply BFS
2) Store heights of nodes to a map that will hold level - list of nodes.
3) Iterate over the map and print out the results.
See Java code below:
public void printByLevel(Node root){
Queue<Node> q = new LinkedBlockingQueue<Node>();
root.visited = true;
root.height=1;
q.add(root);
//Node height - list of nodes with same level
Map<Integer, List<Node>> buckets = new HashMap<Integer, List<Node>>();
addToBuckets(buckets, root);
while (!q.isEmpty()){
Node r = q.poll();
if (r.adjacent!=null)
for (Node n : r.adjacent){
if (!n.visited){
n.height = r.height+1; //adjust new height
addToBuckets(buckets, n);
n.visited = true;
q.add(n);
}
}
}
//iterate over buckets and print each list
printMap(buckets);
}
//helper method that adds to Buckets list
private void addToBuckets(Map<Integer, List<Node>> buckets, Node n){
List<Node> currlist = buckets.get(n.height);
if (currlist==null)
{
List<Node> list = new ArrayList<Node>();
list.add(n);
buckets.put(n.height, list);
}
else{
currlist.add(n);
}
}
//prints the Map
private void printMap(Map<Integer, List<Node>> buckets){
for (Entry<Integer, List<Node>> e : buckets.entrySet()){
for (Node n : e.getValue()){
System.out.print(n.value + " ");
}
System.out.println();
}
Simplest way to do this without using any level information implicitly assumed to be in each Node. Just append a 'null' node after each level. check for this null node to know when to print a new line:
public class BST{
private Node<T> head;
BST(){}
public void setHead(Node<T> val){head = val;}
public static void printBinaryTreebyLevels(Node<T> head){
if(head == null) return;
Queue<Node<T>> q = new LinkedList<>();//assuming you have type inference (JDK 7)
q.add(head);
q.add(null);
while(q.size() > 0){
Node n = q.poll();
if(n == null){
System.out.println();
q.add(null);
n = q.poll();
}
System.out.print(n.value+" ");
if(n.left != null) q.add(n.left);
if(n.right != null) q.add(n.right);
}
}
public static void main(String[] args){
BST b = new BST();
c = buildListedList().getHead();//assume we have access to this for the sake of the example
b.setHead(c);
printBinaryTreeByLevels();
return;
}
}
class Node<T extends Number>{
public Node left, right;
public T value;
Node(T val){value = val;}
}
This works for me. Pass an array list with rootnode when calling printLevel.
void printLevel(ArrayList<Node> n){
ArrayList<Node> next = new ArrayList<Node>();
for (Node t: n) {
System.out.print(t.value+" ");
if (t.left!= null)
next.add(t.left);
if (t.right!=null)
next.add(t.right);
}
System.out.println();
if (next.size()!=0)
printLevel(next);
}
Print Binary Tree in level order with a single Queue:
public void printBFSWithQueue() {
java.util.LinkedList<Node> ll = new LinkedList<>();
ll.addLast(root);
ll.addLast(null);
Node in = null;
StringBuilder sb = new StringBuilder();
while(!ll.isEmpty()) {
if(ll.peekFirst() == null) {
if(ll.size() == 1) {
break;
}
ll.removeFirst();
System.out.println(sb);
sb = new StringBuilder();
ll.addLast(null);
continue;
}
in = ll.pollFirst();
sb.append(in.v).append(" ");
if(in.left != null) {
ll.addLast(in.left);
}
if(in.right != null) {
ll.addLast(in.right);
}
}
}
void printTreePerLevel(Node root)
{
Queue<Node> q= new LinkedList<Node>();
q.add(root);
int currentlevel=1;
int nextlevel=0;
List<Integer> values= new ArrayList<Integer>();
while(!q.isEmpty())
{
Node node = q.remove();
currentlevel--;
values.add(node.value);
if(node.left != null)
{
q.add(node.left);
nextlevel++;
}
if(node.right != null)
{
q.add(node.right);
nextlevel++;
}
if(currentlevel==0)
{
for(Integer i:values)
{
System.out.print(i + ",");
}
System.out.println();
values.clear();
currentlevel=nextlevel;
nextlevel=0;
}
}
}
Python implementation
# Function to print level order traversal of tree
def printLevelOrder(root):
h = height(root)
for i in range(1, h+1):
printGivenLevel(root, i)
# Print nodes at a given level
def printGivenLevel(root , level):
if root is None:
return
if level == 1:
print "%d" %(root.data),
elif level > 1 :
printGivenLevel(root.left , level-1)
printGivenLevel(root.right , level-1)
""" Compute the height of a tree--the number of nodes
along the longest path from the root node down to
the farthest leaf node
"""
def height(node):
if node is None:
return 0
else :
# Compute the height of each subtree
lheight = height(node.left)
rheight = height(node.right)
#Use the larger one
if lheight > rheight :
return lheight+1
else:
return rheight+1
Queue<Node> queue = new LinkedList<>();
queue.add(root);
Node leftMost = null;
while (!queue.isEmpty()) {
Node node = queue.poll();
if (leftMost == node) {
System.out.println();
leftMost = null;
}
System.out.print(node.getData() + " ");
Node left = node.getLeft();
if (left != null) {
queue.add(left);
if (leftMost == null) {
leftMost = left;
}
}
Node right = node.getRight();
if (right != null) {
queue.add(right);
if (leftMost == null) {
leftMost = right;
}
}
}
To solve this type of question which require in-level or same-level traversal approach, one immediately can use Breath First Search or in short BFS. To implement the BFS one can use Queue. In Queue each item comes in order of insertion, so for example if a node has two children, we can insert its children into queue one after another, thus make them in order inserted. When in return polling from queue, we traverse over children as it like we go in same-level of tree. Hense I am going to use a simple implementation of an in-order traversal approach.
I build up my Tree and pass the root which points to the root.
inorderTraversal takes root and do a while-loop that peeks one node first, and fetches children and insert them back into queue. Note that nodes one by one get inserted into queue, as you see, once you fetch the children nodes, you append it to the StringBuilder to construct the final output.
In levelOrderTraversal method though, I want to print the tree in level order. So I need to do the above approach, but instead I don't poll from queue and insert its children back to queue. Because I intent to insert "next-line-character" in a loop, and if I insert the children to queue, this loop would continue inserting a new line for each node, instead I need to check do it only for a level. That's why I used a for-loop to check how many items I have in my queue.
I simply don't poll anything from queue, because I only want to know if there are any level exists.
This separation of method helps me to still keep using BFS data and when required I can print them in-order or level-order , based-on requirements of the application.
public class LevelOrderTraversal {
public static void main(String[] args) throws InterruptedException {
BinaryTreeNode node1 = new BinaryTreeNode(100);
BinaryTreeNode node2 = new BinaryTreeNode(50);
BinaryTreeNode node3 = new BinaryTreeNode(200);
node1.left = node2;
node1.right = node3;
BinaryTreeNode node4 = new BinaryTreeNode(25);
BinaryTreeNode node5 = new BinaryTreeNode(75);
node2.left = node4;
node2.right = node5;
BinaryTreeNode node6 = new BinaryTreeNode(350);
node3.right = node6;
String levelOrderTraversal = levelOrderTraversal(node1);
System.out.println(levelOrderTraversal);
String inorderTraversal = inorderTraversal(node1);
System.out.println(inorderTraversal);
}
private static String inorderTraversal(BinaryTreeNode root) {
Queue<BinaryTreeNode> queue = new LinkedList<>();
StringBuilder sb = new StringBuilder();
queue.offer(root);
BinaryTreeNode node;
while ((node = queue.poll()) != null) {
sb.append(node.data).append(",");
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
return sb.toString();
}
public static String levelOrderTraversal(BinaryTreeNode root) {
Queue<BinaryTreeNode> queue = new LinkedList<>();
queue.offer(root);
StringBuilder stringBuilder = new StringBuilder();
while (!queue.isEmpty()) {
handleLevelPrinting(stringBuilder, queue);
}
return stringBuilder.toString();
}
private static void handleLevelPrinting(StringBuilder sb, Queue<BinaryTreeNode> queue) {
for (int i = 0; i < queue.size(); i++) {
BinaryTreeNode node = queue.poll();
if (node != null) {
sb.append(node.data).append("\t");
queue.offer(node.left);
queue.offer(node.right);
}
}
sb.append("\n");
}
private static class BinaryTreeNode {
int data;
BinaryTreeNode right;
BinaryTreeNode left;
public BinaryTreeNode(int data) {
this.data = data;
}
}
}
Wow. So many answers. For what it is worth, my solution goes like this:
We know the normal way to level order traversal: for each node, first the node is visited and then it’s child nodes are put in a FIFO queue. What we need to do is keep track of each level, so that all the nodes at that level are printed in one line, without a new line.
So I naturally thought of it as miaintaining a queue of queues. The main queue contains internal queues for each level. Each internal queue contains all the nodes in one level in FIFO order. When we dequeue an internal queue, we iterate through it, adding all its children to a new queue, and adding this queue to the main queue.
public static void printByLevel(Node root) {
Queue<Node> firstQ = new LinkedList<>();
firstQ.add(root);
Queue<Queue<Node>> mainQ = new LinkedList<>();
mainQ.add(firstQ);
while (!mainQ.isEmpty()) {
Queue<Node> levelQ = mainQ.remove();
Queue<Node> nextLevelQ = new LinkedList<>();
for (Node x : levelQ) {
System.out.print(x.key + " ");
if (x.left != null) nextLevelQ.add(x.left);
if (x.right != null) nextLevelQ.add(x.right);
}
if (!nextLevelQ.isEmpty()) mainQ.add(nextLevelQ);
System.out.println();
}
}
public void printAtLevel(int i){
printAtLevel(root,i);
}
private void printAtLevel(BTNode<T> n,int i){
if(n != null){
sop(n.data);
} else {
printAtLevel(n.left,i-1);
printAtLevel(n.right,i-1);
}
}
private void printAtLevel(BTNode<T> n,int i){
if(n != null){
sop(n.data);
printAtLevel(n.left,i-1);
printAtLevel(n.right,i-1);
}
}

I get different behaviour in Java depending on HOW I initialize the data structures

I implemented an algorithm in Java. I coded two versions:
one where I initialized the data structures in the constructor,
and
one where I parsed a textfile and initialized the data structure from the input
The strange thing is that I got different behaviour from the two versions, and can hardly understand how.
Why do I get different behaviour?
The algorithm is a first part of Depth-First Search. A set of nodes should be visited and printed only once. In my version where I read from a textfile, the first node is printed twice. The program uses recursion.
Here is the output, the code is below. The first four lines prints the data structures, then is each first-visit-of-a-node printed, and a counter. The counter should only go to 2 not 3.
Output, when read from textfile:
>java GraphStart ex1.txt
Node 1
Node 2
Edge: Node 1 -- Node 2
Edge: Node 2 -- Node 1
Start on Node 1
Node 1 Counter: 1
Node 2 Counter: 2
Node 1 Counter: 3
Output, when initialized in constructor:
Node 1
Node 2
Edge: Node 1 -- Node 2
Edge: Node 2 -- Node 1
Start on Node 1
Node 1 Counter: 1
Node 2 Counter: 2
Depth-First Search - initialized in contructor:
public class DepthFirstSearch {
private final static LinkedList<Node> nodes = new LinkedList<Node>();
private static LinkedList[] edges = new LinkedList[0];
public DepthFirstSearch() {
Node node1 = new Node(1);
Node node2 = new Node(2);
nodes.add(node1);
nodes.add(node2);
edges = Arrays.copyOf(edges, 1);
edges[0] = new LinkedList<Edge>();
edges[0].add(new Edge(node1, node2));
edges = Arrays.copyOf(edges, 2);
edges[1] = new LinkedList<Edge>();
edges[1].add(new Edge(node2, node1));
DFS.startDFS(nodes, edges);
}
public static void main(String[] args) {
new DepthFirstSearch();
}
}
Depth-First Search - initialized from textfile:
public class GraphStart {
private final static LinkedList<Node> nodes = new LinkedList<Node>();
private static LinkedList[] edges = new LinkedList[0];
public GraphStart(String fileName) {
scanFile(fileName);
DFS.startDFS(nodes, edges);
}
// Parse a textfile with even number of integers
// Add the nodes and edges to the datastructures
private static void scanFile(String filename) {
try {
Scanner sc = new Scanner(new File(filename));
while(sc.hasNextInt()){
Node startNode = new Node(sc.nextInt());
if(sc.hasNextInt()) {
Node endNode = new Node(sc.nextInt());
if(!nodes.contains(startNode)){
nodes.add(startNode);
//EDIT
System.out.println("Added " + startNode);
// Grow the Edge-array and initialize the content
if(edges.length < startNode.getNr())
edges = Arrays.copyOf(edges, startNode.getNr());
edges[startNode.getNr()-1] = new LinkedList<Edge>();
}
if(!nodes.contains(endNode)){
nodes.add(endNode);
//EDIT
System.out.println("Added " + endNode);
// Grow the Edge-array and initialize the content
if(edges.length < endNode.getNr())
edges = Arrays.copyOf(edges, endNode.getNr());
edges[endNode.getNr()-1] = new LinkedList<Edge>();
}
// Add the Edge
edges[startNode.getNr()-1].add(new Edge(startNode, endNode));
}
}
} catch (FileNotFoundException e) {
System.out.println("Can not find the file:" + filename);
System.exit(0);
}
}
public static void main(String[] args) {
if(args.length==1) {
new GraphStart(args[0]);
} else {
System.out.println("Wrong argument. <filename>");
}
}
}
Textfile for input:
1 2
2 1
It represents the Edge from Node 1 to Node 2, and the Edge from Node 2 to Node 1.
The algorithm is implemented in a static file, used by both versions.
DFS - the algorithm:
public class DFS {
private static int counter = 0;
private static LinkedList<Node> nodes;
private static LinkedList[] edges;
public static void startDFS(LinkedList<Node> ns, LinkedList[] es) {
nodes = ns;
edges = es;
/* Print the data structures */
printList(nodes);
printEdges(edges);
for(Node n : nodes) {
if(!n.isVisited()) {
System.out.println("\nStart on "+n);
dfs(n);
}
}
}
private static void dfs(Node n) {
counter++;
n.visit();
System.out.println(n + " Counter: " + counter);
for(Object o : edges[n.getNr()-1]) {
if(!((Edge)o).getEnd().isVisited()) {
dfs(((Edge)o).getEnd());
}
}
private static void printList(LinkedList<?> list) {
for(Object obj : list)
System.out.println(obj);
}
private static void printEdges(LinkedList[] edges) {
for(LinkedList list : edges) {
System.out.print("Edge: ");
for(Object o : list) {
System.out.print(o);
}
System.out.println("");
}
}
}
EDIT: Added code listings of Node and Edge.
Node:
public class Node {
private final int nr;
private boolean visited = false;
public Node(int nr) {
this.nr = nr;
}
public int getNr() { return nr; }
public boolean isVisited() { return visited; }
public void visit() { visited = true; }
#Override
public boolean equals(Object obj) {
if(obj instanceof Node)
return ((Node)obj).getNr() == nr;
else
return false;
}
#Override
public String toString() {
return "Node " + nr;
}
}
Edge:
public class Edge {
private final Node startNode;
private final Node endNode;
public Edge(Node start, Node end) {
this.startNode = start;
this.endNode = end;
}
public Node getStart() { return startNode; }
public Node getEnd() { return endNode; }
public String toString() {
return startNode + " " +
"--" + " " +
endNode;
}
}
Sorry for the very long code listings. I tried to isolate my problem and also show a runnable program.
Without seeing the code for Node, my guess is that it isn't implementing hashCode() and equals() or that these aren't implemented correctly.
So for example:
if(!nodes.contains(startNode)){
nodes.add(startNode);
Will be doing the containment check with reference equality (==) instead of anything logical. So the fact that you've create three different node instances will not resolve even though two are "the same".
...and that's why the static method version works because you only have two node instances.
Edit: the above was a good guess but reading deeper into the code I think it has to do with the fact that visit state is kept right on the nodes instead of in a separate visited collection. You have three node instances in your graph even if only two are in the nodes list. One of the edges is pointing to the third node instance (the other one with a '1')... since the visited() method was never called on that one (because it was called on the first '1' instance) then isVisited() will likely return false (can't say for sure because I don't know your Node implementation).
You did not show the implementation for Node, but I would guess that you did not override equals() for it. This will lead nodes.contains(node) to return false and more nodes to be added to the collection than wanted. (The file reading loop creates a fresh start- and endNode everytime through the loop.)
Your constuctor version simply uses 2 unique nodes, which gives the different result.
Implementing Node.equals() will probably solve your issue.
Your scanFile() method creates three nodes - two containing the integer 1, and one containing the integer 2.

Categories

Resources