How to distinguish between two BSTs - algorithm

Here are the combinations of different BSTs with same element, the arrangement looks different depending on the sequence of addition of nodes to the tree structure:
1 1 1 1 1
\ \ \ \ \
2 2 3 4 4
\ \ / \ / /
3 4 2 4 3 2
\ / / \
4 3 2 3
2 2 3 3 4 4 4
/ \ / \ / \ / \ / / /
1 3 1 4 2 4 1 4 3 2 3
\ / / \ / / \ /
4 3 1 2 2 1 3 1
/ \
1 2
4 4
/ /
1 1
\ \
2 3
\ /
3 2
Their in-order traversal will be same, so how do we distinguish them? Especially when there are more than one sequence of adding the nodes and they all generate the same structure, example 2,1,4,5,2,4,1,3,2,4,3,1.

You mentioned that all your examples have the same in-order traversal (1234), meaning inorder is not enough information to derive the tree structure. However, both post-order and pre-order sequences are sufficient for deriving the tree structure of a binary search tree.
For example, given the pre-order 2-1-3-4, the only binary search tree that satisfies this pre-order is your row 2 col 1 example. Compare that to pre-order 2-1-4-3 which would be your row 2 col 2 example.
For all of your examples, here are their pre-order notations
[1234] [1243] [1324] [1432] [1423]
[2134] [2143] [3214] [3124] [4321] [4213] [4312]
[4123] [4132]
As you can see, they are all distinct. You can repeat the same process for their post-order traversal, and you should get all distinct results.

Related

Binary Heap - inserting order

Does inserting order affects the structure of binary heap? I mean, is it possible to get a little different parent-children relations when inserting the same elements in different orders,
for example:
20 6 3 5 7 8 16 10 (inserting order #1) and 6 3 20 10 16 3 7 5 (inserting order #2)
or the final result should always be the same?
A heap can store a given collection of values in different ways. For instance, if the heap happens to be a perfect binary tree, then you can swap any subtree with its sibling subtree without violating the heap property.
For example, if the data collection has the values 1, 2 and 3, there are 2 possible heaps that can represent that data set:
1 1
/ \ / \
2 3 3 2
The first will be the result when 2 is inserted before 3, and the second heap will be the result when 2 is inserted after 3.
If we look at an input with four values (e.g. 1, 2, 3 and 4), we can represent that in four heaps:
1 1 1 1
/ \ / \ / \ / \
2 3 2 4 3 2 4 2
/ / / /
4 3 4 3
Again, the order of insertion will determine which of those four heaps will be the end result.
If you imagine the sequences 1 1 1 1 2 2 and 1 1 2 1 1 2, you should end up with different heaps.
1 versus 1
1 1 1 2
1 2 2 1 1 2

Binary tree optimize solution?

Got this problem in one of the coding contest . Do you have a better approach than mine . I have given the pseudocode below
Given a complete binary tree with nodes of values of either 1 or 0, the following rules always hold:
a node's value is 1 if and only if all its subtree nodes' values are 1
a leaf node can have value either 1 or 0
Implement the following 2 APIs:
set_bit(offset, length), set the bits at range from offset to offset+length-1 on the leaf nodes
clear_bit(offset, length), clear the bits at range from offset to offset+length-1 on the leaf nodes
i.e. The tree is like:
0
/ \
0 1
/ \ / \
0 1 1 1
/\ / \ / \ / \
0 1 1 1 1 1 1 1
Input will given in 2 D array
int arr[][] = [ [0],[0,1],[1,0,1,0],[1,1,1,0,1,1,1,1]]
we need to set the bit or clear bit on the leaf nodes. In the above example if I do
clear(3,5)
i.e. The tree would be like:
0
/ \
0 0
/ \ / \
0 0 0 0
/\ / \ / \ / \
0 1 1 0 0 0 0 0
Pseudocode : My approach
1] Go to the last row and inner loop starts at offset on the leaf node (last row + offset).
2] check for the element at the offset if it is 1
3] if sibling zero the ancestor is zero no further action else if it is one
4] note down the range of the ancestor to zero in our case
(ancestor is row-- and column/2) so in our case for row 2 (range is column 1 to 3)
5]next iteration row 2 and the inner loop will move from column 1 to 3
6] keep repeating
For set bit as well we can for a similar approach

Why is splay tree in textbook different than mine?

