Calculate the depth of a binary search tree? - java

I am having difficulty calculating the summation of depths [the sum of the individual depths for all children of the root] for a given BST. I have the total number of nodes for the tree, and I am trying to calculate the average depth for the tree, requiring I have this depth sum.
Recursion and I don't get along very well.. I am finding this problem very difficult. I would like to see a recursive solution though, if possible.
NOTE:
I have created accessors Node.getLeft() and Node.getRight()

You just need to keep a depth counter as you traverse the tree (look up tree traversals if you have to) and add the value of the counter every time you reach a node. Then just divide by the number of nodes.
This looks like homework so I'm not providing a more detailed solution.

Think about how you would go about this canonically by hand if I had presented a picture of a BST to you on a sheet of paper. When you're at a node, what information do you need to keep track of? How does one find the height of a given node?
From here, try to translate this into pseudocode or even straight into Java. If you're having trouble, feel free to comment so users can help you out.

Is this homework? If so tag the question as such.
You could create a method that:
has a node reference and a depth as arguments
increment depth
if node is not a child node call recursively for left and right and update sum accordingly
otherwise return sum + depth
Once you have this devide by the number of children in the tree to get the average depth.

We need to visit all leaf nodes and figure out how deep they are. This suggests:
Give your node-visiting function an extra argument. It needs to know not just where it's going but also how deep it is. Every time it's called, it's called on to go deeper, so your node visitor just has to increment the depth number it got from the caller.
Now one of 2 things can happen:
Either the node you found is a leaf node, i.e. it doesn't have any children; in this case, your visitor needs to return its depth to the caller. Yeah, it just returns the number it got from the caller, + 1.
or it's not a leaf node. In that case, it will have either 1 or 2 children. We need to get those depth reports from our kids back up to the caller, so just return the sum of the depths returned by the children.
By the magic of recursion, the number returned to the root's visitor will be the sum of the depths of all children.
To get an average depth, you'll want to divide this by the number of leaf nodes; which I'd leave to a second traversal to calculate. It could be done in one, but it would be a little more complicated.

Since this is homework, I don't want to just give you an answer. Instead, here's a recursive way to calculate the length of a singly linked list. Hopefully this will demonstrate recursion in a way you can understand, and you can extrapolate from there to solve your BST problem.
public final class LL {
public final int value;
public LL next;
public LL(final int value) {
this.value = value;
}
public void add(final int value) {
if (null == next) {
next = new LL(value);
} else {
next.add(value);
}
}
/**
* Calculate the length of the linked list with this node as its head (includes this node in the count).
*
* #return the length.
*/
public int length() {
if (null == next) {
return 1;
}
return 1 + next.length();
}
public static void main(final String... args) {
final LL head = new LL(1);
head.add(2);
head.add(3);
System.out.println(head.length());
System.out.println(head.next.length());
}
}

Related

Balance a binary search tree

I'm trying to implement a binary search tree class in Java with a method that can rebalance the tree if there's a difference in height. I'm trying to do it by first storing the value of the nodes in an List (an attribute of the class).
I then want to take the middle element of this list and assign this to the root of the tree. After this I take the left- and right part of the list and do the same thing recursively to the left- and right children of the root and so on.
My algorithm doesn't seem to work though and I don't understand what I'm doing wrong. I wonder if someone can take a look at my code and explain what the problem is? What I do is basically pass the ordered list of elements of the tree (an attribute of the class) and the root into the function below:
public void build(BinaryNode<E> n,List<E> list) {
int idx = (int)Math.floor(list.size()/2);
if(n!=null) {
n.element = list.get(idx);
} else if(n==null) {
n = new BinaryNode<E>(list.get(idx));
}
if(!list.subList(0,idx).isEmpty()) {
build(n.left,list.subList(0,idx));
}
if(!list.subList(idx+1,list.size()).isEmpty() ){
build(n.right,list.subList(idx+1,list.size()));
}
return;
}
Kind regards,
Java method calls are "call by value". This means changing a parameter (like n in your case) has no effect outside of the method.
Try to define your method like this
public BinaryNode<E> build(List<E> list) { ... }
Try investigating about AVL tree
Some useful links:
https://en.wikipedia.org/wiki/AVL_tree
https://www.geeksforgeeks.org/avl-tree-set-1-insertion/

How to implement Union-Find using linked lists?

