How to transform a binary tree into a heap in place? - algorithm

I have thought of the following:
Degenerate the tree into a linked list, and while degenerating, make
a dynamic array with the node object and its index in the linked
list
It would look like this
def treeDegenerator(self):
self.valList = []
currentNode = self
self.totalNodes = 0
self.nodes = 0
while currentNode:
while currentNode.getLeftChild():
currentNode.rotate_root_right()
self.valList.append(currentNode)
currentNode = currentNode.getRightChild()
self.totalNodes += 1
use the dynamic array, dereference all left childs and right childs and transform the degenerated tree into a complete tree by
using (index value)*2+1 to get the left child, add 1 more for the right.
def completeTree():
for node in self.valList:
node.left = None
node.right = None
for i in range(len(self.valList)):
self.valList[i].left = self.valList[(i)*2+1]
self.valList[i].right = a.valList[(i)*2+2]
Turn into heap by shifting values by comparison of the children for each node, level by level,starting at the bottom.
This was a problem for which students had to code without any references on a past exam. The issue with my method is that, its pretty much impossible for me to write all that code down in 30 minutes properly, and maybe could be possible if i memorize some code before hand. I was wondering if theres an easier, more feasible and elegant solution to turn any binary tree into a heap in place?

Conceptually you can break this task down into two steps:
Rebuild the tree into a perfectly-balanced BST with the bottom row filled in from left-to-right. You can do this using a modified version of the Day-Stout-Warren algorithm.
Run the heapify algorithm to convert your tree into a binary heap. This can be done really beautifully recursively; see below for details.
The Day-Stout-Warren algorithm works by rotating the tree into a singly-linked list, then from there applying a series of rotations to turn it into a perfectly-balanced tree. I don't remember off the top of my head whether the DSW algorithm specifically will place all leftover nodes in the bottom layer of the tree on the far left, as needed by a binary heap. If not, you can fix this up by doing a cleanup pass: if the tree doesn't have a number of nodes that's a perfect power of two, remove all nodes from the bottom layer of the tree, then iterate over the tree with an inorder traversal to place them on the far left.
As for the heapify algorithm: the way this is typically done is by visiting the layers of the tree from the bottom toward the top. For each node, you repeatedly swap that node down with its smaller child until it's smaller than all its children. With an explicit tree structure, this can be done with an elegant recursive strategy:
If the tree has no children, stop.
Otherwise, recursively heapify the left and right subtrees, then perform a "bubble-down" pass of repeatedly swapping the root's value with its smaller child's value until it's in the right place.
This overall requires O(n) time and uses only O(log n) auxiliary storage space, which is the space you'd need for the stack frames to implement the two algorithms.
<editorializing> That being said - this seems like a really bad coding question to put on a 30-minute timed exam. You can have a great command of algorithms and how to code them up and yet not remember all the steps involved in the two substeps here. Asking for this in half an hour is essentially testing "have you memorized implementations of various unrelated algorithms in great detail?," which doesn't seem like a good goal. </editorializing>

