How can we find center of a binary tree?
What shall be the most efficient algorithm. Though center of binary tree will be the mid point of the path corresponding to the diameter of tree. We can find the diameter of tree without actually knowing the path, is there any similar technique for finding center of binary tree?
If you know the diameter : D
and you know the max depth of the tree : M
then your center will be at the (M-(D/2)) th node(from the root) on the deepest path.(it might be M - (D-1)/2 depending on parity, you need to check yourself)
If you have more than on 1 paths from root to leaf with M nodes then the center is the root. (only true when the longest path goes through the root)
EDIT:
To answer your remark.
if it doesn't go through the root. Let's take the D/2th node on the diameter it will still be on the longest side of the diameter path (wich is in all the cases the longest path from root to leaf). and therefore M-D/2 still represent this point from the root.
Taking M-D/2nth from the root is the same as talking D/2nth from the leaf of the longest path.
Am I clear enough ? You might just want to draw it to check it .
You could calculate this in linear time O(N) by storing a list of the nodes that you have traversed if you are using a recursive method where you calculate the diameter by using the height of the tree (see this website here).
For instance, adapt the linear-time diameter function at the link I posted above so that you are also collecting a list of the nodes you have visited, and not just distance information. On each recursive call, you would select the list that went along with the longer traversed distance. The middle of the list that represented the diameter of the tree would be the "center" of the tree.
Your setup would look like the following:
typedef struct linked_list
{
tree_node* node;
linked_list* next;
} linked_list;
typedef struct list_pair
{
linked_list* tree_height;
linked_list* full_path;
} list_pair;
//some standard functions for working with the structure data-types
//they're not defined here for the sake of brevity
void back_insert_node(linked_list** tree, tree_node* add_node);
void front_insert_node(linked_list** tree, tree_node* add_node);
int list_length(linked_list* list);
void destroy_list(linked_list* list);
linked_list* copy_list(linked_list* list);
linked_list* append_list(linked_list* first, linked_list* second);
//main function for finding the diameter of the tree
list_pair diameter_path(tree_node* tree)
{
if (tree == NULL)
{
list_pair return_list_pair = {NULL, NULL};
return return_list_pair;
}
list_pair rhs = diameter_path(tree->right);
list_pair lhs = diameter_path(tree->left);
linked_list* highest_tree =
list_length(rhs.tree_height) > list_length(lhs.tree_height) ?
rhs.tree_height : lhs.tree_height;
linked_list* longest_path =
list_length(rhs.full_path) > list_length(lhs.full_path) ?
rhs.full_path : lhs.full_path;
//insert the current node onto the sub-branch with the highest height
//we need to make sure that the full-path, when appending the
//rhs and lhs trees, will read from left-to-right
if (highest_tree == rhs.tree_height)
front_insert_node(highest_tree, tree);
else
back_insert_node(highest_tree, tree);
//make temporary copies of the subtrees lists and append them to
//create a full path that represents a potential diameter of the tree
linked_list* temp_rhs = copy_list(rhs.tree_height);
linked_list* temp_lhs = copy_list(lhs.tree_height);
linked_list* appended_list = append_list(temp_lhs, temp_rhs);
longest_path =
list_length(appended_list) > list_length(longest_path) ?
appended_list : longest_path;
list_pair return_list_pair;
return_list_pair.tree_height = copy_list(highest_tree);
return_list_pair.full_path = copy_list(longest_path);
destroy_list(rhs.tree_height);
destroy_list(rhs.full_path);
destroy_list(lhs.tree_height);
destroy_list(lhs.full_path);
return return_list_pair;
}
Now the function returns a series of pointers in the full_path structure member that can be used to cycle though and find the middle-node which will be the "center" of the tree.
P.S. I understand that utilizing copying functions is not the fastest approach, but I wanted to be clearer rather than make something that was faster but had too much pointer-twiddling.
Optimized implementation: The above implementation can be optimized by calculating the
height in the same recursion rather than calling a height() separately.
/*The second parameter is to store the height of tree.
Initially, we need to pass a pointer to a location with value
as 0. So, function should be used as follows:
int height = 0;
struct node *root = SomeFunctionToMakeTree();
int diameter = diameterOpt(root, &height); */
int diameterOpt(struct node *root, int* height)
{
/* lh --> Height of left subtree
rh --> Height of right subtree */
int lh = 0, rh = 0;
/* ldiameter --> diameter of left subtree
rdiameter --> Diameter of right subtree */
int ldiameter = 0, rdiameter = 0;
if(root == NULL)
{
*height = 0;
return 0; /* diameter is also 0 */
}
/* Get the heights of left and right subtrees in lh and rh
And store the returned values in ldiameter and ldiameter */
ldiameter = diameterOpt(root->left, &lh);
rdiameter = diameterOpt(root->right, &rh);
/* Height of current node is max of heights of left and
right subtrees plus 1*/
*height = max(lh, rh) + 1;
return max(lh + rh + 1, max(ldiameter, rdiameter));
}
Time Complexity: O(n)
Related
I have to analyze an m-ary tree in C - using namely BFS.
There are some requirements I don't succeed to implement for a while:
1. Find the diameter of the tree.
2. Given two vertices in the tree - find the shortest simple path between them.
As for 1 - I went through the topics in Stack - and have seen some implementations (not in C unfortunately) which are not very clear to me... Some way of calculating the diameter by using BFS twice, starting from a random vertex... I'm not sure if the second BFS has to "remember" the visited array from the first BFS.
As for 2 - I really don't know how to approach to that, but I believe I can use somehow BFS here.
Moreover, I have to implement these two requirements in O(n^2) time complexity.
Besides that, I have to find the maximal and minimal heights of the tree.
As for the maximal height - I have implemented BFS (not sure it's absolutely correct) which to my understanding, deals with this maximal height.
As for the minimal height - I have no idea how to find it.
Here are my vertex struct and BFS implementations:
typedef struct Vertex {
size_t key;
size_t amountOfNeighbors; // The current amount of neighbors
size_t capacity; // The capacity of the neighbors (It's updating during run-time)
struct Vertex* parent;
struct Vertex** neighbors; // The possible parent and children of a vertex
} Vertex;
Vertex* bfs(Vertex* allVertices, size_t numOfVertices, Vertex* startVertex, size_t* pathDistance) {
if (startVertex -> neighbors == NULL) { // In case we have only one vertex in the graph
*pathDistance = 0;
return startVertex;
}
Queue* q = (Queue*)malloc((sizeof(size_t) * numOfVertices));
int* visited = (int*)malloc(sizeof(int) * numOfVertices);
for (size_t i = 0; i < numOfVertices; i++) {
visited[i] = 0; // Mark all the vertices as unvisited
}
size_t lastVertex = 0; // Actually indicates the furthermost vertex from startVertex
*pathDistance = 0; // The number of edges between lastVertex and startVertex
enqueue(q, startVertex->key);
visited[startVertex->key] = 1; // Mark as visited
while (!queueIsEmpty(q)) {
unsigned int currentVertex = dequeue(q); // The key of the current vertex
Vertex* s = &allVertices[currentVertex];
size_t currentAmountOfNeighbors = 0; // Detects the number of processed neighbors of the current vertex
for (Vertex **child = s->neighbors; currentAmountOfNeighbors < s->amountOfNeighbors; currentAmountOfNeighbors++) {
if (!visited[(*(child))->key]) {
visited[(*(child))->key] = 1;
enqueue(q, (*(child))->key);
child++; // TODO Validate it's a correct use of memory!
}
}
*pathDistance += 1; // Another layer passed
lastVertex = peekQueue(q);
}
Vertex* furtherMostVertexFromS = &allVertices[lastVertex];
free(q);
q = NULL;
return furtherMostVertexFromS;
}
My difficulties and wondering are in bold and any help with some of them will be appreciated.
Firstly, questions of this nature are more appropriate to the CS Stack Exchange, but I'll try to help regardless
For your first question(finding the diameter), note that the longest path of the tree must begin(or end) with the deepest node in the tree(which is a leaf). BFS helps you find the depths of all nodes, and thus help you find the deepest node. Can you figure from there how to find the end of said path? Hint: Think about the procedure for finding the deepest node of a graph.
There seems to be a misunderstanding on your part about how BFS works: Note that the point of keeping track of visited nodes, is to avoid crossing through back-edges - that is, to avoid cycles - which aren't possible in a tree.
But hypothetically, even if you do maintain such a 'visited' array (e,g if you want your algorithm to handle cyclic graphs), why would it be shared between different BFS invocations?
As for the second question: BFS finds the distances between nodes in the graph and the starting node(also called 'depth' when called from root). In particular, these are the shortest paths(on an unweighted graph)
The answer to the rest of your bolded questions are also related, the key takeway is that in an acylic, unweighted graph - BFS lets you find the shortest path/minimal distance from the starting node (consult an algorithms textbook for more details on that)
How to convert a tree to its mirror tree. For eg.
1 1
/ \ / \
2 3 to 3 2
/ \
4 4
Perform post order traversal.
void mirror(struct node* node)
{
if (node!=NULL)
{
struct node* temp;
/* do the subtrees */
mirror(node->left);
mirror(node->right);
/* swap the pointers in this node */
temp = node->left;
node->left = node->right;
node->right = temp;
}
}
Solution uses recursion to convert a tree to its mirror tree.
If root of both trees are null, then they are same. Return true.
If roots of both the trees are not null, check if the data in the two nodes is same and recursively check if left and right subtrees are identical.
If the roots of only one of the trees is null, then the trees are not identical, so return false.
Source: http://www.ideserve.co.in/learn/mirror-a-tree
Let's say I have this data structure for a minimum heap:
struct node{
int height;
struct node *parent;
struct node *left;
struct node *right;
};
What I want to do is add a new node into the next available position (keeping the min heap property does not matter at this point.) What I have so far is in the case of an empty tree (the root is instantiated earlier to NULL earlier in the code). I am having trouble figuring out the logic in the case that a root already exists. I need to add the elements in one by one. I understand how to do this using a heap as an array, but I need to do it using a heap as a binary tree.
void insert(int number)
{
struct node *nodeToInsert;
nodeToInsert=(struct node*)malloc(sizeof(struct node));
nodeToInsert->value = number;
if(root == NULL)
{
root = nodeToInsert;
root->left = NULL;
root->right = NULL;
}
}
If I understand correctly, you want to know how to descend a complete binary tree to insert the next node. All you need for this is to know how many nodes are already in the bottom level. The bits of this number tell you how to turn (left or right) as you move down the tree to the next available position. Happliy, you can get the number of nodes in the bottom level from the total number of items in the tree, which you normally want to track anyway.
// Let n be the current number of nodes in the tree.
// Subtract sizes of levels until we're at the last.
for (ls = 1, n_levels = 0; ; ls *= 2, n_levels++) {
if (n - ls < 0) break;
n -= ls;
}
// n now contains number of nodes in bottom level
// n_levels contains the number of complete levels above.
struct node *p = root;
for (bit = 1 << (n_levels - 1); bit != 1; bit >>= 1)
if (n & bit)
p = p->right;
else
p = p->left;
if (n & 1)
p->right = new_node();
else
p->left = new_node();
For example say n = 10. So we have a perfect tree of 7 nodes plus 3 on the lowest, incomplete level. The first loop subtracts 1, 2, then 4, so finishes with n = 3 = 011_2 and n_levels = 3. Consequently, the second loop creates the bit mask 1 << 2 = 4 = 100_2. The loop therefore moves down the tree with p = p->left for the high order bit 0 of n, then p = p->right for the 1. The final bit is a 1, therefore it puts the new node at p->right. This is the correct place (11) as you can see in this picture:
=== 1 ---
// \
2 3
/ \\ / \
4 5 6 7
/ \ / \\
8 9 10 11
Note the pseudocode above does not handle the n=0 case, but your code already does that.
Oof, it's not easy. You basically need to count the depth of each non-full node, and insert under the leftmost one with minimal depth.
It gets a lot easier if you know how many nodes are in the tree already. Once you have that, you can just traverse down to the n+1 position and put the node there.
There are many ways you could tackle this. One possible solution is using a queue.
Here is an example implementation in python:
def insert(self,node):
if self.root is None:
self.root = node
return node
else:
q = Queue()
x = self.root
while x is not None:
if x.left is None:
x.left = node
return node
elif x.right is None:
x.right = node
return node
else:
q.add(x.left)
q.add(x.right)
x = q.remove()
Here is what I have to find the kth smallest value in a binary search tree:
struct treeNode
{
int data;
struct treeNode *left, *right:
};
int rank(stuct treeNode* ptr, int k)
{
if(node == NULL)
return root;
while(ptr->left != NULL) {
ptr = ptr->left;
return rank(ptr->left)
}
}
This is obviously not correct. Without providing the solution, could someone guide me in the right direction as to how I could solve this? I am having trouble figuring out how I could find the kth smallest element in a BST.
A BST is a sorted binary tree, an in-order traversal (left subtree, current node, right subtree) will give sorted node values. To find the kth smallest node, just do an in-order traversal with a counter. The counter starts from 0, whenever a node is traversed, increase it by one, when it reaches k, the node is the kth smallest one.
If you have the sizes of each of the subtrees, this can be doable without having to read the data into an array (or otherwise traversing the tree) and counting up. If you don't keep the size information handy, you'll need a helper function to calculate the size.
The basic idea, figure out what is the index of the current node. If it is less than k, you need to search the left subtree. If it is greater than k, search the right offsetting the nodes counted from the left and current. Note that this is essentially the same as searching through a regular BST, except this time we are searching by index, not data. Some pseudocode:
if size of left subtree is equal to k:
// the current node is kth
return data of current node
else if size of left subtree is greater than k:
// the kth node is on the left
repeat on the left subtree
else if size of left subtree is less than k:
// the kth node is on the right
reduce k by the size of the left subtree + 1 // need to find the (k')th node on the right subtree
repeat on the right subtree
To illustrate, consider this tree with the marked indices (don't even worry about the data as it's not important in the search):
3
/ \
2 6
/ / \
0 4 7
\ \
1 5
Suppose we want to find the 2nd (k = 2).
Starting at 3, the size of the left subtree is 3.
It is greater than k so move to the left subtree.
The size of the left subtree is 2.
k is also 2 so the current node must be the 2nd.
Suppose we want to find the 4th (k = 4).
Starting at 3, the size of the left subtree is 3.
It is less than l so adjust the new k to be 0 (k' = 4 - (3 + 1)) and move to the right subtree.
Starting at 6, the size of the left subtree is 2.
It is greater than k' (0) so move to the left subtree.
The size of the left subtree is 0.
k' is also 0 so the current node must be the 4th.
You get the idea.
This should work:
int rank(struct treeNode* n,int k,int* chk)
{
if(!n) return -1;
int _chk = 0;
if(!chk) chk = &_chk;
int t = rank(n->left,k,chk);
if(t>=0) return t;
if(++*chk > k) return n->data;
int t = rank(n->right,k,chk);
if(t>=0) return t;
return -1;
}
call as rank(root,k,0)
How do I calculate the balance factor for a particular node, when I am recursively calling an insert function for adding a node to an AVL tree. I haven't started on the rotation logic. I simply want to calculate the balance factors.
In my current attempt, I am forced to store heights of left & right subtrees as I can't find the balance factor without them.
typedef struct _avlTree
{
int num;
int balFactor;
int height[2]; // left & right subtree heights
struct _avlTree *left,*right;
} *avlTree;
int avlAdd(avlTree a,avlTree aNew)
{
...
if(a->left == NULL) // left subtree insertion case
{
a->left = aNew;
return(1);
}
else
{
a->height[0] = avlAdd(a->left,aNew);
a->balFactor = a->height[0] - a->height[1];
return( (a->height[0]>a->height[1]) ? (a->height[0]+1) : (a->height[1]+1) );
}
...
}
The balance factor is the difference in heights between the right and left subtrees of a node.
When creating a new node, initialize the balance factor to zero since it is balanced (it has no subtrees).
If you are inserting a new node to the right, increase the balance factor by 1.
If you are inserting a new node to the left, decrease the balance factor by 1.
After rebalancing (rotating), if you increase the height of the subtree at this node, recursively propagate the height increase to the parent node.
Here is a very simple approach. If there was a recursive height() function, then balance factor can be computed simply as
node->balFactor = height( node->right ) - height( node->left );
This is not the best approach though, since the complexity of this approach is O( h ) where h is the height of the node in the AVL tree. For better approach, a bigger discussion is required :)
There are numerous resources on AVL tree in the web, a chosen few are:
http://en.wikipedia.org/wiki/AVL_tree
C implementation: http://www.stanford.edu/~blp/avl/libavl.html
Animation: http://www.cs.jhu.edu/~goodrich/dsa/trees/avltree.html
Animation: http://www.strille.net/works/media_technology_projects/avl-tree_2001/
BTW, The avlAdd() function looks wrong. I don't see where aNew->num is compared to a->num. Whether to go to left subtree or right subtree must depend on that. The given code seems to be adding to the left subtree unconditionally.