Finding the Height of a Binary Search Tree in Java using Vertex - java

I have problems writing this method public int getHeight, where i have to find the height of the binary search tree, using recursion. The reason is that my main class, is made with private comparable mKey and private vertex mLeft, mRight, and mParent, instead of nodes. Would love some help.

public int getHeight(Tree t, int depth)
{
if(t == null){
return depth;
}
else{
return Math.max(getHeight(t.mLeft, depth + 1), getHeight(t.mRight, depth + 1))
}
}
This returns the length of the deepest branch in the tree.
EDIT:
call with getHeight(tree,0)

Related

Binary Tree basics

I am following a leet code task which is called Binary tilt. The link to the question is here: https://leetcode.com/problems/binary-tree-tilt/description/
I was stuck on the question so had a look at the solution and I was hoping someone could interpret parts of the below solution for me:
public class Solution {
int result = 0;
public int findTilt(TreeNode root) {
postOrder(root);
return result;
}
private int postOrder(TreeNode root) {
if (root == null) return 0;
int left = postOrder(root.left);
int right = postOrder(root.right);
result += Math.abs(left - right);
return left + right + root.val;
}
}
integers left and right are set to a value every time the recursion happens. What I don’t understand is where this value comes from as in I thought the root.val method would need to be used. Can you explain this in layman terms?
When the method postOrder returns left+right+rootval where is the method returned to? How is it used with the recursive method?
I think what is confusing you is that calculating sum of left and right subtree and calculating tilt for each node is combined in one method. So, I simplified the code that you provided for it to be easier to understand and added comments to it. Though, this way it is much less effective cause you calculate sum for left and right subtree of every node(on each call to calculateTilt), but it is still accepted by leetcode:
public class Solution {
int result = 0; //instance variable to accumulate result(tilt) for all nodes in the tree
public int findTilt(TreeNode root) {
calculateTilt(root);
return result;
}
private void calculateTilt(TreeNode root) {
if (root == null)
return;
int left = findTreeSum(root.left); //find sum of all nodes values of the left subtree
int right = findTreeSum(root.right); //find sum of all nodes values of the right subtree
result += Math.abs(left - right); //add tilt of current node to the result
calculateTilt(root.left); //recursively calculate tilt for the left subtree
calculateTilt(root.right); //recursively calculate tilt for the right subtree
}
//method to find sum of all nodes values for the tree starting at root
private int findTreeSum(TreeNode root){
if (root == null)
return 0;
return findTreeSum(root.left) + findTreeSum(root.right) + root.val;
}
}
Hope this will help!

Tree Structure Not Correctly Printing Out

I am having trouble with a basic binary search tree that I have created in Java. I am trying to output the tree structure in the console with prepended spaces before a nodes value with respect to how deep the node is.
For some reason my printTree() function is outputting a tree structure that seems slightly backwards. I wouldn't think that (5 0.0) would be indented because it would stay as the root in a basic tree like this.
Below is my function and the output:
Note: c creates the root, s adds a key and value, and xp outputs the tree.
private int k;
private float d;
private Node left, right;
public Node(int k) {
this.k = k;
}
public Node(int k, float d) {
this.k = k;
this.d = d;
}
private int height(Node n) {
if (n == null)
return -1;
return 1 + Math.max(height(n.left), height(n.right));
}
private void printTree(Node n) {
if (n == null)
return;
System.out.println(new String(new char[3 * height(n)]).replace("\0", " ") + "(" + n.k + " " + n.d + ") ");
printTree(n.left);
printTree(n.right);
}
Output:
I'm pretty sure that based on my input that 5 should not be indented at all because it would be root node.
I believe that it should look something like (based on a binary search tree):
(5 0.0)
(4 1.2)
(2 3.5)
(6 7.5)
(87 96.5)
(with the correct amount of prepended spaces of course)
Can anybody explain what I'm doing wrong?
You calculate the number of spaces as 3*height(n). height(n) calculates the maximum path length of the left and the right tree, so the root will always be the furthest to the right.
either calculate the height of a node as the length of the path from the node to the root or precalculate the maximum height and set the number of whitespaces for a node to maxHeight - height(n).

Depth First Iterative deepening algorithm returning no results (in java)

