What are some algorithms for incrementally building a balanced binary tree with no order constraints? - algorithm

I am interested in taking a list of elements and turning them into a balanced binary tree with each element on a leaf of the tree. Furthermore, I want to build the tree with an algorithm that only sees one element at a time, rather than the whole list at once. Finally, this tree has no ordering constraints --- that is, it is not a search tree, so the nodes can be in any order.
My question is: there are lots of algorithms for incrementally building up binary search trees, but what are some algoritms for building up balanced binary trees without any ordering constraint? They ought to be more efficient as they don't have to worry about preserving any order relations between the nodes.

You can do it in linear time. For each 2 elements, you need a parent. For each 2 of those, you need another and so on. Can't do it any better though.
First you make N nodes for each data point you have - then you just start working your way back up - connect each two leafs together with a node, then each 2 of those parent nodes together, etc, until you get to 1 node.
Or you can work your way down -- at any level N you get 2^N children.
nodes = [...data...]
root = data.first; <== returns first element without removing it from nodes
while data.size > 1
a=data.pop_front
b=data.pop_front
root = new node(a,b) <== create new node with a and b as children
data.push_back(root)
when you leave the while loop, root contains the top of your tree.

Related

How would you keep an ordinary binary tree (not BST) balanced?

I'm aware of ways to keep binary search trees balanced/self-balancing using rotations.
I am not sure if my case needs to be that complicated. I don't need to maintain any sorted order property like with self-balancing BSTs. I just have an ordinary binary tree that I may need to delete nodes or insert nodes. I need try to maintain balance in the tree. For simplicity, my binary tree is similar to a segment tree, and every time a node is deleted, all the nodes along the path from the root to this node will be affected (in my case, it's just some subtraction of the nodal values). Similarly, every time a node is inserted, all the nodes from the root to the inserted node's final location will be affected (an addition to nodal values this time).
What would be the most straightforward way to keep a tree such as this balanced? It doesn't need to be strictly as height balanced as AVL trees, but something like RB trees or maybe slightly less balanced is acceptable as well.
If a new node does not have to be inserted at a particular spot -- possibly determined by its own value and the values in the tree -- but you are completely free to choose its location, then you could maintain the shape of the tree as a complete tree:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible.
An array is a very efficient data structure for a complete tree, as you can store the nodes in their order in a breadth-first traversal. Because the tree is given to be complete, the array has no gaps. This structure is commonly used for heaps:
Heaps are usually implemented with an array, as follows:
Each element in the array represents a node of the heap, and
The parent / child relationship is defined implicitly by the elements' indices in the array.
Example of a complete binary max-heap with node keys being integers from 1 to 100 and how it would be stored in an array.
In the array, the first index contains the root element. The next two indices of the array contain the root's children. The next four indices contain the four children of the root's two child nodes, and so on. Therefore, given a node at index i, its children are at indices 2i + 1 and 2i + 2, and its parent is at index floor((i-1)/2). This simple indexing scheme makes it efficient to move "up" or "down" the tree.
Operations
In your case, you would define the insert/delete operations as follows:
Insert: append the node to the end of the array. Then perform the mutation needed to its ancestors (as you described in your question)
Delete: replace the node to be deleted with the node that currently sits at the very end of the array, and shorten the array by 1. Make the updates needed that follow from the change at these two locations -- so two paths from root-to-node are impacted.
When balancing non-BSTs, the big question to ask is
Can your tree efficiently support rotations?
Some types of binary trees, like k-d trees, have a specific layer-by-layer structure that makes rotations infeasible. Others, like range trees, have auxiliary metadata in each node that's expensive to update after a rotation. But if you can handle rotations, then you can use just about any of the balancing strategies out there. The simplest option might be to model your tree on a treap: put a randomly-chosen weight field into each node, and then, during insertions, rotate your newly-added leaf up until its weight is less than its parent. To delete, repeatedly rotate the node with its lighter child until it's a leaf, then delete it.
If you cannot support rotations, you'll need a rebalancing strategy that does not require them. Perhaps the easiest option there is to model your tree after a scapegoat tree, which works by lazily detecting a node that's too deep for the tree to be balanced, then rebuilding the smallest imbalanced subtree possible into a perfectly-balanced tree to get everything back into order. Deletions are handled by rebuilding the whole tree once the number of nodes drops by some constant factor.

How to make Full Binary Tree with 6 nodes?

I know well about Full Binary Tree and Complete Binary Tree. But unable to make Full binary tree with only 6 nodes.
The answer is No. You can't make a Full binary tree with just 6 nodes. As the definition in the Wikipedia says:
A full binary tree (sometimes referred to as a proper or plane
binary tree) is a tree in which every node has either 0 or 2
children. Another way of defining a full binary tree is a recursive
definition. A full binary tree is either:
A single vertex.
A tree whose root node has two subtrees, both of which are full binary trees.
Another interesting property I noticed is that, the number of nodes required to make a full binary tree will always be odd.
Another way to see that a full binary tree has an odd number of nodes:
Starting with the definition of a full binary tree (Wikipedia):
a tree in which every node has either 0 or 2 children.
This means that the total number of child nodes is even (0+2+2+0+...+2 is always even). There is only one node that is not a child of another, which is the root. So considering that node as well, the total becomes odd.
By consequence there is no full binary tree with 6 nodes.
Elaborating on #vivek_23's answer, this is, unfortunately, not possible. There's a beautiful theorem that says the following:
Theorem: Any full binary tree has 2L - 1 nodes, where L is the number of leaf nodes in the tree.
The intuition behind this theorem is actually pretty simple. Imagine you take a complete binary tree and delete all the internal nodes from it. You now have a forest of L single-node full binary trees, one for each leaf. Now, add the internal nodes back one at a time. Each time you do, you'll be taking two different trees in the forest and combining them into a single tree, which decreases the number of trees in the forest by one. This means that you have to have exactly L - 1 internal nodes, since if you had any fewer you wouldn't be able to join together all the trees in the forest, and if you had any more you'd run out of trees to combine.
The fact that there are 2L - 1 total nodes in a full binary tree means that the number of nodes in a full binary tree is always odd, so you can't create a full binary tree with 6 nodes. However, you can create a full binary tree with any number of odd nodes - can you figure out how to prove that?
Hope this helps!