In Data Structures and Algorithm Analysis in C++ (4th Edition) by Mark Allen Weiss, on page 162 at figure 4.50, the book describes how splaying the left most child of tree with only left children would ultimately look like.
Where I am confused is how the book gets from step 2 to step 3. Here are the steps highlighted on page 162 at figure 4.50:
Whereas my thirds step looks like this:
7
/
6
/
1
\
3
/ \
2 4
\
5
And my fourth and final step like this:
1
\
4
/ \
3 6
/ / \
2 5 7
I am confused as to how the book is balancing the tree. For me, when 1 surpassed 4 the bottom of the tree looked like this:
...
/
1
\
2
\
3
\
4
My logic was that the root where the balance would occur would be 2. Then you would do a left rotation and the bottom of the tree would look like this:
...
/
1
\
3
/ \
2 4
Am I doing something wrong or am I just doing it in a different but equally valid to the book way? I am also confused because the book's final tree is imbalanced from the root of 6 whereas my root of 4 doesn't have an imbalance.
This is mostly the "Zig-zig" case till upwards, so each time you do a right rotation on the node's grandparent followed by a right rotation on the parent.
Take example:
5
/
4
/
3
/
2
/
1
If you want to splay 1, you rotate right around 3 then 2, resulting in:
5
/
4
/
1
\
2
\
3
Since it is Zig-Zig case again, we rotate around 5 then 4, resulting:
1
\
4
/ \
2 5
\
3
So you keep doing this until you have 1 as root. There are 3 cases, Zig-Zig, Zig and Zig-Zag. Here is a tool that visualizes the whole concept it will be helpful I believe.

Algorithm to Cut tree and reshape?

1
/ \
2 7
/ \ / \
3 4 5 6
1
/ / \ \
3 4 5 6
I'm looking for an algorithm to reduce a tree by cutting out nodes at a specific level and save all the leaves. This example is very simple, so the function my have to be recursive - imagine cutting a tree at level 3 and eliminating nodes at levels 4,5,6,7 - but preserving the leaves by inserting them all at level 4.

Else than backtracking, how do I find longest path in a graph?

I have a graph shaped as a triangle.
8
/ \
1 4
/ \ / \
4 2 0
/ \ / \ / \
9 1 9 4
In the above graph the longest path is {8, 4, 2, 9}
My current algorithm calculates the max number of the adjacent nodes and add it to the list, then calculates the sum of that list. This works in the above graph but won't work in situations such as this scenario:
8
/ \
0 1
/ \ / \
4 0 4
/ \ / \ / \
9 99 3 4
My algorithm will mistakenly go through {8,1,4,4} where the correct longest path is {8,0,4,99}
The only solution I can think of is Backtracking. Where I have to go through all the paths and calculate the max path, which will be insanely slow in a huge graph. This about a 100k nodes graph.
My question is can I do better than this?
Start at the top.
For each node, pick the maximum of its parents (the nodes above connected to it) and add its own value.
Then, in the last row, pick the maximum.
This will just give you the value of the longest path, but you could easily get the actual path by simply starting at the value picked at the bottom and moving upwards, always picking the greater parent.
The running time would be linear in the number of nodes.
Example:
Original:
First example: Second example:
8 8
/ \ / \
1 4 0 1
/ \ / \ / \ / \
4 2 0 4 0 4
/ \ / \ / \ / \ / \ / \
9 1 9 4 9 99 3 4
Output:
First example: Second example:
8 8
/ \ / \
9 12 8 9
/ \ / \ / \ / \
13 14 12 12 9 13
/ \ / \ / \ / \ / \ / \
22 15 23 16 21 111 16 17
Then you'd pick 23 for the first and 111 for the second.
To get the path, we'd have 23-14-12-8, which corresponds to 9-2-4-8, for the first, and 111-12-8-8, which corresponds to 99-4-0-8, for the second.
I'm of course assuming we have a tree, as stated. For general graphs, this problem is quite a lot more difficult - NP-hard, to be exact.
You do not need backtracking here - you can use breadth-first search to propagate the max for the path that you have found so far to the corresponding node, level by level.
Start at the root, and set its max to its own value.
Go through nodes level-by-level
For each node check the max stored in its parent. There may be one or two of these parents. Pick the max of two max-es, add the value of the node itself, and store it in the current node
When the path through the graph is complete, the result would look like this:
Max graph:
8
/ \
8 9
/ \ / \
12 9 13
/ \ / \ / \
21 111 16 17
To recover a path, find the max value in the bottom layer. This is the final node of your path. You can reconstruct the path from the max graph and the original by starting at the max (111), subtracting the value (99), looking for the result (111-99=12) in the max graph, and continuing to that node until you reach the top:
111 - 99 = 12 -- Take 99
12 - 4 = 8 -- Take 4
8 - 0 = 8 -- Take 0
8 is the root -- Take 8
This gives you the max path in reverse. Note that this may not be the unique path (think of a graph filled with equal values to see how there may be multiple max paths). In this case, however, any path that you would recover will satisfy the max path requirement.

Resources