Print all possible diameters of Binary Tree? - java

I know how to calculate the diameter of tree but I want to print all possible diameters of tree. Taking the below example:-
1
/ \
2 3
/ / \
4 5 6
All Possible diameters in above tree are:-
First: 4 2 1 3 5
Second: 4 2 1 3 6
Any help regarding approach will very helpful.

I assume you mean all possible paths of maximal length from one leaf to another?
Recursion may be your best bet - in pseudocode something like:
path(startNode, endNode) {
if startNode = endNode return;
for each possible next node n {
add n to your path;
path(n, endNode);
}
}
You could call this for each pair of leaves then throwaway any non-maximal length paths, or perhaps choose which leaves to call this on in a bit more of a smart way, which I would leave up to you

How is this done in graphs:
Run BFS from any node n to find most distant node (from that node) n'
Run BFS from node n' to his most distant node n''
The path from n' to n'' is the tree diameter
So, looking at a tree (which can be unrolled into a graph):
A diameter path goes from any leaf on the lowest level in the left sub-tree to any leaf on the lowest level in the right sub-tree.
Now, since you don't don't magically know which 2 nodes are the end nodes of a diameter, and you only have parent-to-child links, the above algorithm wont work, per se. However, you can use the analogy to build one that works on trees instead of graphs.
OK, here is some quick code you can use (it may not be optimal, but it works)
public class BinarySearchTree {
...
public Iterable<T> diameter() {
if (this.root == null) {
return null;
}
Deque<T> diameterLeftPart = new ArrayDeque<T>();
Deque<T> diameterRightPart = new ArrayDeque<T>();
diameter(this.root.left, diameterLeftPart);
diameter(this.root.right, diameterRightPart);
Deque<T> diameter = new ArrayDeque<T>();
for (Iterator<T> it = diameterLeftPart.iterator(); it.hasNext();) {
diameter.offerLast(it.next());
}
diameter.offerLast(this.root.item);
for (Iterator<T> it = diameterRightPart.descendingIterator(); it.hasNext();) {
diameter.offerLast(it.next());
}
return diameter;
}
private void diameter(Node node, Deque<T> diameter) {
if (node == null) {
return;
}
Deque<T> leftPart = new ArrayDeque<T>();
Deque<T> rightPart = new ArrayDeque<T>();
diameter(node.left, leftPart);
diameter(node.right, rightPart);
if (leftPart.size() > rightPart.size()) {
diameter.addAll(leftPart);
} else {
diameter.addAll(rightPart);
}
diameter.offerLast(node.item);
}
...
}
And the runner class:
public class TreeDiameter {
public static void main(String[] args) {
Tree<Integer> tree = new BinarySearchTree<Integer>();
tree.add(5);
tree.add(2);
tree.add(8);
tree.add(1);
tree.add(3);
tree.add(7);
tree.add(9);
tree.add(4);
tree.add(6);
for (Integer diameterNode : tree.diameter()) {
System.out.print(diameterNode + " ");
}
}
}
With the following output:
4 3 2 5 8 7 6
Quick explanation:
We know that the root is the integral part of the diameter path.
So, we want to get the longest path in the left sub-tree and the longest path in the right sub-tree.
Glued together, they create a diameter.
Using recursive calls diameter(node.left, leftPart) and diameter(node.right, rightPart), leftPart and rightPart contain longest paths in left and right sub-trees, respectively.
Simply comparing their sizes gives us the indication which one we will use in constructing the diameter for one level up the tree.
So, to sum up:
Recursion first goes all the way down to the tree and returns the longest path in that sub-tree, passing it upwards to its parent, all the way up to the root.

Related

DFS (depth first search) sequence of nodes

