What does minus 1 means in the method about calculating height of red-black tree? - data-structures

I cannot understand why we should minus 1 in line 4.
I think just returning height(root) is fine, what does minus 1 mean?
public int height() {
if(root == null)
return 0;
return height(root) - 1;
}
public int height(Node<K,V> node) {
if (node == null)
return 0;
int leftheight = height(node.left) + 1
int rightheight = height(node.right) + 1
if (leftheight > rightheight)
return leftheight;
return rightheight;
}

This minus one is necessary because the second height function does not calculate the height, but one more than the height.
The height of a tree is defined as the number of edges on the longest path from the root to a leaf, but the second function calculates the number of nodes (or levels) on the longest path from the root to a leaf, which is always one more.
I agree that this is a strange way of doing it, as actually it makes the name of the second function wrong: it doesn't do what it says.
Moreover, the main function has a problem too, because when the root is null, the height should return -1.
It is more natural to change the base case, and make the second function really return the height of the node that is passed as argument:
public int height() {
return height(root); // Simple: if no argument was passed, the default is the root
}
public int height(Node<K,V> node) {
if (node == null)
return -1; // <-----
int leftheight = height(node.left) + 1
int rightheight = height(node.right) + 1
if (leftheight > rightheight)
return leftheight;
return rightheight;
}
It may be strange to have the value -1 there, but the reasoning is as follows:
This is a tree with height 1:
a
/ \
b c
... because the longest path from the root has one edge; it is a tree with 2 levels, and the height is one less than the number of levels.
This is a tree with height 0:
a
Here the number of levels is 1, and so the height is 0.
One step more, is an empty tree -- it doesn't even have a node, and zero levels, and so the corresponding height should be -1.
See also What is the definition for the height of a tree?.

Related

Calculate Height of a Binary Tree Recursive method

I want to know if this implementation is correct for finding height of BT. Please give me your thoughts on it.
public class Node {
int value;
Node left = null;
Node right = null;
public Node(int value) {
this.value = value;
}
}
class Main {
public int BTHeight(Node root) {
//tree is empty.
if(root == null) {
return -1;
}
//recur for left and right tree.
else if(root.left != null || root.right != null) {
return 1 + Math.max(BTHeight(root.left) + BTHeight(root.right));
}
//tree has only one node. that node is both the root and the leaf
return 0;
}
}
No, it is not a correct implementation as your code has a compilation error here (Math.max function need two input parameters):
return 1 + Math.max(BTHeight(root.left) + BTHeight(root.right));
The definition of height as stated in the book Introduction to Algorithms, 3rd Edition (Cormen, page 1177), is:
The height of a node in a tree is the number of edges on the longest simple downward path from the node to a leaf, and the height of a tree is the height of its root. The height of a tree is also equal to the largest depth of any node in the tree.
A NULL node it is not a tree (by definition) so there are several values of height to choose as default like undefined or -1 or 0, it depend on the purpose. The implementation of height's definition stated above is usually shorter if used -1 as height of a NULL node.
It would be like this:
public int BTHeight(Node root) {
return root == null ? -1 : Math.max(BTHeight(root.left)+1, BTHeight(root.right)+1);}
Corner case examples:
Height of a NULL node: -1
Height of a leaf node: 0
You can use also an alternative definition:
The height of a node in a tree is the number of nodes on the longest simple downward path from the node to a leaf.
In this case it would be better to use 0 as height of a NULL node as a leaf's height is 1.
public int BTHeight(Node root) {
return root == null ? 0 : Math.max(BTHeight(root.left)+1, BTHeight(root.right)+1);}
Corner case examples:
Height of a NULL node: 0
Height of a leaf node: 1
You can see that both codes are basically the same and that is convenient in case you have to change from one definition to another.

How to calculate a height of a tree

