Matrix tree data structure - algorithm

Recently I heard from professor in my university about such data structure as "matrix tree". I can understand what it is, but where is it useful?
I'll try to give short explanation for this structure:
We have a tree root - special node. Then we have left and right "children" (subtrees). Both are binary trees. And if there is no some numbers in the tree but we add their "descendants" then we add this missing numbers as parasitic (so subtrees is nearly full). In left tree all nodes are even numbers. Others are in right tree. And for N we can say that N = 2^L(2*Y - 1) where N - node value (even, in this case), L - level number and Y - position in level.
Example (even subtree):
8
/ \
4 12
/ \ /\
2 6 10 14
If we exclude, for example, 4, it become parasitic (special flag in node) and that's all.

Related

Given a list of keys, how do we find the almost complete binary search tree of that list?

I saw an answer here with the idea implemented in Python (not very familiar with Python) - I was looking for a more general algorithm.
EDIT:
For clarification:
Say we are given a list of integer keys: 23 44 88 12 74 32 7 39 10
That list was chosen arbitrarily. We are to create an almost complete (or complete) binary search tree from that list. There is supposed to be only one such tree...how do we find it?
A binary search tree is constructed so that all items on a node's left subtree are less than the node, and all nodes on the right subtree are greater than the node.
A complete (or almost complete) binary tree is one in which all levels except possibly the last are completely full, and the bottom level is filled to the left.
So, for example, this is an almost-complete binary search tree:
4
/ \
2 5
/ \
1 3
This is not:
3
/ \
2 4
/ \
1 5
Because the bottom level of the tree is not filled from the left.
If the number of items is one less than a power of two (i.e. 3, 7, 15, etc.), then building the tree is easy. Start by sorting the list. Then, take the middle element as the root. So if you have [1,2,3,4,5,6,7], and the root node is 4.
You do the same thing recursively for the right and left halves of the array.
If the number of items is not one less than a power of two, you have to adjust the starting point (the root node) so that the bottom row is left-filled. Note that you might have to apply that adjustment recursively, as well, whenever your subtree length is not one less than a power of two.
Since this is a homework assignment, I'll leave that for you to figure out.

Binary Search Trees / Picking a Root

I'm not quite sure how to pick a root for a binary search tree (I'm wanting to do without any code):
5, 9, 2, 1, 4, 8 ,3, 7, 6
How do I pick a root?
The steps are confusing me for this algorithm.
You can initialize an empty BST (binary search tree), then iterate the list and insert each item.
You don't need to pick a root, just build the tree. But maybe you want balanced the tree, you can insert as first element the middle value of the list, but the right answer is to use a balanced binary search tree (AVL tree).
Median number will be a better choice, because you want to have less depth.
Here is one example, the root is find the median the next one is also find the median
5
3 8
2 4 7 9
1 6
5 is get by (1+9)/2. 3 get from ceiling(1+4)/2 (you can also choose the floor of the median as the role of choosing median root)
BST with the same values can have many forms. For example, a tree containing 1,2 can be:
1 <- root
\
2 <-- right son
or
2 <- root
/
1 <-- left son
So you can have a tree where 1 is the root and it goes 1->2->3... and no left sons. You can have 5 as the root with 4 and 6 as left and right sons respectively, and you can have many other trees with the same values, but different ordering (and maybe different roots)
How do I pick a root?
In whichever way you want to. Any number of your data can be the root.
You would like to choose the median though, in this case, 5. With that choice, your tree should get as balanced as it gets, four nodes on the left of 5 and four nodes in the right subtree of 5.
Notice that any element could be the rood (even a random choice, or the first number in your example).
Um, then why should I worried finding the median and not always picking the first number (easiest choice)?
Because you want your Binary Search Tree (BST) to be as balanced as possible.
If you pick the min or the max number as a root, then your tree will reach its maximum depth (worst case scenario), and will emulate a single linked list, which will result in a worst case scenario for the search algorithm as well. However, as Michel stated, picking the minimum or maximum item for the root won't necessarily lead to a degenerate tree. For example, if you picked the minimum item for the root and but the right branch that contains the rest of the items is balanced, then the tree's height is only one level more than optimum. You only get a degenerate tree if you choose the nodes in ascending or descending order.
Keep in mind that in a BST, this rule must be respected:
Left children are less than the parent node and
all right children are greater than the parent node.
For more, read How binary search tree is created??