I want to implement dfs for nodes that are of type long in Java.
My algorithm calculates correctly the number of nodes, and the number
of edges, but not the sequence of nodes. Could you please help me
modify my algorithm so I calculate the order in which the nodes are
visited, correctly?
This is my code:
private int getNumberOfNodes(long firstNode) {
List<Long> marked = new ArrayList<>(); //------------------------------------------->
Stack<Long> stack = new Stack<Long>(); //step 1 Create/declare stack
stack.push(firstNode); //Step 2 Put/push inside the first node
while (!stack.isEmpty()) { //Repeat till stack is empty:
Long node = stack.pop(); //Step 3 Extract the top node in the stack
marked.add(node); //------------------------------------------->
long[] neighbors = xgraph.getNeighborsOf(node); //Get neighbors
if (neighbors.length % 2 == 0) {
} else {
numOfNodesWithOddDegree++;
}
int mnt = 0;
for (long currentNode : neighbors) {
if (!marked.contains(currentNode) && !stack.contains(currentNode) ) { //&& !stack.contains(currentNode)
stack.push(currentNode);
} else {
}
if (!marked.contains(currentNode)) {
numOfEdges++;
}
}
}
return marked.size(); //(int) Arrays.stream(neighbors).count();
}
I guess you exam the marked list for the sequence.
As your graph is undirected, the sequence of traversals could be varied based on which neighbor you pushed into the stack first. which means the logic of your function:
xgraph.getNeighborsOf(node)
could impact your sequence. see Vertex orderings from this wiki https://en.wikipedia.org/wiki/Depth-first_search
so my conclusion is: you may have a different traversal sequence, it does not mean your DFS is wrong, as long as it is Deep first search, it is ok to be a little bit different from the given answer.

Weighted Quick Union Find

I am taking an algorithms course where they go over weighted quick union find. I am confused about why we are concerned about the size of a tree as opposed to the depth?
When I tried writing out the code, my code looked different than the solution provided.
From my understanding, the size of the tree (total number of nodes in a tree) is not as important as the depth of the tree when it comes to the run time of the union function (lg n) because it is the depth that will determine how many look ups are needed to get to the root of a node?
Thanks
My code:
public void union(int p, int q) {
int root_p = root(p);
int root_q = root(q);
// If the two trees are not already connected, union them
if(root_p != root_q) {
// The two trees aren't connected, check which is deeper
// Attach the one that is more shallow to the deeper one
if (depth[root_p] > depth[root_q]) {
// p is deeper, point q's root to p
id[root_q] = root_p;
} else if (depth[root_q] > depth[root_p]) {
// q is deeper, point p's root to p
id[root_p] = root_q;
} else {
// They are of equal depth, point q's root to p and increment p's depth by 1
id[root_q] = root_p;
depth[root_p] += 1;
}
}
}
Solution code provided:
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) return;
// make smaller root point to larger one
if (size[rootP] < size[rootQ]) {
parent[rootP] = rootQ;
size[rootQ] += size[rootP];
}
else {
parent[rootQ] = rootP;
size[rootP] += size[rootQ];
}
count--;
}
You are correct that the depth (actually height) is more directly related to the run time, but using either one will result in O(log N) run time for union and find.
The proof is easy -- Given that when we begin (when all sets are disjoint), every root with height h has at least 2(h-1) nodes, this invariant is maintained by union and find operations. Therefore, if a node has size n, then its height will be at most floor(log2(n))+1
So either one will do. BUT, very soon you will learn about path compression, which makes it difficult to keep track of the height of roots, but the size will still be available. At that point you will be able to use rank, which is kind of like height, or continue to use the size. Again either one will do, but I find the size easier to reason about so I always use that.

Max heap of nodes java

I currently need to implement a max heap of nodes where my node class keeps track of the data, the parent and then the left and right child. My insert method for max heap is taking forever to fill with an array of 100 strings. Here is my code: `
public void insert(String name) {
MyNode node = new MyNode(name);
if (root ==null) {
root = node;
}
else {
MyNode parent = findSpot(root);
if(parent.lChild==null) {
parent.lChild=node;
node.setParent(parent);
}
else {
parent.rChild=node;
node.setParent(parent);
}
}
}
public MyNode findSpot(MyNode curr) {
if (curr.lChild == null) {
return curr;
}
else if (curr.rChild==null) {
return curr;
}
else {
if (findSpot(curr.lChild).findHeight(root, curr, 1) > findSpot(curr.rChild).findHeight(root, curr, 1)) {
return findSpot(curr.lChild);
}
else {
return findSpot(curr.rChild);
}
}
}`
If anyone code offer suggestions or tell me whats wrong that'd be greatly appreciated.
If you want to see why your findSpot function is taking so long, add a line at the beginning that outputs "findSpot <node>", where is the details of the node being searched. You'll find that the recursive algorithm is being called many times. And it looks like findHeight is also being called quite often. I'm not certain, but it looks like you're doing an exhaustive tree search on every insertion.
Binary heaps must maintain the Shape property: it is a complete binary tree except possibly the bottom row, which is left-filled. Because of that, if you know how many nodes are in your heap, you can easily find the insertion spot for the next node. Consider this heap:
1
2 3
4 5 6
There are 6 nodes in the heap. Whenever there are 6 nodes in a heap, the tree will look like this and the insertion spot for the next node will be the right child of the far right node (3 in this case).
The interesting thing is that the binary representation of the node number tells us where that node is. For example, 6 in binary is 110. Lop off the first digit, 1, and you're left with 10. Now, starting at the root and taking the next digit in the number, go left if the digit is 0, and right if the digit is 1. Then take the next digit and do the same thing. Repeat until you run out of digits.
In the case of 6, we'd go right from the root to node 3, and then left to node 6.
When you're adding a new node, increment the count and follow the procedure above to locate the insertion spot. 7 is 111 in binary. You lop off the high bit, leaving 11. Then, starting at the root you go right, and the insertion spot is the right child of node 3.
Of course, once you've placed the node in the tree to satisfy the shape property, you have to do the standard re-heapify to adjust the nodes in the tree so that the heap property is maintained.