I need to write a piece of code using the Kruskal algorithm, which in turn needs the Union-Find algorithm.
This includes the methods Make-Set(x), Find-Set(x) and Union(x, y).
I need to implement them using linked lists, but I am not sure of how to start with the Make-Set method.
The Make-Set Method should create a set and make the first element into a key (to compare sets). How exactly would I declare a key using linked lists?
Shortly put: How do I implement this pseudo code for linked lists in Java?
Make-Set(x)
x.p = x
x.rank = 0
Thanks for your help in advance!
I've heard this referred to in the past not as "Union-Find" but as a disjoint set. It isn't exactly a linked list, since the nodes do have a link, but they aren't necessarily linked up in a linear fashion. It's more like a tree where each node has a pointer to its parent and you can walk up the tree to the root.
I don't have much time right now, but here's a quick sketch of how I would implement it in Java:
class Disjoint {
Disjoint next;
Disjoint findSet() {
Disjoint head = this;
if (next != null) {
head = next.findSet();
next = head;
}
return head;
}
void union(Disjoint other) {
Disjoint us = this.findSet();
Disjoint them = other.findSet();
us.next = them;
}
}
Creating an instance is your Make-Set. What you call Find-Set I would call find head or find leader, maybe find identity. I've called it findSet here, though. It walks the chain to find the root of the tree. It also performs an optional operation; it snaps all the links on the way back out of the recursive call so that they all point directly at the root. This is an optimization to keep the chains short.
Finally, Union is implemented just by assigning one root's next pointer to point at the other set. I'm not sure what you intended with rank; if it's the size of the set, you can add a field for that and simply sum them when you union two sets. But you initialize it to 0 for a new set when I would expect it to be initialized to 1.
Two nodes a and b belong to the same set if a.findSet() == b.findSet(). If you need the nodes to carry some data, make the class generic and provide the data to the constructor, and add a getter:
class Disjoint<T> {
Disjoint<T> next;
T data;
public Disjoint(final T data) {
this.data = data;
}
public T getData() {
return data;
}
// rest of class identical except Disjoint replaced with Disjoint<T> everywhere
}

Determine average of all Node values within a Tree Structure

Given this interface...
public static interface Node
{
int getValue();
List<Node> getChildren();
}
Implement the following method to return the average of all node values in the tree.
public static double getAverage(Node root)
{
}
I'm having an extremely hard time with this practice problem and have a few questions.
I assume this is best completed using recursion, is that correct?
Is this possible without a helper method or global variables?
Is this possible without having to traverse the tree twice? (Once for node sum, once for node count)
Additionally, if someone could provide some psuedo-code, I'd greatly appreciate it.
You can use recursion, but it is possible to solve this problem without it, too. What you need is just a depth-first search. You can implement it iteratively using a stack.
Yes, it is possible. A version with a stack does not require any additional methods.
Yes, it is possible. You can just compute both of these values during one traversal.
Here is a pseudo code of a non-recursive implementation:
valuesSum = 0
nodesCount = 0
stack = new Stack
stack.add(root)
while (!stack.isEmpty())
Node v = stack.poll()
nodesCount++
valuesSum += v.getValue()
for (child : v.getChildren())
stack.add(child)
return valuesSum / nodesCount

Get number of descendants at each node in tree in linear time without dynamic programming?

I have written a recursive function that computes the number of descendants at each node in an n-ary tree.
The results of the computation are in the array that is passed in. I am looking for a function that runs in linear time and does not use dynamic programming. The results would ideally be set within each node not requiring a separate data structure. Recursive is preferred if possible.
void setNumberDescendants(Node root, int[] descCount) {
for(Node child:root.children){
setNumberDescendants(child, descCount);
descCount[root.key] += 1+descCount[child.key];
}
}
class Node{
int key;
List<Node> children;
}
Your solution does what you ask for.
It is linear: you only access each node once, and do a constant amount of work for each one.
It does not use dynamic programming: dynamic programming requires a problem to exhibit overlapping subproblems and optimal substructure. This problem does not exhibit overlapping subproblems. Your subproblems, for a set node, consist of the answers for the subtrees rooted at that node. These subtrees do no overlap.
If you want to set the results in each node, simply do something like this:
void setNumberDescendants(Node root) {
for(Node child:root.children){
setNumberDescendants(child);
root.descendants += 1+child.descendants;
}
}
class Node{
int key;
int descendants;
List<Node> children;
}

DFS a tree with no memory

I'm trying to write a function to traverse a tree with depth first search.
My current algorithm goes something like:
If children
go to first child
If no children
go to next sibling
If no siblings
go to parent
The problem I'm running into is that I can't mark nodes on the tree as having been visited, so when I go to the parent the cycle just resets and it goes to the child again, getting stuck in a loop. Does anyone have any idea as to how I could solve this?
(It's in java using the ANTLR plugin)
EDIT:
Following one of the suggestions I wrote this:
public void traverseTree(Tree tree){
if (tree.getChildCount() > 0){
tree = tree.getChild(0);
traverseTree(tree);
System.out.println(tree.toString());
}
if (tree.getParent().getChild(tree.getChildIndex() + 1) != null){
tree = tree.getParent().getChild(tree.getChildIndex() + 1);
traverseTree(tree);
System.out.println(tree.toString());
}
if (!tree.getParent().toString().contains("ROOT_NODE")){
tree = tree.getParent();
traverseTree(tree);
System.out.println(tree.toString());
}
}
Root node is the name of the root node, but I'm getting a stack overflow error. Anyone have any idea why?
Thanks.
I would use recursion in this case.
class Node {
public List<Node> getChildren() { .... }
public void traverse(Visitor<Node> visitor) {
// If children
// go to first child - by traversing the children first.
for(Node kid: getChildren())
kid.traverse(visitor);
// If no children
// go to next sibling, - by continuing the loop.
visitor.visit(this);
// If no siblings
// go to parent - by returning and letting the parent be processed
}
}
interface Vistor<N> {
public void visit(N n);
}
Using a hash_table map each vertex to boolean indicate whether visited or not
Write a depth first Iterator that keeps track of visited nodes internally. That way the tree doesn't have to change to know that it's being watched.
If "no memory" can be interpreted as O(1) memory, then the change may help:
Remember not only the current node, but also node where you came from
Traverse children only if you didn't came from one of them

Categories