Joining of binary trees

Suppose we have a set of binary trees with their inorder and preorder traversals given,and where no tree is a subtree of another tree in the given set. Now another binary tree Q is given.find whether it can be formed by joining the binary trees from the given set.(while joining each tree in the set should be considered atmost once) joining operation means:
Pick the root of any tree in the set and hook it to any vertex of another tree such that the resulting tree is also a binary tree.
Can we do this using LCA (least common ancestor)?or does it needs any special datastructure to solve?
I think a Binary tree structure should be enough. I don't think you NEED any other special data structure.
And I don't understand how you would use LCA for this. As far as my knowledge goes, LCA is used for knowing the lowest common Ancestor for two NODES in the same tree. It would not help in comparing two trees. (which is what I would do to check if Q can be formed)
My solution in words.
The tree Q that has to be checked if it can be made from the set of trees, So I would take a top-down approach. Basically comparing Q with the possible trees formed from the set.
Logic:
if Q.root does not match with any of the roots of the trees in the set (A,B,C....Z...), No solution possible.
if Q.root matches a Tree root (say A) check corresponding children and mark A as used/visited. (Which is what I understand from the question: a tree can be used only once)
We should continue with A in our solution only if all of Q's children match the corresponding children of A. (I would do Depth First traversal, Breadth First would work as well).
We can add append a new tree from the set (i.e. append a new root (tree B) only at leaf nodes of A as we have to maintain binary tree). Keep track of where the B was appended.
Repeat same check with corresponding children comparison as done for A. If no match, remove B and try to add C tree at the place where B was Added.
We continue to do this till we run out of nodes in Q. (unless we want IDENTICAL MATCH, in which case we would try other tree combinations other than the ones that we have, which match Q but have more nodes).
Apologies for the lengthy verbose answer. (I feel my pseudo code would be difficult to write and be riddled with comments to explain).
Hope this helps.
An alternate solution: Will be much less efficient (try only if there are relatively less number of trees) : forming all possible set of trees ( first in 2s then 3s ....N) and and Checking the formed trees if they are identical to Q.
the comparing part can be referred here:
http://www.geeksforgeeks.org/write-c-code-to-determine-if-two-trees-are-identical/

Find a loop in a binary tree

How to find a loop in a binary tree? I am looking for a solution other than marking the visited nodes as visited or doing a address hashing. Any ideas?
Suppose you have a binary tree but you don't trust it and you think it might be a graph, the general case will dictate to remember the visited nodes. It is, somewhat, the same algorithm to construct a minimum spanning tree from a graph and this means the space and time complexity will be an issue.
Another approach would be to consider the data you save in the tree. Consider you have numbers of hashes so you can compare.
A pseudocode would test for this conditions:
Every node would have to have a maximum of 2 children and 1 parent (max 3 connections). More then 3 connections => not a binary tree.
The parent must not be a child.
If a node has two children, then the left child has a smaller value than the parent and the right child has a bigger value. So considering this, if a leaf, or inner node has as a child some node on a higher level (like parent's parent) you can determine a loop based on the values. If a child is a right node then it's value must be bigger then it's parent but if that child forms a loop, it means he is from the left part or the right part of the parent.
3.a. So if it is from the left part then it's value is smaller than it's sibling. So => not a binary tree. The idea is somewhat the same for the other part.
Testing aside, in what form is the tree that you want to test? Remeber that every node has a pointer to it's parent. An this pointer points to a single parent. So depending of the format you tree is in, you can take advantage from this.
As mentioned already: A tree does not (by definition) contain cycles (loops).
To test if your directed graph contains cycles (references to nodes already added to the tree) you can iterate trough the tree and add each node to a visited-list (or the hash of it if you rather prefer) and check each new node if it is in the list.
Plenty of algorithms for cycle-detection in graphs are just a google-search away.

Split 2-3 tree into less-than and greater-than given value X

I need to write function, which receives some key x and split 2-3 tree into 2 2-3 trees. In first tree there are all nodes which are bigger than x, and in second which are less. I need to make it with complexity O(logn). thanks in advance for any idea.
edited
I thought about finding key x in the tree. And after split its two sub-trees(bigger or lesser if they exist) into 2 trees, and after begin to go up and every time to check sub-trees which I've not checked yet and to join to one of the trees. My problem is that all leaves must be at the same level.
If you move from the root to your key and split each node so one points at the nodes larger than the key and the other at the rest and then make the larger node be a part of your larger tree, say by having the leftmost node at one level higher point at it, (don't fix the tree yet, do it at the end) until you reach the key you will get your trees. Then you just need to fix both trees on the path you used (note that the same path exists on both trees).
Assuming you have covered 2-3-4 trees in the lecture already, here is a hint: see whether you can apply the same insertion algorithm for 2-3 trees also. In particular, make insertions always start in the leaf, and then restructure the tree appropriately. When done, determine the complexity of the algorithm you got.

Resources