I am a beginner to binary trees and have been working my way through the algorithms book. I have learnt about the various traversal methods of BSTs (pre-order, post order etc).
Could someone please explain how one can traverse a BST to count the number of nodes that are leaves (no children) please?
Many thanks!
Use a recursive method:
For a leaf return 1.
For a non-leaf, return the sum of that method applied to its children.
Example in PHP:
class BST {
public $left; // The substree containing the smaller entries
public $right; // The substree containing the larger entries
public $data; // The value that is stored in the node
}
function countLeafs(BST $b) {
// Test whether children exist ...
if ($b->left || $b->right) {
// ... yes, the left or the right child exists. It's not a leaf.
// Return the sum of calling countLeafs() on all children.
return ($b->left ? countLeafs($b->left) : 0)
+ ($b->right ? countLeafs($b->right) : 0);
} else {
// ... no, it's a leaf
return 1;
}
}
The different traversal methods would lead to different algorithms (although for a simple problem like this, all DFS variants are more or less the same).
I assume that you have a BST which consists of objects of type Node. A node has two fields left and right of type Node, which are the children of the node. If a child is not present, the value of that field is null. The whole tree is referenced by a reference to the root, called root. In java:
class Node {
public Node left;
public Node right;
}
Node root;
A DFS is easiest to implement by recursion: define a method
int numberOfLeafs(Node node)
which returns the number of leafs in the subtree rooted by node. Of course, numberOfLeafs(root) should yield the number of leafs of the whole tree.
As said, it is really artificial to distinguish pre-, in-, and post-order traversal here, but I'm gonna do it anyway:
Pre-order DFS: First deal with the current node, then with the children
int numberOfLeafs(Node node) {
int result = 0;
if (node.left == null && node.right == null)
result += 1;
if (node.left != null)
result += numberOfLeafs(node.left)
if (node.right != null)
result += numberOfLeafs(node.right)
return result;
}
In-order DFS: First deal with the left child, then with the current node, then with the right child
int numberOfLeafs(Node node) {
int result = 0;
if (node.left != null)
result += numberOfLeafs(node.left)
if (node.left == null && node.right == null)
result += 1;
if (node.right != null)
result += numberOfLeafs(node.right)
return result;
}
Post-order DFS: First deal with the children, then with the current node
int numberOfLeafs(Node node) {
int result = 0;
if (node.left != null)
result += numberOfLeafs(node.left)
if (node.right != null)
result += numberOfLeafs(node.right)
if (node.left == null && node.right == null)
result += 1;
return result;
}
For a BFS, you typically use a simple loop with a queue in which you add unvisited vertices. I now assume that I have a class Queue to which I can add nodes at the end and take nodes from the front:
Queue queue = new Queue();
queue.add(root);
int numberOfLeafs = 0;
while (!queue.empty) {
// take an unhandled node from the queue
Node node = queue.take();
if (node.left == null && node.right == null)
numberOfLeafs += 1;
if (node.left != null)
queue.add(node.left);
if (node.right != null)
queue.add(node.right);
}
try this
int countLeafNodes(BTNode node) {
if (node == null)
return 0;
if (node.getLeftChild() == null && node.getRightChild() == null
&& node.getParent() != null)//this is a leaf, no left or right child
return 1;
else
return countLeafNodes(node.getLeftChild())
+ countLeafNodes(node.getRightChild());
}
which recursively counts leaf nodes for left and right sub trees and returns the total count
Related
I have question on whether my analysis of runtime and space for algorithm that determine whether a tree S contains a subtree that is exactly the same tree as other tree T My code is as follows:
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root == null) return subRoot == null;
return isSameTree(root, subRoot) ||
isSubtree(root.left, subRoot) ||
isSubtree(root.right, subRoot);
}
public boolean isSameTree(TreeNode root, TreeNode subRoot) {
if(root == null) return subRoot == null;
if(subRoot == null) return false;
return root.val == subRoot.val &&
isSameTree(root.left, subRoot.left) && isSameTree(root.right, subRoot.right);
}
}
I think the time is O(S * min(S, T)) where S and T are total number of node of tree s and t respectively, and space is O(max(S, T)). I got the time because we are performing dfs on every node of tree s to determine whether it is the same as tree t, and each dfs takes minimum of node of s and t, and space is because our recursion call stack can at most contain minimum of two tree's node, if smaller tree hits null case while dfsing with larger tree, we will just return
You don't need to check on subRoot being null as it is invalid that null is subtree of null. So, in that case you can return false. Please use this code for your reference and time
complexity O(mn), where m = |nodes| ∈ root and n = |nodes| ∈ subRoot
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root == null)
return false;
if (isSameTree(root, subRoot))
return true;
return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
}
public boolean isSameTree(TreeNode root, TreeNode subRoot) {
if(root==null || subRoot==null)
return root==subRoot;
return root.val == subRoot.val && isSameTree(root.left, subRoot.left) && isSameTree(root.right, subRoot.right);
}
}
Here is the pseudo code that wikipedia gives for iterative postorder tree traversal.
iterativePostorder(node)
parentStack = empty stack
lastnodevisited = null
while (not parentStack.isEmpty() or node ≠ null)
if (node ≠ null)
parentStack.push(node)
node = node.left
else
peeknode = parentStack.peek()
if (peeknode.right ≠ null and lastnodevisited ≠ peeknode.right)
/* if right child exists AND traversing node from left child, move right */
node = peeknode.right
else
visit(peeknode)
lastnodevisited = parentStack.pop()
It is pretty straight forward, and I have implemented it in Java. But it does not work, the problem is that every time it visits the most left leaf and return to its parent, it will add that left leaf again into the stack in next iteration. This causes an infinite loop. Is my method incorrect or the wikipedia version is wrong?
public static List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) return res;
Stack<TreeNode> s = new Stack<TreeNode>();
TreeNode lastVisitedNode = null;
TreeNode curr = root;
int i = 0;
while (curr != null || !s.isEmpty()) {
if (curr != null) {
System.out.println("push " + curr.val);
s.push(curr);
curr = curr.left;
} else {
curr = s.peek();
if (curr.right != null && lastVisitedNode != curr.right) {
curr = curr.right;
} else {
res.add(curr.val);
System.out.println("pop " + curr.val);
lastVisitedNode = s.pop();
}
}
System.out.println(s);
System.out.println(res);
if (i>8) break;
else i++;
}
return res;
}
The wikipedia version is wrong for the exact same reason as you've explained it.
Here is a probably better pseudo-code, from geeksforgeeks
1.1 Create an empty stack
2.1 Do following while root is not NULL
a) Push root's right child and then root to stack.
b) Set root as root's left child.
2.2 Pop an item from stack and set it as root.
a) If the popped item has a right child and the right child
is at top of stack, then remove the right child from stack,
push the root back and set root as root's right child.
b) Else print root's data and set root as NULL.
2.3 Repeat steps 2.1 and 2.2 while stack is not empty.
You will have to add extra code to check if the node right child is null in 2.1.a though.
The wikipedia pseudocode is not wrong. They use two different variables: node and peekNode, while you only use curr for both. Node == null refers to the case when there is no more of a left branch left to explore, so we can stop pushing and instead investigate the next element in the stack. You can either revert to using two different variables, or you make the following fix in your code:
Since you reassign curr to a non-null value everytime you investigate the stack, you need to reset curr to null after you visit your node. (Because the state that still no more left branch left to explore is still unchanged).
The wikipedia pseudocode doesn't have to do this because their node value remains null.
Here is my code which gives a perfect answer:
var currentNode = this.root()
var previousNode = null
while(!nodeStack.isEmpty() || currentNode) {
// If there is a node on which the recursive call is made, we have a subtree to explore. If this is null, we have to backtrack and do a callback.
if (currentNode) {
nodeStack.push(currentNode)
previousNode = currentNode
currentNode = currentNode.leftChild
} else {
currentNode = nodeStack.peek()
if (currentNode.rightChild && previousNode != currentNode.rightChild) {
currentNode = currentNode.rightChild
} else {
callback(currentNode)
currentNode = null
previousNode = nodeStack.pop()
}
}
}
I'm trying this question for sometime but couldn't figure out the algorithm. My preference is to do it iteratively. Till now, I've figure out something but not sure on some point.
Currently, My algorithm looks like:
First traverse the tree to find the node
While traversing the tree, keep track of the previous node.
if you find the node, check if left child is present then that is successor return.
if left child is not present then check if right child is present the that is successor and return.
if the node(is left to the parent) and don't have left or right child then we've saved the prev node earlier then either prev or prev's right child is the successor.
But what if the node we found is in the right to parent and don't have left or right child how to find successor of this node?
May be there are many flaws in this algorithm as still I've not understand all the cases properly. If anyone has any idea or algorithm please share.
Thanks in advance.
when you find a node in preorder, to find its successor is just travesing to its next node.
what I was thinking first is the relationship of a node and its successor's values in pre-oder, but I found that it seems not very clear like the relationship in in-order. I think there is only one step beteen a node and its successor(if exists) : just move on travesing. So I design this algorithm.
my algorithm below is based on preorder travesal, it can run on a binary tree,not only BST.
#define NOT_FOUND -1
#define NEXT 0
#define FOUND 1
struct node {
struct node *p;//parent,but useless here
struct node *l;//left child
struct node *r;//right child
int value;
};
int travese(struct node* bnode, int* flag,int value)
{
if(bnode == NULL)
return 0;
else
{
if(*flag == FOUND)
//when the successor is found,do pruning.
return 1;
else if(*flag == NEXT) {
printf("successor:%d\n",bnode->value);
*flag = FOUND;
return 1;
}
else if(*flag == NOT_FOUND && bnode->value == value)
*flag = NEXT;
travese(bnode->l,flag,value);
travese(bnode->r,flag,value);
}
return 0;
}
and use it by:
int flag = NOT_FOUND;
travese(root,&flag,value);
if(flag == NEXT || flag == NOT_FOUND)
printf("no successor.\n");
EDIT:
turning a recurrence algorithm to a iterative one is not difficult by using a stack like below:
int preorder_travese_with_stack(struct node* bnode, int* flag,int value)
{
if(bnode == NULL)
return 0;
struct stack s;//some kind of implement
push(s,bnode);
while(NotEmpty(s) && *flag) {
struct node *curNode = pop(s);
if(*flag == NEXT) {
printf("successor:%d\n",curNode->value);
*flag = FOUND;
return 1;
}
else if(*flag == NOT_FOUND && curNode->value == value)
*flag = NEXT;
push(s,curNode->r);
push(s,curNode->l);
}
return 0;
}
but according to your comment and original description, I think the one you want is iterative algorithm without a stack.here it is.
After thinking ,searching and trying, I wrote one. When travse the tree iteratively without stack , the parent of a node is not useless any more. In a path, some nodes is visited not only once, and you need to record its direction at that time.
int preorder_travese_without_stack(struct node *root,int value,int *flag)
{
int state=1;
//state: traveral direction on a node
//1 for going down
//2 for going up from its left chlid
//3 for going up from its right child
struct node *cur = root;
while(1) {
if(state == 1) //first visit
{
//common travese:
//printf("%d ",cur->value);
if(cur->value == value && *flag == NOT_FOUND)
*flag = NEXT;
else if (*flag==NEXT) {
*flag = FOUND;
printf("successor:%d\n",cur->value);
break;
}
}
if((state == 1)&&(cur->l!=NULL))
cur = cur->l;
else if((state==1)&&(cur->l==NULL))
{
state = 2;
continue;
}
else if(state==2) {
if(cur->r != NULL ) {
cur=cur->r;
state = 1;
}
else
{
if(cur->p!=NULL)
{
if(cur==cur->p->r)
state = 3;
//else state keeps 2
cur=cur->p;
}
else //cur->p==NULL
{
if(cur->p->r!=NULL)
{
cur=cur->p->r;
state = 1;
}
else
break;
//end up in lchild of root
//because root's rchild is NULL
}
}
continue;
}
else //state ==3
{
if(cur->p!=NULL)
{
if(cur==cur->p->l)
state = 2;
else
state = 3;
cur=cur->p;
continue;
}
else
break;
}
}
}
the usage is the same as the first recurrence one.
If you are confused yet,mostly about the direction of a node , you can draw a tree and draw the path of pre-order traverse on paper,it would help.
I'm not sure there are bugs left in the code,but it works well on the tree below:
0
/ \
1 2
/ \ / \
3 4 5 6
btw,"wirte down pre-order (or else) travese algorithm of a tree both by recurrence and iteration" is a common interview problem, although solving the latter by a stack is permitted.but I think the BST requirement is unnecessary in pre-order travese.
My implementation of the algorithm does not use the key. Therefore it is possible to use it in any kind of binary tree, not only in Binary search trees.
The algorith I used is this:
if given node is not present, return NULL
if node has left child, return left child
if node has right child, return right child
return right child of the closest ancestor whose right child is present and not yet processed
Bellow there is my solution.
TreeNode<ItemType>* CBinaryTree<ItemType>::succesorPreOrder(TreeNode<ItemType> *wStartNode)
{
//if given node is not present, return NULL
if (wStartNode == NULL) return NULL;
/* if node has left child, return left child */
if (wStartNode->left != NULL) return wStartNode->left;
/* if node has right child, return right child */
if (wStartNode->right != NULL) return wStartNode->right;
/* if node isLeaf
return right child of the closest ancestor whose right child is present and not yet processed*/
if (isLeaf(wStartNode)) {
TreeNode<ItemType> *cur = wStartNode;
TreeNode<ItemType> *y = wStartNode->parent;
while (y->right == NULL && y->parent!=NULL){
cur = y;
y = y->parent;
}
while (y != NULL && cur == y->right) {
cur = y;
y = y->parent;
}
return y->right;
}
}
bool CBinaryTree<ItemType>::isLeaf(TreeNode<ItemType> *wStartNode){
if (wStartNode->left == NULL && wStartNode->right == NULL) return true;
else return false;
};
Since I could not find anything useful so I am here to ask my question:
How can we convert the BST to a In-order linklist, and back to "same" BST, without using any extra space.
What I have tried so far (still doing though): I tried Morris Traversal to link up to the next in-order successor,
but it is not able to connect for all the nodes, only working for the left subtree, and right subtree, not for the actual root of the tree.
Please suggest how can I convert Tree to Linked List and back to Same tree...
To store a tree in lists - you need at least two lists: one for pre-order traversal, and the other for in-order traversal.
Luckily - since the tree is a BST, the in-order traversal is just the sorted list.
So, you can store the pre-order traversal (You can try doing it in-place) and by sorting the elements in re-construction, you can get the in-order traversal.
This post discusses how to reconstruct a tree from the inorder and pre-order traversals of it.
Binary Search Tree to List:
subTreeToList(node)
if (node.hasLeft()) then subTreeToList(node.left, list)
list.add(node.Value)
if (node.hasRight()) subTreeToList(node.right, list)
end if
subTreeToList end
treeToList(tree)
subTreeToList(tree.root)
treeToList end
list <- new List()
treeToList(tree)
You need to implement the idea above into your solution, if you are working with object-oriented technologies, then list and trees should be data members, otherwise they should be passed to the functions as references.
You can build back your tree knowing that insertion in the tree looks like this:
Insert(tree, value)
if (tree.root is null) then
tree.createRoot(value)
else
node <- tree.root
while (((node.value < value) and (node.hasRight())) or ((node.value > value) and (node.hasLeft())))
if ((node.value < value) and (node.hasRight())) then node <- node.right()
else node <- node.left()
end if
while end
if (node.value > value) then node.createLeft(value)
else node.createRight(value)
end if
end if
insert end
You just have to traverse your list sequentially and call the function implemented based on my pseudo-code above. Good luck with your homework.
I think I found the solution myself: below is the complete Java implementation
The logic + pseudo Code is as below
[1] Find the left most node in the tree, that will be the head of the LinkList, store it in the class
Node HeadOfList = null;
findTheHeadOfInorderList (Node root)
{
Node curr = root;
while(curr.left != null)
curr = curr.left;
HeadOfList = curr; // Curr will hold the head of the list
}
[2] Do the reverse - inorder traversal of the tree to convert it to a LL on right pointer, and make sure the left pointer is always pointing to the parent of the node.
updateInorderSuccessor(Node root, Node inorderNext, Node parent)
{
if(root != null)
//Recursively call with the right child
updateInorderSuccessor(root.right, inorderNext, root);
// Update the in-order successor in right pointer
root.right = inorderNext;
inorderNext = root;
//Recursively call with the left child
updateInorderSuccessor(root.left, inorderNext, root);
// Update the parent in left pointer
root.left = parent;
}
}
[3] To convert it back :
Traverse the list and find the node with left pointer as null,
Make it the root, break the link of this root in the linklist and also from its children...
Now the link list is broken into two parts one for left Subtree and one for right subtree,
recursively find the roots in these two list and make them the left and right child, Please refer the function restoreBST()
Node restoreBST(Node head)
{
if(head == null || (head.left == null && head.right == null)) return root;
Node prev, root, right, curr;
curr = head;
// Traverse the list and find the node with left as null
while(curr != null)
{
if(curr.left == null)
{
// Found the root of this tree
root = curr;
// Save the head of the right list
right = curr.right;
// Detach the children of the root just found, these will be updated later as a part of the recursive solution
detachChildren(curr, head);
break;
}
prev = curr;
curr = curr.right;
}
// By now the root is found and the children of the root are detached from it.
// Now disconnect the right pointer based connection in the list for the root node, so that list is broken in to two list, one for left subtree and one for right subtree
prev.right = null;
root.right = null;
// Recursively call for left and right subtree
root.left = restoreBST(head);
root.right = restoreBST(right);
//now root points to its proper children, lets return the root
return root;
}
Logic to detach the children is simple : Iterate through the list and look for the nodes with left pointer equal to root.
private void detachChildren(AvlNode root, AvlNode head) {
AvlNode curr = head;
while(curr != null)
{
if(curr.left == root)
{
curr.left = null;
}
curr = curr.right;
}
}
Here is a recursive solution for BST to LL, hope you find it useful.
Node BSTtoLL(BST root) {
if(null == root) return null;
Node l = BSTtoLL(root.left);
Node r = BSTtoLL(root.right);
Node l1 = null;
if(null != l) {
l1 = l;
while(null != l.left) { l = l.left; }
l.left = root;
l.right = null;
}
if(null != r) {
root.left = r;
root.right = null;
}
if(null != l1) return l1;
return root;
}
Given a node with the following structure
class Node {
int data,
Node* P1,
Node* p2;
}
We need to determine, if the node represents a Circular Doubly Link List OR a Binary Tree.
In my opinion We need to start traversing the given node in one direction
node = givenNode;
while(node->P1 != null && node->P1 != givenNode)
{
node = node->p1
}
if(node == givenNode) // It means Circular DLL
else if(node == null) // It means Tree
And it would take O(n) time to detect this.
Please suggest if there is any better approach than this.
I suggest you could check if its a doubl-linked list or not with this piece of code:
node = givenNode;
if(givenNode->P1 == null || givenNode->P2 == null)
// It can not be double link list (circular)
else if(givenNode->p1->p2 == givenNode || givenNode->p2->p1 == givenNode)
{
//It is a double linked list
}
else
{
It is not a double linked list
}
And we have O(1) complexity