I would first collapse the tree into an ordered linked list on node.right.
I'm assuming we started with an ordered BST. If not, then sort the list. If you want a max-heap instead of a min-heap, then reverse the list at this point, too.
Count the nodes and calculate the depth of the largest complete tree contained in the solution
Do a recursive preorder traversal of the complete tree, filling in each node from the head of the list as you go.
Do a pre-order traversal of the tree you just built, filling in leaves from list nodes until you run out
Step 4 would be accomplished recursively like this:
root = list
fillChildren(root, list.right, levels-1)
fillChildren(root, list, levels) {
if (levels < 1) {
root.left = root.right = null
return list
}
root.left = list
list = fillChildren(root.left, list.right, levels-1)
root.right = list
list = fillChildren(root.right, list.right, levels-1)
return list
}
The trick to this, of course, is that mapping nodes in order to a pre-order traversal satisfies the heap property.
It's also pretty easy to combine steps 4 and 5 just by keeping track of each node's index in an imaginary array heap.
Just for fun, here's the whole job:
treeToHeap(root) {
if (root == null) {
return null
}
// Convert tree to list
while(root.left != null) {
root = rotateRight(root)
}
for (n = root; n.right != null; n=n.right) {
while (n.right.left != null) {
n.right = rotateRight(n.right)
}
}
// Count nodes
count = 0
for (n = root; n!=null; n=n.right) {
count+=1
}
// Build min-heap
list = root.right
// root's index in imaginary array heap is 0
if (count>1) {
root.left = list
list = fillNodes(root.left, list.right, 1, count)
} else {
root.left = null
}
if (count>2) {
root.right = list
list = fillNodes(root.right, list.right, 2, count)
} else {
root.right = null
}
return root
}
fillNodes(root, list, heapIndex, heapSize) {
heapIndex = heapIndex*2+1
if (heapIndex < heapSize) {
root.left = list
list = fillNodes(root.left, list.right, heapIndex, heapSize)
} else {
root.left = null
}
heapIndex += 1
if (heapIndex < heapSize) {
root.right = list
list = fillNodes(root.right, list.right, heapIndex, heapSize)
} else {
root.right = null
}
return list
}
So that took 15 minutes (and I didn't bother to write out rotateRight), and that's after figuring out how to do it. And I returned a couple times to fix bugs.
For a 30 minute exam, it's quite tough... BUT maybe the exam didn't really require the heap to be perfectly balanced. If it's just a question of implementing an in-place heapify, then it's quite reasonable.

Related

What are some algorithms for comparing the differences between two trees?

I'm looking to find the differences while comparing two tree structures.
The nodes will be strings. And I would like to capture at what level of the tree it is occurring.
For example finding the differences between these two trees:
What about a simple hash! List all values from root to leaf of the first tree and hash them, then list all values from root to leaf of the second tree and compare to the first one with O(1) time complexity. One can split the second tree (i.g based on the first layer) and use multi thread. In python, just put them on a set, and it's all done; or hash both of them and do a .difference()
The basic idea is to traverse the both tree level by level. Once you find,
the nodes are not the same
or
the nodes are not samely structured
means you found a difference here! now you can mark the level or the node, whatever you want.
PSEDOCODE:
function getDiff(Tree root, Tree root1){
Queue queue->push(root);
Queue queue1->push(root1);
level = 1;
while(queue->size() != 0 && queue1->size() != 0){
if(queue->size() != queue1->size()) {
PRINT: "THE TREE AREN'T IN SAME STRUCTURE :/";
return;
}
size = queue->size();
/* traversing both trees level-by-level */
while(size-- > 0){
Tree temp = queue->peek();
Tree temp1 = queue1->peek();
queue->pop();
queue1->pop();
if(!temp->node != temp1->node) {
PROCESS: level;
}
if(temp->left != null && temp1->left != null) {
queue->push(temp->left);
queue1->push(temp1->left);
}
if(temp->right!= null && temp1->right!= null) {
queue->push(temp->right);
queue1->push(temp1->right);
}
}
/* increase level */
level += 1;
}
}
NOTE: CHANGE THE PSEDOCODE INTO YOUR FAVOURITE LANGUAGE :)

The Great Tree list recursion program

I faced an interesting problem called as the Great Tree-List Problem. The Problem is as follows :
In the ordered binary tree, each node contains a single data element and "small" and "large" pointers to sub-trees .All the nodes in the "small" sub-tree are less than or equal to the data in the parent node. All the nodes in the "large" sub-tree are greater than the parent node. And a circular doubly linked list consist of previous and next pointers.
The problem is to take an ordered binary tree and rearrange the internal pointers to make a circular doubly linked list out of it. The "small" pointer should play the role of "previous" and the "large" pointer should play the role of "next". The list should be arranged so that the nodes are in increasing order. I have to write a recursive function & Return the head pointer to the new list.
The operation should be done in O(n) time.
I understand that recursion will go down the tree, but how to recursively change the small and large sub-trees into lists, also i have to append those lists together with the parent node.
How should i approach the problem?.. I just need a direction to solve the problem!.
The idea is to create a method that converts a tree node containing subtrees (children nodes) into a loop. And given a node that has converted children (e.g. after recursive calls came back), you create a new loop by pointing the large pointer (next) of the largest node to the smallest node, and the small pointer of the smallest node to the largest node.
May not be complete, but it will be close to this:
tree_node {
small
large
}
convert(node){
//base case 1, if leaf node
if node.small == null && node.large == null
return (self, self)
//recursively convert children
if node.small !=null
smallest, larger = convert(node.small)
else
smallest = larger = self
if node.large !=null
smaller, largest = convert(node.large)
else
smaller = largest = self
//wrap the ends of the chain
largest.large = smallest
smallest.small = largest
//wrap the mid part
smaller.small = larger
larger.large = small
//return pointers to the absolute smallest and largest of this subtree
return (smallest, largest)
}
//actually doing it
convert(tree.root)
The key to recursive programming is to imagine you already have the solution.
So, you already have a function recLink(Tree t) which receives a pointer to a tree, turns that tree into a doubly-linked circular list and returns a pointer to the list's head (leftmost) node:
recLink( n={Node: left, elt, right}) = // pattern match tree to a full node
rt := recLink( right); // already
lt := recLink( left); // have it
n.right := rt; n.left := lt.left; // middle node
lt.left.right := n; rt.left.right := lt; // right edges
lt.left := rt.left; rt.left := n;
return lt;
Finish up with the edge cases (empty child branches etc.). :)
assuming you have a simple tree of 3 nodes
B <--- A ---> C
walk down the left and right sides, get the pointers for each node, then have
B -> C
B <- C
Since your tree is binary, it will be composed of 3 node "subtrees" that can recursively use this strategy.

