Is there a way without using extra space to find LCA of nary tree.
I did it using a string saving the preorder of both the nodes and finding common prefix
If nodes "know" their depth - or you're willing to allow the space to compute the depth of your nodes, you can back up from the lower node to the same depth of the higher node, and then go up one level at a time until they meet.
Depends on what "extra space" means in this context. You can do it with one integer - the difference in depths of the two nodes. Is that too much space?
Another possibility is given you don't have a parent pointer, you can use pointer reversal - every time you traverse a pointer, remember the location from which you came, remember the pointer you will next traverse, and then just before the next pointer traversal, replace that pointer with the back pointer. You have to reverse this when going up the tree to restore it. This takes the space of one pointer as a temporary. And another integer to keep the depth as you work your way down and up. Do this synchronously for the two nodes you seek, so that you can work your way back up from the lower one until you're at the same height in both traversals, and then work back up from both until you're at the common node. This takes three extra pieces of memory - one for each of the current depths, one for the temporary used during a pointer reversal. Very space efficient. Is it worth it?
Go back and do it for a binary tree. If you can do it for a binary tree you can do it for an n-ary tree.
Here's a link to LCA in a binary tree:
And here's how it looks after converting it to a n-ary tree LCA:
public class LCA {
public static <V> Node<V>
lowestCommonAncestor(Node<V> argRoot, Node<V> a, Node<V> b) {
if (argRoot == null) {
return null;
}
if (argRoot.equals(a) || argRoot.equals(b)) {
// if at least one matched, no need to continue
// this is the LCA for this root
return argRoot;
}
Iterator<Node<V>> it = argRoot.childIterator();
// nr of branches that a or b are on,
// could be max 2 (considering unique nodes)
int i = 0;
Node<V> lastFoundLCA = null;
while (it.hasNext()) {
Node<V> node = lowestCommonAncestor(it.next(), a, b);
if (node != null) {
lastFoundLCA = node;
i++ ;
}
if (i >= 2) {
return argRoot;
}
}
return lastFoundLCA;
}
}
Do a synchronous walk to both the nodes.
Start with LCA=root;
loop:
find the step to take for A and the step for B
if these are equal { LCA= the step; decend A; descend B; goto loop; }
done: LCA now contains the lca for A and B
Pseudocode in C:
struct node {
struct node *offspring[1234];
int payload;
};
/* compare function returning the slot in which this should be found/placed */
int find_index (struct node *par, struct node *this);
struct node *lca(struct node *root, struct node *one, struct node *two)
{
struct node *lca;
int idx1,idx2;
for (lca=root; lca; lca=lca->offspring[idx1] ) {
idx1 = find_index(lca, one);
idx2 = find_index(lca, two);
if (idx1 != idx2 || idx1 < 0) break;
if (lca->offspring[idx1] == NULL) break;
}
return lca;
}
Related
I know about algorithm to level order traversal of a tree. (I think everybody knows about that) That algorithm uses queue to store the nodes of the tree. Is there a algorithm that do not uses additional memory? That algorithm must not use recursion (in that way we are using stack). Note, that tree is given in left-child right-sibling representation. No additional pointers are allowed.
The structures in C, for the tree are:
struct node {
int data;
struct node *left-child;
struct node *right-sibling;
}
Tree is represented with a pointer to the root node. Of course, root cannot have right-sibling.
One way could be to use the right-sibling pointers which are null, to make all nodes siblings of each other (temporarily).
You could use a slow and fast pointer. The fast one would always be at the last sibling (that has a null pointer as right-sibling). The left-child pointer of the slow node would then be copied into that right-sibling, after which the fast pointer runs further to the end again. The slow pointer goes one step to the right and the same repeats. When the slow pointer also reaches the end, all nodes will be siblings. Either the slow or fast pointer can be used to output the values in the level-order. This will do the job, but the tree will have been destroyed as a consequence.
To restore the tree, I would suggest that during the above process the direction of all sibling edges is reversed. This means you need to have another pointer that lags behind the slow pointer. This will allow the reversal to be performed between those two. This is a bit obscure, because the right-sibling will then in fact point to something that is mostly a left sibling.
After the above process, the pointers will be at the end of the node list, but because we have reversed the sibling edges, we can also walk back and reverse the edges again. One difficulty is to know which sibling pointers should become null again (for when a node was originally a right most child). This can be done by having again a fast pointer moving ahead (in the left direction) to find nodes that have child. If the pointer that lags behind the slow pointer hits such a child, we know that the slow pointer's node should get a null pointer as right-sibling. When this fix is applied, the fast pointer should again run ahead to find yet another parent node, ...etc.
Note that the left-child pointers are not altered by this algorithm.
So, in total this solution uses three pointers and the structure of the tree itself.
Here is a sample tree I have used in an implementation below:
1
/
2 ------------ 3 ---------4
/ / /
5 -- 6 -- 7 8 -- 9 10 -- 11 -- 12 -- 13
/ /
14 -- 15 -- 16 17 -- 18 -- 19
Implementation in JavaScript -- runnable snippet:
function * traverse(node) {
let lead = node; // ...walks somewhere ahead of node
let lag = null; // ... always follows one step behind node
while (node) {
yield node.data; // output
lead.rightSibling = node.leftChild;
while (lead.rightSibling) lead = lead.rightSibling;
// rotate: point node to next right-sibling, and reverse direction of sibling edge
[node.rightSibling, lag, node] = [lag, node, node.rightSibling]
}
// Restore tree
lead = node = lag.rightSibling; // backwards
lag.rightSibling = null;
while (lead !== null && lead.leftChild === null) lead = lead.rightSibling; // actually going left!
while (node) {
if (lead !== null && lead.leftChild === lag) {
// When lag is the leftChild of some node (lead), then lag should not be the target of a rightSibling
[node.rightSibling, lag, node] = [null, node, node.rightSibling];
// Find previous parent
lead = lead.rightSibling;
while (lead !== null && lead.leftChild === null) lead = lead.rightSibling; // actually going left!
} else {
// walk back and restore sibling pointers
[node.rightSibling, lag, node] = [lag, node, node.rightSibling];
}
}
}
// Create node, given its data and child nodes
function Node(data, ...children) {
// Link the children as siblings
if (children.length > 1) children.reduceRight((a, b) => (b.rightSibling = a, b))
// Create the node itself. For now, without any siblings
return {
data,
leftChild: children.length ? children[0] : null,
rightSibling: null
};
}
// Example tree
let tree = Node(1,
Node(2,
Node(5), Node(6,
Node(14), Node(15), Node(16)
), Node(7)
), Node(3,
Node(8), Node(9)
), Node(4,
Node(10), Node(11,
Node(17), Node(18), Node(19)
), Node(12), Node(13)
)
);
// Apply the algorithm and output the yielded values
console.log(...traverse(tree));
Version in C
I am not so fluent in C, but I think this should do it:
#include <stdio.h>
#include <stdlib.h>
// define Node as a pointer to a node struct
typedef struct node {
int data;
struct node *leftChild;
struct node *rightSibling;
} * Node;
// Some helper functions to ease the creation of a tree:
Node sibling(Node leftSibling, Node rightSibling) {
leftSibling->rightSibling = rightSibling;
return leftSibling;
}
Node parent(Node parent, Node child) {
parent->leftChild = child;
return parent;
}
Node create(int data) {
Node node = malloc(sizeof(struct node));
node->data = data;
return node;
}
// end - helper functions
void traverse(Node node) {
Node lead = node; // ...walks somewhere ahead of node
Node lag = NULL; // ... always follows one step behind node
while (node) {
printf("%d\n", node->data); // output
lead->rightSibling = node->leftChild;
while (lead->rightSibling) lead = lead->rightSibling;
// rotate: point node to next right-sibling, and reverse direction of sibling edge
Node temp = node->rightSibling;
node->rightSibling = lag;
lag = node;
node = temp;
}
// Restore tree
lead = node = lag->rightSibling; // backwards
lag->rightSibling = NULL;
while (lead != NULL && lead->leftChild == NULL) lead = lead->rightSibling; // actually going left!
while (node != NULL) {
if (lead != NULL && lead->leftChild == lag) {
// When lag is the leftChild of some node (lead), then lag should not be the target of a rightSibling
lag = node;
node = node->rightSibling;
lag->rightSibling = NULL;
// Find previous parent
lead = lead->rightSibling;
while (lead != NULL && lead->leftChild == NULL) lead = lead->rightSibling; // actually going left!
} else {
// walk back and restore sibling pointers
Node temp = node->rightSibling;
node->rightSibling = lag;
lag = node;
node = temp;
}
}
}
int main(void) {
// Create the example tree
Node root = parent(create(1),
sibling(parent(create(2),
sibling(create(5), sibling(parent(create(6),
sibling(create(14), sibling(create(15), create(16)))
), create(7)))
), sibling(parent(create(3),
sibling(create(8), create(9))
), parent(create(4),
sibling(create(10), sibling(parent(create(11),
sibling(create(17), sibling(create(18), create(19)))
), sibling(create(12), create(13))))
)))
);
traverse(root);
return 0;
}
To print the tree in a very basic format, you can use this function:
void printTree(Node node, int indent) {
if (!node) return;
for (int i = 0; i < indent; i++) printf(" ");
printf("%d\n", node->data);
printTree(node->leftChild, indent+1);
printTree(node->rightSibling, indent);
}
This will help to verify that indeed the tree is the same before and after the traversal.
If you can store an extra next pointer in each node of the tree which points to the next node in level order for each level, then you can do the level order traversal in constant space.
You can apply Morris level order traversal if you want to traverse your tree in constant space.You can refer here and here.
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|).
Here's the algorithm I came up with for non-recursively finding the lowest common ancestor of two nodes in a binary tree. Here's the basic strategy:
Use a dictionary/hashtable to store the tree. Each key-value pair represents a node and its parent.
Starting from each of the two nodes, walk up the tree by setting the variable representing each node's value to that of its parent, storing traversed values in a hashset (one for each of the two nodes).
The search is complete when any of the following conditions are reached: (a) the value of the two nodes is equal; or (b) when the two paths cross each other (i.e., the hashset of node 1's traversed values contains the current value for node 2, or vice versa); or (c) the node passed in doesn't exist in the tree (in which case the algorithm terminates and returns -1).
My understanding is that the worst-case time and space complexity of my algorithm is O(log(n)), since we never need to make more than 2 * height traversals or store more than 2 * height values in our hashsets (and since the lookup time for the hashsets and the tree dictionary are O(1)).
Following is my code (C#). Please advise if I am correct in my analysis, or if there is a more efficient (non-recursive) way to do this:
int LowestCommonAncestor(int value1, int value2, Dictionary<int, int> tree)
{
var value1Visited = new HashSet<int>();
var value2Visited = new HashSet<int>();
while (true)
{
if (value1 == value2) return value1;
if (value1Visited.Contains(value2)) return value2;
if (value2Visited.Contains(value1)) return value1;
int nextValue1;
int nextValue2;
if (tree.TryGetValue(value1, out nextValue1))
{
//Walk node 1 up the tree:
value1 = nextValue1;
value1Visited.Add(value1);
}
else
{
//Node doesn't exist in tree:
return -1;
}
if (tree.TryGetValue(value2, out nextValue2))
{
//Walk node 2 up the tree:
value2 = nextValue2;
value2Visited.Add(value2);
}
else
{
//Node doesn't exist in tree:
return -1;
}
}
}
Go up from each node to the root to measure its depth
Move up the path from the deeper node until you get to the same depth as the shallower one.
Move up the paths from both nodes (i.e., keeping the same depth on both paths) until they meet.
You don't need two hash sets.
Go up and collect in a single hash set the ancestors of one node
Go up from the second node and at each of its ancestors, check if the path collected at step 1 contains the current ancestor of the second. Stop at the first common one.
With D being the max depth of the tree, the complexity is O(D) worst-case complexity.
The worst case complexity in N - number of nodes - when the tree is degenerated in a list, one of the node being the head of this list and the other is the tail.
If the tree is balanced, D=log(N) - with log's base being the number of descendents of a node (binary - log2, ternary - log3, etc).
Here, then, is my revised algorithm:
int LCA(int value1, int value2, Dictionary<int, int> tree)
{
if (!tree.ContainsKey(value1) || !(tree.ContainsKey(value2))) return -1;
int depth1 = 0;
int depth2 = 0;
int tmpVal1 = value1;
int tmpVal2 = value2;
while (tmpVal1 != -1)
{
tmpVal1 = tree[tmpVal1];
depth1++;
}
while (tmpVal2 != -1)
{
tmpVal2 = tree[tmpVal2];
depth2++;
}
if (depth1 > depth2)
{
while (depth1 > depth2)
{
value1 = tree[value1];
depth1--;
}
}
else if (depth2 > depth1)
{
while (depth2 > depth1)
{
value2 = tree[value2];
depth2--;
}
}
while (value1 != value2)
{
value1 = tree[value1];
value2 = tree[value2];
}
return value1;
}
How are non binary trees typically represented? Trees where there is no limit to the number of children a node can have. Is it best to use a Adjacency Matrix or Adjacency List and just assume there will be no cycles, or do something similar to this question ->
How to implement a Non-Binary tree
and follow up question, when you have a n-ary tree (is that the correct name for them?) What's a good way to find the Least Common Ancestor for two given nodes/data values in that tree? All I can find are algorithms that deal with binary trees, like this one ->
static Node lca(Node root,int v1,int v2)
{
if (root == null || root.data == v1 || root.data == v2) {
return root;
}
Node left = lca(root.left, v1, v2);
Node right = lca(root.right, v1, v2);
if (left != null && right != null) {
return root;
}
return (left != null) ? left : right;
}
Adjacency matrix sounds like a bad idea, it will be very sparse (most cells will be empty). Usually for n-ary trees (yes that's how they are called) you just follow the same strategy as with the binary tree, the difference is that a binary tree would have 2 fields representing the left and right children:
class Node<T> {
T value;
Node<T> left;
Node<T> right;
}
Here you change those fields into a data structure like an array (static or dynamic):
class Node<T> {
T value;
List<Node<T>> children;
}
As for the LCA, are you planning on storing the parent pointer in the nodes? Are the values supposed to be a tree with unique values? Will the values be ordered in any way?
If no, but you can assume that the nodes are in the tree (although handling the other case is not that hard) then the LCA is very similar to what you've shown above. You just need to change the part where you get the Node left and Node right so that it traverses all children:
int count = 0;
Node<T> temp = null;
for(Node<T> child : root.children) {
Node<T> result = lca(child, v1, v2);
if(result != null) {
count++;
temp = result;
}
}
if(count == 2) {
return root;
}
return temp;
With parent pointers and/or storing the dept in each node we can do better but at a storage cost.
Given a binary tree, how would you join the nodes at each level, left to right.
Say there are 5 nodes at level three, link all of them from left to right.
I don't need anybody to write code for this.. but just an efficient algorithm.
Thanks
Idea is:
1. Traverse tree with BFS.
2. When you do traversing, you're linking nodes on next level - if node has left and right node, you'll link left to right. If node has next node, then you link rightmost child of current node to leftmost child of next node.
public void BreadthFirstSearch(Action<Node> currentNodeAction)
{
Queue<Node> q = new Queue<Node>();
q.Enqueue(root);
while (q.Count != 0)
{
Node current = q.Dequeue();
if (currentNodeAction != null)
currentNodeAction(current);
if (current.left != null) q.Enqueue(current.left);
if (current.right != null) q.Enqueue(current.right);
}
}
private void Linker(Node node)
{
Link(node.left, node.right);
if (node.next != null)
Link(node.right ?? node.left, node.next.left ?? node.next.right);
}
private void Link(Node node1, Node node2)
{
if (node1 != null && node2 != null)
node1.next = node2;
}
public void LinkSameLevel()
{
BreadthFirstSearch(Linker);
}
Create a vector of linked lists.
Do a DFS keeping track of your level, and for each node you find, add it to the linked list of the level.
This will run in O(n) which is optimal.
Is this what you want to do?
This is not a direct answer to the question and may not be applicable based on your situation. But if you have control over the creation and maintenance of the binary tree, it would probably be more efficient to maintain the links while building/updating the tree.
If you kept both left and right pointers at each level, then it would be "simple" (always easy to say that word when someone else is doing the work) to maintain them. When inserting a new node at a given level, you know its direct siblings from the parent node information. You can adjust the left and right pointers for the three nodes involved (assuming not at the edge of the tree). Likewise, when removing a node, simply update the left and right pointers of the siblings of the node being removed. Change them to point to each other.
I agree with Thomas Ahle's answer if you want to make all of the row-lists at the same time. It seems that you are only interested in making the list for a one specific row.
Let's say you have a giant tree, but you only want to link the 5th row. There's clearly no point in accessing any node below the 5th row. So just do an early-terminated DFS. Unfortunately, you still have to run through all of the ancestors of every node in the list.
But here's the good news. If you have a perfect binary tree (where every single node branches exactly twice except for the last row) then the first row will have 1 one, the second 2, the third 4, the fourth 8 and the fifth 16. Thus there are more nodes on the last row (16) than all the previous put together (1 + 2 + 4 + 8 = 15), so searching through all of the ancestors is still just O(n), where n is the number of nodes in the row.
The worst case on the other hand would be to have the fifth row consist of a single node with a full binary tree above it. Then you still have to search through all 15 ancestors just to put that one node on the list.
So while this algorithm is really your only choice without modifying your data structure its efficiency relies entirely on how populated the row is compared to higher rows.
#include <queue>
struct Node {
Node *left;
Node *right;
Node *next;
};
/** Link all nodes of the same level in a binary tree. */
void link_level_nodes(Node *pRoot)
{
queue<Node*> q;
Node *prev; // Pointer to the revious node of the current level
Node *node;
int cnt; // Count of the nodes in the current level
int cntnext; // Count of the nodes in the next level
if(NULL == pRoot)
return;
q.push(pRoot);
cnt = 1;
cntnext = 0;
prev = NULL;
while (!q.empty()) {
node = q.front();
q.pop();
/* Add the left and the right nodes of the current node to the queue
and increment the counter of nodes at the next level.
*/
if (node->left){
q.push(node->left);
cntnext++;
}
if (node->right){
q.push(node->right);
cntnext++;
}
/* Link the previous node of the current level to this node */
if (prev)
prev->next = node;
/* Se the previous node to the current */
prev = node;
cnt--;
if (0 == cnt) { // if this is the last node of the current level
cnt = cntnext;
cntnext = 0;
prev = NULL;
}
}
}
What I usually do to solve this problem is that I do a simple inorder traversal.
I initialize my tree with a constructor that gives a level or column value to every node. Hence my head is at Level 0.
public Node(int d)
{
head=this;
data=d;
left=null;
right=null;
level=0;
}
Now, if in the traversal, I take a left or a right, I simply do the traversal with a level indicator. For each level identifier, I make a Linked List, possibly in a Vector of Nodes.
Different approaches can be used to solve this problem. Some of them that comes to mind are -
1) Using level order traversal or BFS.
We can modify queue entries to contain level of nodes.So queue node will contain a pointer to a tree node and an integer level. When we deque a node we can check the level of dequeued node if it is same we can set right pointer to point to it.
Time complexity for this method would be O(n).
2) If we have complete binary tree we can extend Pre-Order traversal. In this method we shall set right pointer of parent before the children.
Time complexity for this method would be O(n).
3) In case of incomplete binary tree we can modify method (2) by traversing first root then right pointer and then left so we can make sure that all nodes at level i have the right pointer set, before the level i+1 nodes.
Time complexity for this method would be O(n^2).
private class Node
{
public readonly Node Left;
public readonly Node Right;
public Node Link { get; private set; }
public void Run()
{
LinkNext = null;
}
private Node LinkNext
{
get
{
return Link == null ? null : (Link.Left ?? Link.Right ?? Link.LinkNext);
}
set
{
Link = value;
if (Right != null)
Right.LinkNext = LinkNext;
if (Left != null)
Left.LinkNext = Right ?? LinkNext;
}
}
}
Keep a depth array while breadth-first search.
vector<forward_list<index_t>> level_link(MAX_NODES);
index_t fringe_depth = 0;
static index_t depth[MAX_NODES];
memset(depth,0,sizeof(depth));
depth[0] = 0;
Now when the depth-changes while de-queuing, you get all linked !
explored[0] = true;
static deque<index_t> fringe;
fringe.clear();
fringe.push_back(0); // start bfs from node 0
while(!fringe.empty()) {
index_t xindex = fringe.front();
fringe.pop_front();
if(fringe_depth < depth[xindex]) {
// play with prev-level-data
fringe_depth = depth[xindex];
}
Now we have fringe-depth, so we can level-link.
level_link[fringe_depth].push_front(xindex);
for(auto yindex : nodes[xindex].connected) {
if(explored[yindex])
continue;
explored[yindex] = true;
depth[yindex] = depth[xindex] + 1;
fringe.push_back(yindex);
}
}