Number of levels in Binary Tree given the list of datas

Lets consider that, the following is the resultant of the Level Order Traversal of the Binary Tree.
Ex: 1,2,3,4,5,6,7,8
But, I got a question like, with the given list of data, how to compute the total number of levels in the binary tree.
I thought some thing like, Sqrt(8) and doing the Math.Round to it, will yield the result.
But I doubt that, I am wrong.
May I know, what is the perfect to do that.
Thanks in advance...
In the general case, a binary tree with n nodes will have at least 1 + floor(log_2(n)) levels. For example, you can fit 7 nodes on 3 levels, but 8 nodes will take at least 4 levels no matter what.
Also in the general case, the upper limit is n levels in the case of a degenerate binary tree (which looks like a linked list hanging down from the root). Consider your example, where the level-order traversal (also known as breadth-first traversal) is 1 2 3 4 5 6 7 8. The following cases are possible, along with everything in between:
1 1
/ \ \
/ \ 2
2 3 \
/ \ / \ 3
4 5 6 7 \
/ 4
8 \
5
(4 levels) \
6
\
7
\
8
(8 levels)
There are particular types of binary trees for which you can put stronger constraints on the upper limit. For complete or full binary trees, the number of levels is always 1 + floor(log_2(n)), because the shape of the tree depends only on n.
If you label the nodes with an index in breadth-first order, you can compute the level without any traversal in O(1) time. So if you are doing multiple queries, you can do an O(N) BFT and have each query answered in O(1) time.
The formula for the level is:
level = floor(log(index + 1))
Where the log is to the base 2
This link help you How can I calculate the level of a node in a perfect binary tree from its depth-first order index?
The height of a complete binary tree is up to O(logN).
Where N is the number of nodes you fill in the tree.
Note that Big O notation is required due to the fact that the actual height could vary by some addition or scaling factor.
https://www.cs.cmu.edu/~adamchik/15-121/lectures/Trees/trees.html
Level index value either can starts from 0 or 1.
If you are counting the level index starting from 0 (i.e., Root at Level 0) then
#no.of levels = floor(log_2(n))
If you are counting the level index starting from 1 (i.e., Root at Level 1) then
#no.of levels = 1 + floor(log_2(n))

How do you know where to perform rotations in an AVL tree?