Connecting nodes in a matrix for a graph

Hi I'm working on this little project which requires me to build a matrix in Java which resembles a chess board. I'm supposed to get the Knight to get from a point to another(In the way Knight moves). So I need to find the shortest way to get there in the end.
My problem is, I can't get to connect the edges to get to that point. I can find out if the vertex is a valid move but I can't seem to find a way to create nodes to get to that point. For Example,
0 XXXXX
1 XXXOX
2 XXXXX
3 XXKXX
4 XXXXX
5 XXXXX
I need to create nodes that connect K to O to find out shortest distance later.
PS. I'll be okay with just hints of how to get there or just some tips. Don't really need the exact code. Thank you very much!
I know it's a bad representation of matrix up there but spare me the critique please
A classic Breadth-First-Search is probably the simplest approach:
class Location {
int x;
int y;
List<Location> adjacent() {
// TODO return list of locations reachable in a single step
}
}
List<Location> findShortestPath(Location start, Location destination) {
Location[][] previous = new Location[8][8];
Deque<Location> queue = new ArrayDeque<>();
queue.add(start);
do {
Location loc = queue.poll();
for (Location n : loc.neighbors()) {
if (previous[n.x][n.y] == null) {
previous[n.x][n.y] = loc;
queue.add(n);
if (n.x == destination.x && n.y == destination.y) {
// we've found a way, let's reconstruct the list of steps
List<Location> path = new ArrayList<>();
for (Location l = n; l != start; l = previous[l.x][l.y]) {
path.add(l);
}
path.reverse();
return path;
}
}
}
} while (!queue.isEmpty());
return null; // no path exists
}
This code enumerates all paths from the start location. Therefore, if there is a path to destination, it will find it. In addition, because paths are enumerated in order or ascending length, the first such path will be a shortest one.
The chess board can be implemented by a 2d array. Each cell in the matrix can be considered to be a node (or vertex) in the graph. Edge is composed of two nodes (in this case two cells) one being the from or source [ lets call it Nod A] and other being the to or neighbor or destination node [ Lets call it node B].
Edge exits if there is a possibility of moving from node A to node B.
You can use Dijkstra's algorithm.
http://krishnalearnings.blogspot.in/2015/07/implementation-in-java-for-dijkstras.html
For Node with the Knight's position you can see the possibilities of the cells where Knight can move to and add in the Min Heap. The weight of each edge is constant. You just need to update the cost of the Node.

Printing binary tree by levels in java

I want to know the code to print a binary tree level by level, I mean, if I have this tree:
5
/ \
3 2
/ \
4 6
I want to print it like: 5 3 2 4 6.
I know I need to do the tree depth method and I already did it, but I don't know what else to do.
You can use the level traversal algorithm to print them.
The algorithm works as follows:
queue := < root >
while queue is not empty
v := queue.front
print v
foreach s : s is a son of v
queue.enqueue(s)
queue.dequeue
Okay, I think I figured it out:
1. extend the class Node and add a property called height (int)
2. Calculate the height of each node of the tree (easy recursive function - no data-structure is needed)
3. use a for-loop, and run in-order traversal, for each height (level) and print the nodes of that level
public void displayByLevel(){
ArrayList<Node> ar = new ArrayList<>();
ar.add(root);
displayByLevelHelper(ar);
}
private void displayByLevelHelper(ArrayList<Node> ar){
if(ar.isEmpty()){
return;
}
ArrayList<Node> nextAr= new ArrayList<>();
for(Node n:ar){
System.out.print(n.data + " ");
if(n.left!=null){
nextAr.add(n.left);
}
if(n.right!=null){
nextAr.add(n.right);
}
}
System.out.println();
displayByLevelHelper(nextAr);
}

Categories