Delete multiple nodes from a binary search tree at O(n) time

Consider a binary search tree, where all keys are unique. Nodes haven't parent pointers.
We have up to n/2 marked nodes.
I can delete all of them at O(n2) time ( using postorder traversal and when encounter a marked node delete each at O(n)). But it is inappropriate.
I need an algorithm to delete all marked nodes at O(n) time.
Thanks.
EDIT After deletion I need to have nodes order unchanged.
EDIT-2 So it should look like I have deleted each marked node using the typical deletion (finding the rightmost node at the left subtree and exchanging it with the node to delete).
There are many ways, but here is one that should be easy to get right, and give you a perfectly balanced tree as a side effect. It requires linear extra space, however.
Create an array of size N minus the number of marked nodes (or N, if you don't know how many are marked and don't want to check it).
Place the elements in order in the array, by inorder traversal, skipping the marked elements. This takes linear time, and stack space proportional to the height of the tree.
Rebuild the tree top-down using the array. The mid element in the array becomes the new root, the mid element of the left subarray its new left child, and the mid element of the right subarray its new right subchild. Repeat recursively. This takes linear time and logarithmic stack space.
Update: forgot to say skipping the marked elements, but that was obvious, right? ;)
I have found how to do it!
We use an inorder traversal.
We check if node need to be deleted before recursive calls of the function.
When we find a node to delete we stand flag toFindMax and searching the rightmost node in the left subtree.
If we encounter another node to delete we push all our variables to the stack and pop them when the node was deleted.
When we find the maximum in the left subtree we save reference to it and to it's parent.
And then, when we recursively return to the initial node to delete, we delete it (exchange it with the maximum).
static class LinearDeletion {
public static Node MIN_VALUE = new Node(Integer.MIN_VALUE);;
boolean toFindMax = false;
Node parentOfMax = null;
Node max = MIN_VALUE;
Stack<Object> stack = new Stack<>();
public void perform(Node x, Node parent) {
if (x.isToDelete) {
stack.push(toFindMax);
stack.push(parentOfMax);
stack.push(max);
toFindMax = true;
parentOfMax = null;
max = MIN_VALUE;
if (x.left != null) {
perform(x.left, x);
}
if (x.left == null) { //deletion of the node
if (parent.left == x) {
parent.left = x.right;
} else {
parent.right = x.right;
}
} else {
if (x.right == null) {
if (parent.left == x) {
parent.left = x.left;
} else {
parent.right = x.left;
}
} else {
x.key = max.key;
x.isToDelete = max.isToDelete;
if (parentOfMax != x) {
parentOfMax.right = max.left;
} else {
x.left = max.left;
}
}
} // end of deletion
max = (Node) stack.pop();
parentOfMax = (Node) stack.pop();
toFindMax = (boolean) stack.pop();
if (toFindMax) { // check if the current node is the maximum
if (x.key > max.key) {
max = x;
parentOfMax = parent;
}
}
if (x.right != null) {
perform(x.right, x);
}
} else {
if (x.left != null) {
perform(x.left, x);
}
if (toFindMax) {
if (x.key > max.key) {
max = x;
parentOfMax = parent;
}
}
if (x.right != null) {
perform(x.right, x);
}
}
}
}
I don't see why a postorder traversal would be O(n2). The reason that deleting a single node is O(n) is that you need to traverse the tree to find the node, which is an O(n) operation. But once you find a node, it can be deleted in O(1) time.* Thus, you can delete all O(n) marked nodes in a single traversal in O(n) time.
* Unless you need to maintain a balanced tree. However, you don't list that as a requirement.
EDIT As #njlarsson correctly points out in his comment, a delete operation is not normally O(1) even after the node is found. However, since the left and right subtrees are being traversed before visiting a node to be deleted, the minimum (or maximum) elements of the subtrees can be obtained at no additional cost during the subtree traversals. This enables an O(1) deletion.