I have a search algorithm that is supposed to parse the entire tree, find all results that could match a search query, and return them all as a list. I realize this isn't quite the point of the algorithm, but I'm doing this as a test with breadth first and depth first searches to see what is fastest by timing them. The other two searches work as intended, but when I enter the same search information as my goal for the DFID search i get an empty list. So I know my data is right, just something in the algorithm is wrong and I can't figure out what. I wrote this based off the pseudocode on Wikipedia. Here's what I have:
boolean maxDepth = false;
List<String> results = new ArrayList<String>();
public List<String> dfid(Tree t, String goal)
{
int depth = 0;
while (!maxDepth)
{
System.out.println(results);
maxDepth = true;
depth += 1;
dls(t.root, goal, depth);
}
return results;
}
public void dls(Node node, String goal, int depth)
{
System.out.println(depth);
if (depth == 0 && node.data.contains(goal))
{
//set maxDepth to false if the node has children
if (!node.children.isEmpty())
{
maxDepth = false;
}
results.add(node.data);
}
else if (depth > 0)
{
for(Node child : node.children)
{
dls(child, goal, depth-1);
}
}
}
swap the lines zim-zam suggested and add another else (after the else if depth > 0 ) to flip maxDepth to false

java binary search tree find closest leaf

Im having trouble with a method that finds the height of the closest leaf. What i have just counts all of the leafs. would i have to separate the recursive calls into two conditional statements to check each one independently? any help or suggestions would be appreciated
this is my method
//find the distance to the closest leaf
public int closeLeaf()
{
int distance;
return distance = closeLeaf(root);
}
private int closeLeaf(StringNode n)
{
int dist = 0;
if(n == null)
{
dist = 0;//empty tree
}
else if(n.getLeft()== null && n.getRight()== null)
{
dist++;
}
else
{
dist =closeLeaf(n.getLeft()) + closeLeaf(n.getRight());
}
return dist;
}
Returning values
Please don't do this:
int distance;
return distance = closeLeaf(root);
Just:
return closeLeaf(root);
On to the real question
Here you're adding up the distance to each leaf:
dist = closeLeaf(n.getLeft()) + closeLeaf(n.getRight());
You probably just want to get the minimum of the two values (to tell you the distance to the closest one).
Instead of
dist =closeLeaf(n.getLeft()) + closeLeaf(n.getRight());
which increments dist for every node encountered, use a static/class member variable that gets incremented each time the closeLeaf function is called.
Limit the recursion to finding a leaf, and the value of dist when you find one will give you the height of the closest leaf.

Implement an Indirect Connectivity Test for Java Graph class

