Suppose that there's a binary tree like the one below that needs to be stored in an array.
7
/ \
1 10
/\
9 11
And I found that the formula for storing the nodes in the array begins with storing the root node at position 0, and then for every node at index i, its children are placed at indices (i*2)+1 and (i*2)+2. And if the index of either child is greater than the array.length - 1, then that node does not have children.
So I begin by putting 7 at position 0, then its children 1 and 10 at position i2+1 and i2+2 which would be 1 and 2:
|7|1|10| | | |
0 1 2 3 4 5
Now, I'm stuck with node 1 which does not have any children. What should I put as its children?
Is it OK to put some default value that would represent the absence of a node, for example -1, like this:
|7|1|10|-1|-1|9|11|
0 1 2 3 4 5 6 7
This algorithm for storing a binary tree in an array is designed for trees such that every branch of the tree starting from the root node is of the same length: the array size is based on the greatest depth within the tree, and then it assigns an array position for every tree position of equal or lesser depth. If you have many different branch lengths, this may not be the correct algorithm for you. If your branch lengths are mostly the same depth but are sometimes empty near the end of the tree, placing a 'null' value such as -1 or Integer.MIN_VALUE may be an appropriate solution, as long as you know that you will not normally need to place any -1 values into the tree.
If you happen to know that you will only be missing elements from the greatest depth level of your tree (as in the example you provided), and the left/right order of the tree does not matter, you can instead simply reorder your tree such that the empty values are always in the bottommost, rightmost positions, which is also the set of positions at the end of your array, thus making your tree a complete binary tree. Then, you need only remember the number of elements in the tree, which is one greater than the index of the last non-null value. Diagrammed:
7
/ \
10 1
/\
9 11
-->
|7|10|1|9|11|0|0|
0 1 2 3 4 5 6
length = 5 or lastIndex = 4
I was thinking of using values which will break binary tree property at this point. In a general binary tree Left is always smaller and right is bigger than current node. If encounter higher on left or lower on right means end nodes.
Related
Binary Heaps can be represented using array which is a linear data structure, contrast to a tree, which is a non-linear data structure. Does that mean that binary heap represented using an array is no longer a tree?
You're confusing the model--the conceptual view of the heap--with the implementation.
A binary heap is a tree that is implemented in an array. That is, we allocate a fixed block of memory and reference it as though it's a tree. We can do that because the binary heap is a very special type of tree. In concept this is not much different than how we implement a two-dimensional array.
Consider a two-dimensional array declared as a[3,4]. Most languages allocate that as a single block of memory--a linear array--of size 12. But we address it as though it's a two-dimensional structure. The compiler converts our 2D addressing to one-dimensional array indices (assuming row-major ordering), like this:
1 2 3 4 5 6 7 8 9 10 11 12
| Row 1 | Row 2 | Row 3
In our two-dimensional view it looks like this:
1 2 3 4
5 6 7 8
9 10 11 12
So a[2,3] resolves to index 7.
What does that have to to with heaps?
Because a binary heap is a complete binary tree in which all levels except possibly the last are full, and the last is left-filled (i.e. all empty space is on the right side of the last level), we can overlay a tree structure on the array in much the same way we overlay the two-dimensional array.
We know that the first element of the array is the root of the heap. We know that the next two array elements are children of the root. The next four elements are those children's children, and so on. So in a binary heap with 7 nodes we have:
Index 1 - root node
Indices 2 and 3 - Children of root node
Indices 4,5,6,7 - Children of root's children
(4 and 5 are children of the node at index 2. 6 and 7 are children of the node at index 3).
That leads to a view of the array that looks like this:
1
2 3
4 5 6 7
8 9 10 11 12 13 14 15
Or, viewed as a tree:
1
2 3
4 5 6 7
8 9 10 11 12 13 14 15
The binary heap is still a tree. We're just using our knowledge of the special nature of a binary heap to implement it more efficiently than we can implement other types of trees.
Yes, we are using a linear data structure to implement a non-linear data structure. But that's true of all the data structures we use. Early processors (think 8086 and before) viewed memory as essentially one big array. Software would essentially split that up into different areas for operating system, program code, processor stack, process heap, etc. And within the process heap (again, one big linear data structure), programs would allocate and deallocate individual blocks to build non-linear data structures. Even today's systems, with memory virtualization and address translation, things work much the same way: your program allocates large blocks of linear memory and manages them, parceling out small pieces for non-linear data structures.
And then there's the linked list: a linear data structure that's implemented in terms of a non-linear data structure. Again, the model is a list--a linear data structure. The implementation is not linear at all.
And then consider implementing a linked list in an array. Each element of the array contains the node data and an index to the next item in the list. Traversed in order, the list nodes might be at array indices 1,7,5,4,6,2,3. Whether that's a linear or non-linear data structure depends on how you're looking at the problem. Or perhaps which part of the implementation you're looking at. Again, the model of the list is linear. And the implementation is in a linear data structure (the array). But the first node in the list is at the beginning of the array, the second node is at the end, and the nodes in the middle are in essentially random order. It's not linear at all!
You must learn to separate the model from the implementation.
The answer is no, we can represent how we want, but it will be a tree. The point is here, is there no limitations for all properties of binary heap when we represent it as an array.
I need an algorithm to find the shortest path between a defined source node and a defined target node.
The input file looks something like this:
0 6 1.4
7 9
0 1 3.2
0 2 2.4
0 3 1.7
1 2 -2.1
2 4 1.6
3 4 1.8
4 5 1.9
4 6 1.7
5 6 -3.1
the first line represents: the first number is the starting node, the second one is the target
node and the third one is the maximum weight i could possibly spend
the second line represents the number of node and arcs
the other lines represent the description of the arcs with their weights
// Example: from the node 0 to the node 1 the weight is 3.2.
At the end if there are no possibly paths that cost less than 1.4 (as the first input line gives) the program must return the value 0. If it's possible, it must return 1.
I tried to use the Bellman-Ford algorithm , however it finds shortest distance to all destinations.
Any suggestion is appreciated
You can apply the Bellman-Ford algorithm and check if the shortest path to the target node has inferior or equal weight to the one specified in the results.
Say results is a List object returned from the Bellman-Ford application on the graph speciying a starting node src, where results.get(tgt) returns the shortest-path weight between nodes src and tgt.
Say maxWeight is the maximum weight you want your shortest-path to weight.
You could do something like this:
if(!results.contain(tgt))
return 0;
if(results.get(tgt) <= maxWeight)
return 1;
I'd like to be able to programmatically examine an array and determine whether or not it could have been the result of a Weighted Quick Union algorithm. For those of us who need a refresher, a java implementation of Weighted Quick Union is here.
The basic idea of the weighted quick union algorithm is that is always connects the smaller tree to the larger one in order to minimize height, thus optimizing any traversal functions.
For example, an array that looks like 8 4 8 8 8 3 8 3 9 7 could not be the result of Weighted Quick Union because it contains a cycle, 9->7->3->8->9
An array like 8 0 9 3 6 6 0 4 8 0 cannot be a weighted quick union because the height of the trees together is 4, which is more than log(N) (where N is 10, the size of the initial array).
However, an array like 0 1 2 8 4 1 1 7 8 9 could have been the result of a weighted quick union.
I'd like to write a Java function like this:
public static boolean canBeResultOfWeightedQuickUnion(int[] id){
//returns whether or not the given array of ints could have been the result of a weighted quick union
}
How could I go about writing a method like this, ideally using the data structure available here?
"An array like *** cannot be a weighted quick union because the height of the trees together is 4, which is more than log(N) (where N is 10, the size of the initial array)."
In fact the maximum height in this case is ceil(log_2(N)), which is 4. To check this, just keep merging trees with the same height from the start
This property remains for all subtrees, and it is a very good answer for your question since you can just check this property.
The question that stills is how can you do this with most efficiency. I suppose that you just received an array and is checking it. So no other info is available. If this is the case, you can just create a auxiliary array for the height. Then you must go throught the id array, find the leafs and in a second step recursively go from the leafs to the roots updating the values of the heights and comparing to the number of elements in the subtree.
Here is one implementation of the remove method for BST. I quote from there:
Removing an element from a search tree, although tricky,
is conceptually straight-forward with one (common) exception: removing the element at a
node with two non-null children. In this case, the solution is either:
removeMax: remove the maximum (rightmost) node from the left subtree
and replace the root's value with the value of the removed node.
removeMin: remove the minimum (leftmost) node from the right subtree
and replace the root's value with the value of the removed node.
In either case the search tree's order structure is preserved.
If you look at this binary tree,
I want to remove 8 and if I choose to pick element from leftTree, using removeMax, I will choose 7 according to the above definition.
but I need to choose 13 from right Tree using removeMin and that breaks the BST.
am I not understanding this correctly?
The way remove works is getting the either the maximum from the leftTree or minimum from the rightTree and replace the node to be removed with its data.
Despite the visual appearance, the leftmost node of the right subtree above is ten, not 13. Reaching 13 requires moving right (from ten to 14), so 13 cannot be the leftmost node. If you choose ten, the BST property would not be broken.
The right subtree has three nodes - 10, 14, and 13.
10
\
\
14
/
13
Ten (at the top) has no left subtree, so it is the leftmost node of the right subtree.
what if 10's leftnode is not null but some node?
Then the tree would look like this:
10
/ \
/ \
9 14
/
13
so the leftmost node would be nine, not ten. Then the algorithm that you describe would pick nine for removal, which would again preserve the BST property.
The minimum value from the right subtree is 10, not 13.
Something that might help if you need a visual mnemonic: the minimum value of a right subtree is the "leftmost descendent of the right child."
ok i am given a bunch of leafs 10,9,7,8 and i need to create a sum tree from them as such
i need to find the sum of what is circled.
the problem is really a weight problem where i can choose two elements at a time to add them and their combined weight is the work done to combine the elements and i have to keep doing this till all the weights are combined while doing the minimum amount of work but i have turned it into this because i think this is the way to solve it.
is this the best way to solve this problem or is there a better way?
what would be the fastest way to create this tree and calculate the sum of those nodes?
The greedy solution:
Put all leaves in a priority queue (minimum weight comes out first).
While the queue contains more than one tree, pull out the two least-weight trees, join them and insert the joint tree into the queue.
When the queue contains only a single tree, that is your solution.
The greedy solution works:
Given any binary tree built from the leaves, each leaf contributes depth*weight to the total work/cost. (Where the depth of a leaf is the length of the path from the root to the leaf, e.g. in
18
/ \
3 15
/ \ / \
1 2 4 11
/ \
5 6
the leaves 1, 2, and 4 have depth 2, the leaves 5 and 6 have depth 3.)
So for any given shape of the tree, the smallest total cost is obtained when the lightest leaves are the deepest. Therefore a minimum cost tree is reached when the first step is joining the two lightest leaves to a new tree.
When some leaves have already been joined, the total cost of building the tree is (cost so far) + (cost of building cheapest tree considering the non-singleton trees as leaves).
So in the minimum cost tree, by the reasoning above, the two lightest "leaves" must be at the deepest level, hence can be joined to form a new subtree.
Use a stack machine. Push the leaves until the stack has 2 elements. Pop those elements, add (sub, mult, div, etc.) them, and push the result. Continuously do that until the input has no more elements. The final result is on top of the stack. This algorithm does arithmetic in the same order the sum tree would do it.
code stack
--------------------------
push 10 10$
push 9 9, 10$
pop a 10$
pop b $
push a+b 19$
push 7 7, 19$
push 8 8, 7, 19$
pop a 7, 19$
pop b 19$
push a+b 15, 19$
pop a 19$
pop b $
push a+b 34$
done 34$
Here is the implementation using Java
public static int sumTree(BinaryTreeNode<Integer> node) {
if (node == null) {
return 0;
}
int oldVal = node.getData();
node.setData(sumTree(node.getLeft()) + sumTree(node.getRight()));
return oldVal + node.getData();
}
Here is the test case
#Test
public void sumTreeTest() {
BinaryTreeNode<Integer> bt = BinaryTreeUtil.<Integer>fromInAndPostOrder(new Integer[]{8,-2,-4,10,7,6,5}, new Integer[]{8,-4,-2,7,5,6,10});
BinaryTreeUtil.sumTree(bt);
List<Integer> result = new ArrayList<Integer>();
BinaryTreeUtil.printInOrder(bt, result);
assertThat(result.toArray(new Integer[0]), equalTo(new Integer[]{0, 4, 0, 20, 0, 12, 0}));
//System.out.println(Arrays.toString(result.toArray()));
}