Removing duplicate subtrees from binary tree

I have to design an algorithm under the additional homework. This algorithm have to compress binary tree by transforming it into DAG by removing repetitive subtrees and redirecting all these connections to one left original subtree. For instance I've got a tree (I'm giving the nodes preorder):
1 2 1 3 2 1 3
The algorithm have to remove right connection (right subtree that means 2 1 3) of 1 (root) and redirect it to left connection (because these substrees are the same and left was first in preorder so we leave only the left)
The way I see it: I'm passing the tree preorder. For current node 'w', I start recursion that have to detect (if there exist) the original subtree equals to the subtree with root 'w'. I'm cutting the recursion if I find equal subtree (and I do what must be done) or when I get to 'w' in my finding the same subtrees recursion. Of course I predict some small improvements like comparing only subtrees with equal number of nodes.
If I'm not wrong it gives complexity O(n^2) where n is number of nodes of given binary tree. Is there any chance to do it faster (I think it is). Is the linear algorithm possible?
Pity that my algorithm finally has complexity O(n^3). Your answers with hashing probably will be very useful for me after some time, when I will know much more.. For now it's too difficult for me..
The last question. Is there any chance to do it in O(n^2) using elementary techniques (not hashing)?
This happens when constructing oBDDs. The Idea is: put the tree into a canonical form, and construct a hashtable with an entry for every node. Hash function is a function of the node + the hash functions for the left/right child nodes. Complexity is O(N), but only if one can rely on the hashvalues being unique. The final compare (e.g. for Resolving collisions) will still cost o(N*N) for the recursive subtree <--> subtree compare.
More on BDDs or the original Bryant paper
The hashfunction I currently use:
#define SHUFFLE(x,n) (((x) << (n))|((x) >>(32-(n))))
/* a node's hashvalue is based on its value
* and (recursively) on it's children's hashvalues.
*/
#define NODE_HASH2(l,r) ((SHUFFLE((l),5)^SHUFFLE((r),9)))
#define NODE_HASH3(v,l,r) ((0x54321u*(v) ^ NODE_HASH2((l),(r))))
Typical usage:
void node_sethash(NodeNum num)
{
if (NODE_IS_NULL(num)) return;
if (NODE_IS_TERMINAL(num)) switch (nodes[num].var) {
case 0: nodes[num].hash.hash= HASH_FALSE; break;
case 1: nodes[num].hash.hash= HASH_TRUE; break;
case 2: nodes[num].hash.hash= HASH_FALSE^HASH_TRUE; break;
}
else if (NODE_IS_NAMED(num)) {
NodeNum f,t;
f = nodes[num].negative;
t = nodes[num].positive;
nodes[num].hash.hash = NODE_HASH3 (nodes[num].var, nodes[f].hash.hash, nodes[t].hash.hash);
}
return ;
}
Searching the hash table:
NodeNum *hash_hnd(NodeNum num, int want_exact)
{
unsigned slot;
NodeNum *ptr, this;
if (NODE_IS_NULL(num)) return NULL;
slot = nodes[num].hash.hash % COUNTOF(hash_nodes);
for (ptr = &hash_nodes[slot]; !NODE_IS_NULL(this= *ptr); ptr = &nodes[this].hash.link) {
if (this == num) break;
if (want_exact) continue;
if (nodes[this].hash.hash != nodes[num].hash.hash) continue;
if (nodes[this].var != nodes[num].var) continue;
if (node_compare( nodes[this].negative , nodes[num].negative)) continue;
if (node_compare( nodes[this].positive , nodes[num].positive)) continue;
/* duplicate node := same var+same children */
break;
}
return ptr;
}
The recursive compare function:
int node_compare(NodeNum one, NodeNum two)
{
int rc;
if (one == two) return 0;
if (NODE_IS_NULL(one) && NODE_IS_NULL(two)) return 0;
if (NODE_IS_NULL(one) && !NODE_IS_NULL(two)) return -1;
if (!NODE_IS_NULL(one) && NODE_IS_NULL(two)) return 1;
if (NODE_IS_TERMINAL(one) && !NODE_IS_TERMINAL(two)) return -1;
if (!NODE_IS_TERMINAL(one) && NODE_IS_TERMINAL(two)) return 1;
if (VAR_RANK(nodes[one].var) < VAR_RANK(nodes[two].var) ) return -1;
if (VAR_RANK(nodes[one].var) > VAR_RANK(nodes[two].var) ) return 1;
rc = node_compare(nodes[one].negative,nodes[two].negative);
if (rc) return rc;
rc = node_compare(nodes[one].positive,nodes[two].positive);
if (rc) return rc;
return 0;
}
This is a problem commonly solved to do common sub-expression elimination in programming languages.
The approach is as follows (and is easily generalized to more than 2 children in a node):
Algorithm (Assumes mutable tree structure; You can easily build a new tree along the way):
MakeDAG(tree):
HASH = a new hash-table-based dictionary
foreach subtree NODE in the tree // traverse this however you like
if NODE is in HASH
replace NODE with HASH[NODE]
else
HASH[NODE] = N // insert the current node, N, in the dictionary
To compute the hash code for a node, you need to recursively compute the hash nodes until you reach the leaves of the tree.
Simply calculating these hash codes naively will bump up your runtime to O(n^2).
It is crucial that you store the results on your way down the tree to avoid repeated recursive calls and to improve the runtime to O(n).
I would go with a hashing approach.
A hash for a leaf is its value mod P_1. Hash for a node is (value+hash(left_son)*P_2+hash(right_son)*P_2^2) mod P_1, where P_1, P_2 are primes. If you count those hashes for at least 5 different big prime pairs(by big i mean something near 10^8-10^9, so you can do your math without overflowing), you can safely assume that nodes with same hashes are the same.
Then you can walk the tree, checking sons, first and do your transform. This will work in O(n) time.
NOTE that you can use other hash functions, like (value + hash(left_son)*P_2 + hash(right_son)*P_3) mod P_1, etc.