So I'm self teaching AVL trees and I understand the basic idea behind it, but I just want to make sure my intuition of actually implementing it is valid:
I'll examine it with the left rotation-
So, the following situation is simple:
8
/ \
7 10
/
6
/
3
When we add the 3, the tree rebalances itself to:
8
/ \
6 10
/ \
3 7
But is the rotation based on the addition of the 3 or the imbalance of the subtree rooted at 7? Is it even based on the imbalance of the tree rooted at 8?
The following example is where things get a bit hairy, in my opinion:
9
/ \
7 10
/ \
6 8
/
3
So, in this case, the subtree at 7 is fine when the 3 is added, so that subtree doesn't need to rotate. However, the tree at 9 is imbalanced with the addition of 3, so we base the rotation at 9. We get:
7
/ \
6 9
/ / \
3 8 10
So in writing my code, which I will quite soon, would the following code, starting from small subtrees working up to bigger subtrees do the trick?
pseudocode:
function balanceTree(Node n){
if (n is not null){
balanceTree(n.rightchild);
balanceTree(n.leftchild);
}
if (abs(balanceFactor(n))>1){
rotateAsNeeded(n);// rotate based on balance factor
}
}
Thanks in advance!
The pseudocode that you've posted will correctly balance a tree. That said, it is too inefficient to be practical - notice that you're recursively exploring the entire tree trying to do rebalancing operations, which will make all insertions and deletions take O(n) time, eating away all the efficiency gains of having a balanced tree.
The idea behind AVL trees is that globally rebalancing the tree can be done by iteratively applying local rotations. In other words, when you do an insertion or deletion and need to do tree rotations, those rotations won't appear in random spots in the tree. They'll always appear along the access path you took when inserting or deleting the node.
For example, you were curious about inserting the value 3 into this tree:
9
/ \
7 10
/ \
6 8
Let's start off by writing out the difference in balance factors associated with each node (it's critical that AVL tree nodes store this information, since it's what makes it possible to do insertions and deletions efficiently):
9(+1)
/ \
7 (0) 10 (0)
/ \
6(0) 8(0)
So now let's see what happens when we insert 3. This places the 3 here:
9(+1?)
/ \
7 (0?) 10 (0)
/ \
6(0?) 8(0)
/
3(0)
Notice that I've marked all nodes on the access path with a ?, since we're no longer sure what their balance factors are. Since we inserted a new child for 6, this changes the balance factor for the 6 node to +1:
9(+1?)
/ \
7 (0?) 10 (0)
/ \
6(+1) 8(0)
/
3(0)
Similarly, the left subtree of 7 grew in height, so its balance factor should be incremented:
9(+1?)
/ \
7 (+1) 10 (0)
/ \
6(+1) 8(0)
/
3(0)
Finally, 9's left subtree grew by one, which gives this:
9(+2!)
/ \
7 (+1) 10 (0)
/ \
6(+1) 8(0)
/
3(0)
And here we find that 9 has a balance factor of +2, which means that we need to do a rotation. Consulting Wikipedia's great table of all AVL tree rotations, we can see that we're in the case where we have a balance factor of +2 where the left child has a balance factor of +1. This means that we do a right rotation and pull the 7 above the 9, as shown here:
7(0)
/ \
6(+1) 9(0)
/ / \
3(0) 8(0) 10 (0)
Et voilĂ ! The tree is now balanced.
Notice that when we did this fixup procedure, we didn't have to look over the entire tree. Instead, all we needed to do was look along the access path and check each node there. Typically, when implementing an AVL tree, your insertion procedure will do the following:
If the tree is null:
Insert the node with balance factor 0.
Return that the tree height has increased by 1.
Otherwise:
If the value to insert matches the current node, do nothing.
Otherwise, recursively insert the node into the proper subtree and get the amount that the tree height has changed by.
Update the balance factor of this node based on the amount that the subtree height changed.
If this mandates a series of rotations, perform them.
Return the resulting change in the height of this tree.
Since all these operations are local, the total work done is based purely on the length of the access path, which in this case is O(log n) because AVL trees are always balanced.
Hope this helps!
PS: Your initial example was this tree:
8
/ \
7 10
/
6
/
3
Note that this tree isn't actually a legal AVL tree, since the balance factor of the root node is +2. If you consistently maintain tree balance using the AVL algorithm, you will never encounter this case.

When two trees are equal?

If in-order traversal of two binrary trees (not binary search trees) are the same, does it guarantee that the two trees are the same?
if answer is no, then what about both in-order and pre-order traversal are the same?
Definitely not. The two trees
b
/ \
a d
/ \
c e
and
d
/ \
b e
/ \
a c
both have an inorder traversal of a b c d e. They are, in fact, rotations, an operation which preserves inorder traversal.
NO, and its seen with this simple example
3 2
2 1 3
1 0
0
Both have same inorder traversals [0,1,2,3]
But if inorder and preorder traversals are same then the trees are equal.
I'm thinking "no."
It's possible for two trees to be balanced differently, but have the same "order" of node values. For instance, if, of the set
1,2,3,4,5,6,7
You build a tree:
4
2 6
1 3 5 7
in-order traversal will yield 1,2,3,4,5,6,7.
however, if you choose a different root node (if the list is not sorted correctly beforehand)
5
4 6
2 7
1 3
These two trees will give the same in-order traversal result, but are (clearly) not identical.
or even
7
6
5
4
3
2
1
et cetera.
This is also related to a problem with BSP (binary space partition) trees, typically used in game development collision detection and visibility determination.
The BSP stores triangles in a tree. Each node contains a triangle or facet. The left node contains all children that are "behind" the facet, while the right child contains everything that is in "front." Recurse as expected.
If you pick the left-most facet in the scene as your root, the right child will then own every other facet. If you make a bad decision for the right child, the same thing will happen. It's perfectly possible for one to build a BSP compiler that, through idiotic analysis, builds a "tree" that is actually a list (as in my last example above). The problem is to partition the data set so that each node divides the remaining list as equally as possible. This is one of the reasons that BSPs are typically generated at compile time, as building one for a very complex geometry can take hours to find the/an optimal solution.
Inorder and any one of pre-order or post-order, uniquely define a tree structure. Nothing less.
One thing you can do is use level order
5
4 6
2 7
1 3
lvel order- 5 4 6 2 N N 7 1 3 N N N N N N

Resources