I'm writing a class in Java to represent a Graph data structure. This is specific to an undirected, unweighted graph and it's purpose is mainly for edge testing (is node A connected to node B, either directly or indirectly).
I need help implementing the indirectEdgeTest method. In the code below, I've only commented this method and I'm returning false so the code will compile as-is.
I have put some time into coming up with an algorithm, but I can't seem to find anything more simple than this, and I fear I'm making it more complicated than it needs to be:
test first for a direct connection
if no direct connection exists from node a to node b:
for every edge i connected to node a:
create a new graph that does not contain edge a -> i
test new graph for indirect connectivity between nodes i and b
Either pseudocode or actual Java code is welcome in your answers. Here's the code I have:
class Graph {
// This is for an undirected, unweighted graph
// This implementation uses an adjacency matrix for speed in edge testing
private boolean[][] edge;
private int numberOfNodes;
public Graph(int numNodes) {
// The indices of the matrix will not be zero-based, for clarity,
// so the size of the array will be increased by 1.
edge = new boolean[numNodes + 1][numNodes + 1];
numberOfNodes = numNodes;
}
public void addEdge(int a, int b) {
if (a <= numberOfNodes && a >= 1) {
if (b <= numberOfNodes && b >= 1) {
edge[a][b] = true;
edge[b][a] = true;
}
}
}
public void removeEdge(int a, int b) {
if (a <= numberOfNodes && a >= 1) {
if (b <= numberOfNodes && b >= 1) {
edge[a][b] = false;
edge[b][a] = false;
}
}
}
public boolean directEdgeTest(int a, int b) {
// if node a and node b are directly connected, return true
boolean result = false;
if (a <= numberOfNodes && a >= 1) {
if (b <= numberOfNodes && b >= 1) {
if (edge[a][b] == true) {
result = true;
}
}
}
return result;
}
public boolean indirectEdgeTest(int a, int b) {
// if there exists a path from node a to node b, return true
// implement indirectEdgeTest algorithm here.
return false;
}
}
Erm, that approach sounds horribly inefficient. What about this one:
void walk(Node orgin, Set<Node> visited) {
for (Node n : origin.neighbours) {
if (!visited.contains(n)) {
visited.add(n);
walk(n, visited);
}
}
}
boolean hasPath(Node origin, Node target) {
Set<Node> reachables = new HashSet<Node>();
walk(origin, reachables);
return reachables.contains(target);
}
Also, using an adjacency matrix is of questionable use for graph traversal, since you can not efficiently iterate over a node's neighbours in a sparse graph.
If that method is frequently used, and the graph changes rarely, you can speed queries up by doing the decomposition into connected regions up front, and storing for each node the region it belongs to. Then, two nodes are connected if they belong to the same region.
Edit: To clarify on how to best represent the graph. For direct edge testing, an adjacency matrix is preferred. For path testing, a decomposition into regions is. The latter is not trivial to keep current as the graph changes, but there may be algorithms for this in the literature. Alternatively, adjacency lists are serviceable for graph traversal and thus path testing, but they remain less efficient than directly recording the decomposition into connected regions. You can also use adjacency sets to combine the more efficient neighbor iteration in sparse graphs with constant-time edge testing.
Keep in mind that you can also store information redundantly, keeping, for each kind of query, a tailored, separate data structure.
Your solution will work, but a better solution would be to construct a spanning tree from the root "a" node. This way you will eventually have only one tree to consider, instead of multiple sub-graphs that only are missing particular edges.
Once you get the idea, how you implement it is up to you. Assuming you can implement the algorithm in a reasonable manner, you should only have one tree to search for connectivity, which would speed things up considerably.
I credit meriton for his or her answer, but I've coded the idea into working Java classes and a unit test, so I'm supplying a separate answer here in case anyone is looking for reusable code.
Thanks meriton. I agree it's important to make a distinction between direct edge testing and path testing, and that there are different implementations of graphs that are better suited to a particular type of testing. In the case of path testing, it seems adjacency lists are much more efficient than an adjacency matrix representation.
My code below is probably not as efficient as it could be, but for now it is solving my problem. If anyone has improvements to suggest, please feel free.
To compile: javac Graph.java
To execute: java GraphTest
class Graph {
private java.util.ArrayList<Node> nodeList;
private int numberOfNodes;
public Graph(int size) {
nodeList = new java.util.ArrayList<Node>(size + 1);
numberOfNodes = size;
for (int i = 0; i <= numberOfNodes; i++) {
nodeList.add(new Node());
}
}
public void addEdge(int a, int b) {
if (a >= 1 && a <= numberOfNodes) {
if (b >= 1 && b <= numberOfNodes) {
nodeList.get(a).addNeighbour(nodeList.get(b));
nodeList.get(b).addNeighbour(nodeList.get(a));
}
}
}
public void walk(Node origin, java.util.Set<Node> visited) {
for (Node n : origin.getNeighbours()) {
if (!visited.contains(n)) {
visited.add(n);
walk(n, visited);
}
}
}
public boolean hasPath(Node origin, Node target) {
java.util.Set<Node> reachables = new java.util.HashSet<Node>();
walk(origin, reachables);
return reachables.contains(target);
}
public boolean hasPath(int a, int b) {
java.util.Set<Node> reachables = new java.util.HashSet<Node>();
Node origin = nodeList.get(a);
Node target = nodeList.get(b);
walk(origin, reachables);
return reachables.contains(target);
}
}
class Node {
private java.util.Set<Node> neighbours;
public Node() {
neighbours = new java.util.HashSet<Node>();
}
public void addNeighbour(Node n) {
neighbours.add(n);
}
public java.util.Set<Node> getNeighbours() {
return neighbours;
}
}
class GraphTest {
private static Graph g;
public static void main(String[] args) {
g = new Graph(6);
g.addEdge(1,5);
g.addEdge(4,1);
g.addEdge(4,3);
g.addEdge(3,6);
printTest(1, 2);
printTest(1, 4);
printTest(6, 1);
}
public static void printTest(int a, int b) {
System.out.print("Are nodes " + a + " and " + b + " connected?");
if (g.hasPath(a, b)) {
System.out.println(" YES.");
} else {
System.out.println(" NO.");
}
}
}

Categories

Resources