Create Balanced Binary Search Tree from Sorted linked list

What's the best way to create a balanced binary search tree from a sorted singly linked list?
How about creating nodes bottom-up?
This solution's time complexity is O(N). Detailed explanation in my blog post:
http://www.leetcode.com/2010/11/convert-sorted-list-to-balanced-binary.html
Two traversal of the linked list is all we need. First traversal to get the length of the list (which is then passed in as the parameter n into the function), then create nodes by the list's order.
BinaryTree* sortedListToBST(ListNode *& list, int start, int end) {
if (start > end) return NULL;
// same as (start+end)/2, avoids overflow
int mid = start + (end - start) / 2;
BinaryTree *leftChild = sortedListToBST(list, start, mid-1);
BinaryTree *parent = new BinaryTree(list->data);
parent->left = leftChild;
list = list->next;
parent->right = sortedListToBST(list, mid+1, end);
return parent;
}
BinaryTree* sortedListToBST(ListNode *head, int n) {
return sortedListToBST(head, 0, n-1);
}
You can't do better than linear time, since you have to at least read all the elements of the list, so you might as well copy the list into an array (linear time) and then construct the tree efficiently in the usual way, i.e. if you had the list [9,12,18,23,24,51,84], then you'd start by making 23 the root, with children 12 and 51, then 9 and 18 become children of 12, and 24 and 84 become children of 51. Overall, should be O(n) if you do it right.
The actual algorithm, for what it's worth, is "take the middle element of the list as the root, and recursively build BSTs for the sub-lists to the left and right of the middle element and attach them below the root".
Best isn't only about asynmptopic run time. The sorted linked list has all the information needed to create the binary tree directly, and I think this is probably what they are looking for
Note that the first and third entries become children of the second, then the fourth node has chidren of the second and sixth (which has children the fifth and seventh) and so on...
in psuedo code
read three elements, make a node from them, mark as level 1, push on stack
loop
read three elemeents and make a node of them
mark as level 1
push on stack
loop while top two enties on stack have same level (n)
make node of top two entries, mark as level n + 1, push on stack
while elements remain in list
(with a bit of adjustment for when there's less than three elements left or an unbalanced tree at any point)
EDIT:
At any point, there is a left node of height N on the stack. Next step is to read one element, then read and construct another node of height N on the stack. To construct a node of height N, make and push a node of height N -1 on the stack, then read an element, make another node of height N-1 on the stack -- which is a recursive call.
Actually, this means the algorithm (even as modified) won't produce a balanced tree. If there are 2N+1 nodes, it will produce a tree with 2N-1 values on the left, and 1 on the right.
So I think #sgolodetz's answer is better, unless I can think of a way of rebalancing the tree as it's built.
Trick question!
The best way is to use the STL, and advantage yourself of the fact that the sorted associative container ADT, of which set is an implementation, demands insertion of sorted ranges have amortized linear time. Any passable set of core data structures for any language should offer a similar guarantee. For a real answer, see the quite clever solutions others have provided.
What's that? I should offer something useful?
Hum...
How about this?
The smallest possible meaningful tree in a balanced binary tree is 3 nodes.
A parent, and two children. The very first instance of such a tree is the first three elements. Child-parent-Child. Let's now imagine this as a single node. Okay, well, we no longer have a tree. But we know that the shape we want is Child-parent-Child.
Done for a moment with our imaginings, we want to keep a pointer to the parent in that initial triumvirate. But it's singly linked!
We'll want to have four pointers, which I'll call A, B, C, and D. So, we move A to 1, set B equal to A and advance it one. Set C equal to B, and advance it two. The node under B already points to its right-child-to-be. We build our initial tree. We leave B at the parent of Tree one. C is sitting at the node that will have our two minimal trees as children. Set A equal to C, and advance it one. Set D equal to A, and advance it one. We can now build our next minimal tree. D points to the root of that tree, B points to the root of the other, and C points to the... the new root from which we will hang our two minimal trees.
How about some pictures?
[A][B][-][C]
With our image of a minimal tree as a node...
[B = Tree][C][A][D][-]
And then
[Tree A][C][Tree B]
Except we have a problem. The node two after D is our next root.
[B = Tree A][C][A][D][-][Roooooot?!]
It would be a lot easier on us if we could simply maintain a pointer to it instead of to it and C. Turns out, since we know it will point to C, we can go ahead and start constructing the node in the binary tree that will hold it, and as part of this we can enter C into it as a left-node. How can we do this elegantly?
Set the pointer of the Node under C to the node Under B.
It's cheating in every sense of the word, but by using this trick, we free up B.
Alternatively, you can be sane, and actually start building out the node structure. After all, you really can't reuse the nodes from the SLL, they're probably POD structs.
So now...
[TreeA]<-[C][A][D][-][B]
[TreeA]<-[C]->[TreeB][B]
And... Wait a sec. We can use this same trick to free up C, if we just let ourselves think of it as a single node instead of a tree. Because after all, it really is just a single node.
[TreeC]<-[B][A][D][-][C]
We can further generalize our tricks.
[TreeC]<-[B][TreeD]<-[C][-]<-[D][-][A]
[TreeC]<-[B][TreeD]<-[C]->[TreeE][A]
[TreeC]<-[B]->[TreeF][A]
[TreeG]<-[A][B][C][-][D]
[TreeG]<-[A][-]<-[C][-][D]
[TreeG]<-[A][TreeH]<-[D][B][C][-]
[TreeG]<-[A][TreeH]<-[D][-]<-[C][-][B]
[TreeG]<-[A][TreeJ]<-[B][-]<-[C][-][D]
[TreeG]<-[A][TreeJ]<-[B][TreeK]<-[D][-]<-[C][-]
[TreeG]<-[A][TreeJ]<-[B][TreeK]<-[D][-]<-[C][-]
We are missing a critical step!
[TreeG]<-[A]->([TreeJ]<-[B]->([TreeK]<-[D][-]<-[C][-]))
Becomes :
[TreeG]<-[A]->[TreeL->([TreeK]<-[D][-]<-[C][-])][B]
[TreeG]<-[A]->[TreeL->([TreeK]<-[D]->[TreeM])][B]
[TreeG]<-[A]->[TreeL->[TreeN]][B]
[TreeG]<-[A]->[TreeO][B]
[TreeP]<-[B]
Obviously, the algorithm can be cleaned up considerably, but I thought it would be interesting to demonstrate how one can optimize as you go by iteratively designing your algorithm. I think this kind of process is what a good employer should be looking for more than anything.
The trick, basically, is that each time we reach the next midpoint, which we know is a parent-to-be, we know that its left subtree is already finished. The other trick is that we are done with a node once it has two children and something pointing to it, even if all of the sub-trees aren't finished. Using this, we can get what I am pretty sure is a linear time solution, as each element is touched only 4 times at most. The problem is that this relies on being given a list that will form a truly balanced binary search tree. There are, in other words, some hidden constraints that may make this solution either much harder to apply, or impossible. For example, if you have an odd number of elements, or if there are a lot of non-unique values, this starts to produce a fairly silly tree.
Considerations:
Render the element unique.
Insert a dummy element at the end if the number of nodes is odd.
Sing longingly for a more naive implementation.
Use a deque to keep the roots of completed subtrees and the midpoints in, instead of mucking around with my second trick.
This is a python implementation:
def sll_to_bbst(sll, start, end):
"""Build a balanced binary search tree from sorted linked list.
This assumes that you have a class BinarySearchTree, with properties
'l_child' and 'r_child'.
Params:
sll: sorted linked list, any data structure with 'popleft()' method,
which removes and returns the leftmost element of the list. The
easiest thing to do is to use 'collections.deque' for the sorted
list.
start: int, start index, on initial call set to 0
end: int, on initial call should be set to len(sll)
Returns:
A balanced instance of BinarySearchTree
This is a python implementation of solution found here:
http://leetcode.com/2010/11/convert-sorted-list-to-balanced-binary.html
"""
if start >= end:
return None
middle = (start + end) // 2
l_child = sll_to_bbst(sll, start, middle)
root = BinarySearchTree(sll.popleft())
root.l_child = l_child
root.r_child = sll_to_bbst(sll, middle+1, end)
return root
Instead of the sorted linked list i was asked on a sorted array (doesn't matter though logically, but yes run-time varies) to create a BST of minimal height, following is the code i could get out:
typedef struct Node{
struct Node *left;
int info;
struct Node *right;
}Node_t;
Node_t* Bin(int low, int high) {
Node_t* node = NULL;
int mid = 0;
if(low <= high) {
mid = (low+high)/2;
node = CreateNode(a[mid]);
printf("DEBUG: creating node for %d\n", a[mid]);
if(node->left == NULL) {
node->left = Bin(low, mid-1);
}
if(node->right == NULL) {
node->right = Bin(mid+1, high);
}
return node;
}//if(low <=high)
else {
return NULL;
}
}//Bin(low,high)
Node_t* CreateNode(int info) {
Node_t* node = malloc(sizeof(Node_t));
memset(node, 0, sizeof(Node_t));
node->info = info;
node->left = NULL;
node->right = NULL;
return node;
}//CreateNode(info)
// call function for an array example: 6 7 8 9 10 11 12, it gets you desired
// result
Bin(0,6);
HTH Somebody..
This is the pseudo recursive algorithm that I will suggest.
createTree(treenode *root, linknode *start, linknode *end)
{
if(start == end or start = end->next)
{
return;
}
ptrsingle=start;
ptrdouble=start;
while(ptrdouble != end and ptrdouble->next !=end)
{
ptrsignle=ptrsingle->next;
ptrdouble=ptrdouble->next->next;
}
//ptrsignle will now be at the middle element.
treenode cur_node=Allocatememory;
cur_node->data = ptrsingle->data;
if(root = null)
{
root = cur_node;
}
else
{
if(cur_node->data (less than) root->data)
root->left=cur_node
else
root->right=cur_node
}
createTree(cur_node, start, ptrSingle);
createTree(cur_node, ptrSingle, End);
}
Root = null;
The inital call will be createtree(Root, list, null);
We are doing the recursive building of the tree, but without using the intermediate array.
To get to the middle element every time we are advancing two pointers, one by one element, other by two elements. By the time the second pointer is at the end, the first pointer will be at the middle.
The running time will be o(nlogn). The extra space will be o(logn). Not an efficient solution for a real situation where you can have R-B tree which guarantees nlogn insertion. But good enough for interview.
Similar to #Stuart Golodetz and #Jake Kurzer the important thing is that the list is already sorted.
In #Stuart's answer, the array he presented is the backing data structure for the BST. The find operation for example would just need to perform index array calculations to traverse the tree. Growing the array and removing elements would be the trickier part, so I'd prefer a vector or other constant time lookup data structure.
#Jake's answer also uses this fact but unfortunately requires you to traverse the list to find each time to do a get(index) operation. But requires no additional memory usage.
Unless it was specifically mentioned by the interviewer that they wanted an object structure representation of the tree, I would use #Stuart's answer.
In a question like this you'd be given extra points for discussing the tradeoffs and all the options that you have.
Hope the detailed explanation on this post helps:
http://preparefortechinterview.blogspot.com/2013/10/planting-trees_1.html
A slightly improved implementation from #1337c0d3r in my blog.
// create a balanced BST using #len elements starting from #head & move #head forward by #len
TreeNode *sortedListToBSTHelper(ListNode *&head, int len) {
if (0 == len) return NULL;
auto left = sortedListToBSTHelper(head, len / 2);
auto root = new TreeNode(head->val);
root->left = left;
head = head->next;
root->right = sortedListToBSTHelper(head, (len - 1) / 2);
return root;
}
TreeNode *sortedListToBST(ListNode *head) {
int n = length(head);
return sortedListToBSTHelper(head, n);
}
If you know how many nodes are in the linked list, you can do it like this:
// Gives path to subtree being built. If branch[N] is false, branch
// less from the node at depth N, if true branch greater.
bool branch[max depth];
// If rem[N] is true, then for the current subtree at depth N, it's
// greater subtree has one more node than it's less subtree.
bool rem[max depth];
// Depth of root node of current subtree.
unsigned depth = 0;
// Number of nodes in current subtree.
unsigned num_sub = Number of nodes in linked list;
// The algorithm relies on a stack of nodes whose less subtree has
// been built, but whose right subtree has not yet been built. The
// stack is implemented as linked list. The nodes are linked
// together by having the "greater" handle of a node set to the
// next node in the list. "less_parent" is the handle of the first
// node in the list.
Node *less_parent = nullptr;
// h is root of current subtree, child is one of its children.
Node *h, *child;
Node *p = head of the sorted linked list of nodes;
LOOP // loop unconditionally
LOOP WHILE (num_sub > 2)
// Subtract one for root of subtree.
num_sub = num_sub - 1;
rem[depth] = !!(num_sub & 1); // true if num_sub is an odd number
branch[depth] = false;
depth = depth + 1;
num_sub = num_sub / 2;
END LOOP
IF (num_sub == 2)
// Build a subtree with two nodes, slanting to greater.
// I arbitrarily chose to always have the extra node in the
// greater subtree when there is an odd number of nodes to
// split between the two subtrees.
h = p;
p = the node after p in the linked list;
child = p;
p = the node after p in the linked list;
make h and p into a two-element AVL tree;
ELSE // num_sub == 1
// Build a subtree with one node.
h = p;
p = the next node in the linked list;
make h into a leaf node;
END IF
LOOP WHILE (depth > 0)
depth = depth - 1;
IF (not branch[depth])
// We've completed a less subtree, exit while loop.
EXIT LOOP;
END IF
// We've completed a greater subtree, so attach it to
// its parent (that is less than it). We pop the parent
// off the stack of less parents.
child = h;
h = less_parent;
less_parent = h->greater_child;
h->greater_child = child;
num_sub = 2 * (num_sub - rem[depth]) + rem[depth] + 1;
IF (num_sub & (num_sub - 1))
// num_sub is not a power of 2
h->balance_factor = 0;
ELSE
// num_sub is a power of 2
h->balance_factor = 1;
END IF
END LOOP
IF (num_sub == number of node in original linked list)
// We've completed the full tree, exit outer unconditional loop
EXIT LOOP;
END IF
// The subtree we've completed is the less subtree of the
// next node in the sequence.
child = h;
h = p;
p = the next node in the linked list;
h->less_child = child;
// Put h onto the stack of less parents.
h->greater_child = less_parent;
less_parent = h;
// Proceed to creating greater than subtree of h.
branch[depth] = true;
num_sub = num_sub + rem[depth];
depth = depth + 1;
END LOOP
// h now points to the root of the completed AVL tree.
For an encoding of this in C++, see the build member function (currently at line 361) in https://github.com/wkaras/C-plus-plus-intrusive-container-templates/blob/master/avl_tree.h . It's actually more general, a template using any forward iterator rather than specifically a linked list.

Resources