I am trying to learn DSA and got stuck on one problem.
How to calculate height of a tree. I mean normal tree, not any specific implementation of tree like BT or BST.
I have tried google but seems everyone is talking about Binary tree and nothing is available for normal tree.
Can anyone help me to redirect to some page or articles to calculate height of a tree.
Lets say a typical node in your tree is represented as Java class.
class Node{
Entry entry;
ArrayList<Node> children;
Node(Entry entry, ArrayList<Node> children){
this.entry = entry;
this.children = children;
}
ArrayList<Node> getChildren(){
return children;
}
}
Then a simple Height Function can be -
int getHeight(Node node){
if(node == null){
return 0;
}else if(node.getChildren() == null){
return 1;
} else{
int childrenMaxHeight = 0;
for(Node n : node.getChildren()){
childrenMaxHeight = Math.max(childrenMaxHeight, getHeight(n));
}
return 1 + childrenMaxHeight;
}
}
Then you just need to call this function passing the root of tree as argument. Since it traverse all the node exactly once, the run time is O(n).
1. If height of leaf node is considered as 0 / Or height is measured depending on number of edges in longest path from root to leaf :
int maxHeight(treeNode<int>* root){
if(root == NULL)
return -1; // -1 beacuse since a leaf node is 0 then NULL node should be -1
int h=0;
for(int i=0;i<root->childNodes.size();i++){
temp+=maxHeight(root->childNodes[i]);
if(temp>h){
h=temp;
}
}
return h+1;
}
2. If height of root node is considered 1:
int maxHeight(treeNode<int>* root){
if(root == NULL)
return 0;
int h=0;
for(int i=0;i<root->childNodes.size();i++){
temp+=maxHeight(root->childNodes[i]);
if(temp>h){
h=temp;
}
}
return h+1;
Above Code is based upon following class :
template <typename T>
class treeNode{
public:
T data;
vector<treeNode<T>*> childNodes; // vector for storing pointer to child treenode
creating Tree node
treeNode(T data){
this->data = data;
}
};
In case of 'normal tree' you can recursively calculate the height of tree in similar fashion to a binary tree but here you will have to consider all children at a node instead of just two.
To find a tree height a BFS iteration will work fine.
Edited form Wikipedia:
Breadth-First-Search(Graph, root):
create empty set S
create empty queues Q1, Q2
root.parent = NIL
height = -1
Q1.enqueue(root)
while Q1 is not empty:
height = height + 1
switch Q1 and Q2
while Q2 is not empty:
for each node n that is adjacent to current:
if n is not in S:
add n to S
n.parent = current
Q1.enqueue(n)
You can see that adding another queue allows me to know what level of the tree.
It iterates for each level, and for each mode in that level.
This is a discursion way to do it (opposite of recursive). So you don't have to worry about that too.
Run time is O(|V|+ |E|).

Find maximum length of path with only 1

I have a tree consisting of only binary numbers as node data. Now I must find the maximum length of the path which consist only of nodes that has its node value as 1 and path must be continuous i.e it should not contain any zero on its way.
For example, let's consider this tree:
root->data = 0;
root->left->data = 1;
root->right->data = 0;
root->left->left->data = 1;
root->left->right->data = 1;
root->left->left->left->data = 1;
root->left->right->left->data = 1;
root->left->right->right->data = 0;
The answer of above tree should be 5.
Please refer to figure in the link given below:
Click this for more detail
How can I do this?
Your example is weird. I don't see how the answer is 5 when your root has a 0, it should be 0. Plus, it should only be 4 since the longest path is along the entire left side if the root is a 1.
Anyways, this is essentially finding the height of a tree while forcing values to be 1. This is a variant on the diameter of a binary tree which can be implemented by modifying the basic solution like this:
public int MaxDiameterWithOnes(Node node)
{
if (node == null || node.Data == 0)
return 0;
return 1 + Math.Max(MaxDiameterWithOnes(node.Left), MaxDiameterWithOnes(node.Right));
}
You can modify this using the second method in the link above to be more efficient.
Basic idea:
int GetDepthWithCondition(Node node)
{
if (node.Data == 0)
return -100000;
return 1 + Math.Max(GetDepthWithCondition(node.RightSon),
GetDepthWithCondition(node.LeftSon));
}
Algorithm may be the following (pseudo code):
maxPath tree | treeHasNoChildren = []
| data == 0 = []
| otherwise =
takeSolutionHavingMaxLength (
left:maxPath (left tree),
right:maxPath (right tree)
)

Computing rank of a node in a binary search tree

If each node in a binary search tree stores its weight (number of nodes in its subtree), what would be an efficient method to compute a rank of a given node (its index in the sorted list) as I search for it in the tree?
Start the rank at zero. As the binary search proceeds down from the root, add the sizes of all the left subtrees that the search skips by, including the left subtree of the found node.
I.e., when the search goes left (from parent to left child), it discovers no new values less than the searched item, so the rank stays the same. When it goes right, the parent plus all the nodes in the left subtree are less than the searched item, so add one plus the left subtree size. When it finds the searched item. any items in the left subtree of the node containing the item are less than it, so add this to the rank.
Putting this all together:
int rank_of(NODE *tree, int val) {
int rank = 0;
while (tree) {
if (val < tree->val) // move to left subtree
tree = tree->left;
else if (val > tree->val) {
rank += 1 + size(tree->left);
tree = tree->right;
}
else
return rank + size(tree->left);
}
return NOT_FOUND; // not found
}
This returns the zero-based rank. If you need 1-based then initialize rank to 1 instead of 0.
Since each node has a field storing its weight, the first you should implement a method call size() which return the number of nodes in a node's substree:
private int size(Node x)
{
if (x == null) return 0;
else return x.N;
}
then compute the rank of a given node is easy
public int rank(Node key)
{ return rank(key,root) }
private int rank(Node key,Node root)
{
if root == null
return 0;
int cmp = key.compareTo(root);
// key are smaller than root, then the rank in the whole tree
// is equal to the rank in the left subtree of the root.
if (cmp < 0) {
return rank(key, root.left)
}
//key are bigger than root,the the rank in the whole tree is equal
// to the size of subtree of the root plus 1 (the root) plus the rank
//in the right sub tree of the root.
else if(cmp > 0){
return size(root.left) + 1 + rank(key,root.right);
}
// key equals to the root, the rank is the size of left subtree of the root
else return size( root.left);
}
Depends on the BST implementation, but I believe you can solve it recursively.
public int rank(Key key){
return rank(root, key);
}
private int rank(Node n, Key key){
int count = 0;
if (n == null)return 0;
if (key.compareTo(n.key) > 0) count++;
return count + rank(n.left, key) + rank(n.right, key);
}

Print the Longest leaf-to-leaf path in a binary tree along with its length

I am solving a problem in which I have to find the longest leaf-to-leaf path in a binary tree along with its length.
for example, if the Binary tree is as follows:
a
/\
b c
/ / \
d e f
/ \ \
g h p
\
k
The longest leaf-to-leaf path would be k-h-d-b-a-c-f-p which is of length 8.
I am calculating the length by recursively finding the length of the left and right sub-tree and then return height_left + height_right + 1 . Is my concept correct?.
Also how should I print the longest leaf-to-leaf path? I just want an idea to proceed.
It seems to me that this algorithm is very close to finding a diameter of a binary tree. Diameter of the tree is the number of nodes on the longest path between two leaves in the tree.
I think you can look here for the implementation: http://www.geeksforgeeks.org/diameter-of-a-binary-tree/ and then adapt it or optimize it's time complexity if you want. But i think O(n) is good enough.
Most answers on the net gives how to find diameter of a tree, i.e
How to find the number of nodes in the longest path.
The only addition is we need to store the nodes which contribute to it.
In recursion, this can be done in two ways.
a) It should be a return type
b) It should be an input parameter which is an object. This object is populated with the result during the course of recursion.
Without the need to print the longest path, we only need to check at every node:
Max of
1) Left node max path
2) Right node max path
c) Current node max path (requires more inputs)
Now, to calculate current node max path, we need more inputs:
Current node max path needs:
1) Max left node height
2) Max right node height
This can either be stored in the node itself (as height parameter) or can be passed with the recursion.
This will only give diameter/length of the longest path.
Now, to get the path printed, we need to store more info which is:
- List<Nodes> pathList - This contains the nodes which form the longest path so far (Note this may not contain the current node).
- List<Nodes> heightList - This contains the nodes which form the longest height from the node to its leaf.
Finally the algo:
//Inputs and Outputs of the method
class Node{
int value;
Node leftchild;
Node rightchild;
}
class ReturnInfo{
ReturnInfo(){
maxpathlen = 0;
maxheight = 0;
pathList = new ArrayList<Node>();
heightList = new ArrayList<Node>();
}
int maxpathlen; //current max path
int maxheight; //current max height
List<Nodes> pathList;
List<Nodes> heightList;
}
//Signature
public ReturnInfo getMaxPath(Node n);
//Implementation
public ReturnInfo getMaxPath(Node n){
//Base case
if(n==null) return new ReturnInfo();
//This is a bottom up recursion. Info will flow from leaves to root.
//So first recurse and then do the work at this node level
//Recurse left & right
ReturnInfo leftReturnInfo = getMaxPath(n.leftchild);
ReturnInfo rightReturnInfo = getMaxPath(n.rightchild);
//Do work in this recursion or for this node
ReturnInfo retInfo = new ReturnInfo();
//Update all 4 parameters of returninfo and we are done
retInfo.maxheight = max(leftReturnInfo.maxheight, rightReturnInfo.maxheight) + 1;
//Update retInfo.heightList accordingly
retInfo.heightList = ....
retInfo.maxPathLen = max(leftReturnInfo.maxPathLen, rigthReturnInfo.maxPathLen, leftReturnInfo.maxHeight+rightReturnInfo.maxHeight+1);
//Remember from where maxPathLen came from and update accordingly
retInfo.pathList = .....
return retInfo;//We are done
}
You need a function that returns longest branch in a subtree and the longest path:
PS: I am leaving out details (Eg. Boundary conditions and so on). But this should give you an idea. This function returns two things 'branch' and 'path'. 'branch' is the longest path from this node to any of its leaves. 'path' is the longest path between any two leaves in this subtree.
def longestPath(node):
(leftBranch, leftPath) = longestPath(node.left);
(rightBranch, rightPath) = longestPath(node.right);
if len(rightBranch) > len(leftBranch):
curBranch = rightBranch+node.name
else:
curBranch = leftBranch+node.name
curPath = leftBranch + node.name + rev(rightBranch)
bestPath = curPath
if len(leftPath) > length(bestPath):
bestPath = leftPath
if len(rightPath) > length(bestPath):
bestPath = rightPath
return (curBranch, bestPath)
defintion:
node: (char content, node left , node right , node parent)
add(list , node): add node as last element in list
remove(list , index): remove and return element at index in list
length(string): length of string
insert(string , char , index): insert char at index in string
concat(string a , string OR char b): append b to a
input: node start
output: string
start
list nodes
node n
add(nodes , start)
do
n = remove(nodes , 0)
if n.parent != null
add(nodes , n.parent)
if n.left != null
add(nodes , n.left)
if n.right != null
add(nodes , n.right)
while !isEmpty(nodes)
//n now is the node with the greatest distance to start
string left = ""
string right = ""
node a = start
node b = n
while(a != b)
insert(left , a.content , length(left) - 1)
insert(right , b.content , 0)
a = a.parent
b = b.parent
string result = left
concat(result , a.content)
concat(result , right)
return result
Here is my Scala solution (Tree.scala):
/** Searches for the longest possible leaf-to-leaf path in this tree.
*
* Time - O(log^2 n)
* Space - O(log n)
*/
def diameter: List[A] = {
def build(t: Tree[A], p: List[A]): List[A] =
if (t.isEmpty) p
else if (t.left.height > t.right.height) build(t.left, t.value :: p)
else build(t.right, t.value :: p)
if (isEmpty) Nil
else {
val ld = left.diameter
val rd = right.diameter
val md = if (ld.length > rd.length) ld else rd
if (1 + left.height + right.height > md.length)
build(right, value :: build(left, Nil).reverse).reverse
else md
}
}
The idea is quite simple:
We recursively search for diameters in children (ld and rd and maximum 'md').
Check whether the longest possibe path that goes through current node is greather then diameters of its children or not (if (1 + ....)).
If its greater then we just need to build a new path with build function, which bilds a longest path from given node 't' to leaf. So, we just concatenates two resuts of this function (for left and right child) with current node.
If its not greater then the diameter is found it is md.
Longest leaf to leaf path means finding diameter of a tree. It can be done using height function.
There are many solutions available online.
Here is my Swift solution:
func diameterPath() -> [T] {
return diameterPathHelper(root).Path
}
typealias HeightAndDiameterAndPath = (Height: Int, Diameter: Int, Path: [T])
private func diameterPathHelper(node: TreeNode<T>?) -> HeightAndDiameterAndPath {
guard let node = node else {
return HeightAndDiameterAndPath(0, 0, [])
}
let left = diameterPathHelper(node.left)
let right = diameterPathHelper(node.right)
let height = max(left.Height, right.Height) + 1
if left.Height + right.Height + 1 > max(left.Diameter, right.Diameter) {
let currentDiameter = left.Height + right.Height + 1
let path = left.Path + [node.data] + right.Path
return HeightAndDiameterAndPath(height, currentDiameter, path)
} else {
if left.Diameter > right.Diameter {
return HeightAndDiameterAndPath(height, left.Diameter, left.Path)
} else {
return HeightAndDiameterAndPath(height, right.Diameter, right.Path)
}
}
}
We can use the maxdepth approach for this and initialize a variable max as 0.
public int diameterOfBinaryTree(TreeNode root) {
maxDepth(root);
return max;
}
private int maxDepth(TreeNode root) {
if (root == null) return 0;
int left = maxDepth(root.left);
int right = maxDepth(root.right);
max = Math.max(max, left + right);
return Math.max(left, right) + 1;
}
}
You have neglected one condition: What if the longest path doesn't pass through the root node?
static int findLongestPathLength(Node root){
if(root == null)
return 0;
int lh = getHeight(root.left);
int rh = getHeight(root.right);
return Math.max(1+lh+rh,
Math.max(findLongestPathLength(root.left),findLongestPathLength(root.right)));
}
static int getHeight(Node root){
if(root == null)
return 0;
return Math.max(getHeight(root.left)+1, getHeight(root.right)+1);
}
This will also make sure it find the longest path even if it doesn't pass through root.

Resources