Binary search tree -- ordering - sorting

If we have V values for a search tree where the values are V= {1,2,3,4,5,6,7} inserted from right to left
And we are to order it to get the largest and shortest height possible -- how would we do it? Would it require the best and worst (lg2 (n+1)) case??
And would the orderings be unique?
Thanks -- I kinda understand but am not sure on what steps i should take.

The largest height is easy; put them in order:
1
\
2
\
...
With the smallest height, sort them, take the middle as the root, and put the two sides one either branch. Rinse and repeat.
3
/ \
2 5
/ / \
1 4 6
\
7
So... n for the first one, and log_2(n) for the second (rounded up).

The tallest such trees are created by inserting the values from a sorted sequence
1 2 3 4 5 6 7
or
7 6 5 4 3 2 1
The shortest tree is made by ordering the values via a recursive algorithm that finds the median then processes the left and right subtrees recursively:
4 2 1 3 6 5 7
This produces a tree of logarithmic height:
4
/ \
2 6
/ \ / \
1 3 5 7
Here the median is 4, so that goes first.
4
Now you have a partition for the left (1, 2, 3) and right (5, 6, 7). To order the left, start with its median, 2. Now you have 1 and 3 for its subtrees. These are 1 element sets so that's your base case.
4 2 1 3
Now process your right subtree (5, 6, 7), starting with 6.
4 2 1 3 6 5 7

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

Modified algorithm for building a Heap

I am quite new to programming and I am trying to understand a certain problem regarding heap sort. In a book I'm reading, there is a modified algorithm for building a max heap, which is:
BuildHeap(A)
A.heap-size = 1
for i = 2 to A.length
Heap-Insert(A, A[i])
So from my understanding, this algorithm takes in an array and defines the size of the heap to be 1 and then iterates from 2 to the total length of the array and then inserts the value into the heap.
But how would this build a max heap? If I had an array of [4, 7, 2, 3, 9, 1], then wouldn't the algorithm start at value 2 and then simply add all the values from the A[2] to A.length to the heap without actually building a max heap?
I do not understand how the heap-size = 1 does anything in the algorithm other than restrict the total size of the heap. I am confused as to how you would build a max heap.
From what it states in the book, the normal max heap works by first inserting every array value into a heap, and then starting at the A/2 place, then working backwards and swapping values that are larger than the current value being assessed by calling Max-Heapify.
So how would this max heap work since there is no Max-Heapify(A, largest) call, but instead there is simply a heap-insert(A, A[i])?
First of all, this question is not about heap sort, which is just one of the applications for a heap. You are asking about the heap construction.
The pseudo code you presented is indeed an alternative (and less efficient) way of building a heap, and this would actually be the algorithm that many would come up with when they wouldn't have known about the standard algorithm of Floyd.
So taking a look at the code:
BuildHeap(A)
A.heap-size = 1
for i = 2 to A.length
Heap-Insert(A, A[i])
Most of the logic of this algorithm is berried inside the Heap-Insert function, which is not just a simple "append" to an array: it does much more than that. Wikipedia describes that hidden algorithm as follows:
Add the element to the bottom level of the heap at the leftmost open space.
Compare the added element with its parent; if they are in the correct order, stop.
If not, swap the element with its parent and return to the previous step.
You write in your question:
there is no Max-Heapify(A, largest)
Indeed, it would be too simple if you already knew what the largest value was before using the heap. You need to first insert a value (any value) in a heap, and let the heap do its magic (inside Heap-Insert) to make sure that the largest value ends up in the first (top) position in the array A, i.e. in A[1].
The first step of the quoted algorithm is thus important: Heap-Insert expects the new value to be inserted at the end.
Let's work through the example [4, 7, 2, 3, 9, 1], and let's put a pipe symbol to indicate the end of the heap. At the start, the heap size is 1, so we have:
4 | 7 2 3 9 1
Let's also represent a more visually appealing binary tree at the right side -- it just has a root element:
4 | 7 2 3 9 1 4
Then we call Heap-Insert(A, A[2]), which is Heap-Insert(A, 7). The implementation of Heap-Insert will increase the size of the heap, and put that value in the last slot, so we get:
4 7 | 2 3 9 1 4
/
7
Heap-Insert has not finished yet -- this was just the first step it performs. Now it "bubbles up" that 7 following steps 2 and 3 of that quoted algorithm, and so we get:
7 4 | 2 3 9 1 7
/
4
At the second iteration of the pseudo code loop, we call Heap-Insert(A, 2), so Heap-Insert performs its first step:
7 4 2 | 3 9 1 7
/ \
4 2
...and finds out that nothing needs to change when performing step 2 and 3.
We continue inserting 3:
7 4 2 3 | 9 1 7
/ \
4 2
/
3
...and again nothing needs to change as 3 is less than 4 (remember that A[2] is the parent of A[4].
We continue inserting 9:
7 4 2 3 9 | 1 7
/ \
4 2
/ \
3 9
And here 9 > 4, and also 9 > 7, so Heap-Insert will further modify A to this:
9 7 2 3 4 | 1 9
/ \
7 2
/ \
3 4
One more to go:
9 7 2 3 4 1 9
/ \
7 2
/ \ /
3 4 1
And Heap-Insert has nothing more to do as 1 < 2.

Binary tree in concentric circles

Recently I came across a question in an interview "Print a complete binary tree in concentric circles".
1
2 3
4 5 6 7
8 9 0 1 2 3 4 5
The output should be
1 2 4 8 9 0 1 2 3 4 5 7 3
5 6
Could anyone help me out on how we can solve this problem?
Here is how you can approach the problem. Arrange the tree by levels:
1
2, 3
4, 5, 6, 7
8, 9, 0, 1, 2, 3, 4, 5
So the data you have is k levels L1, L2, ..., Lk. Now answer this questions: After we execute one step, that is when one circle is traversed, how would the tree levels would look like after the traverse elements have been removed from the levels? How should I modify the levels and which elements should I print so that it would seems like I've traversed on circle?
In your example, after the first step the levels would be modified to just:
5, 6
So what was the operation that was executed?
After you've answered the questions just apply the same procedure couple of times until you've printed all elements.

Balanced Binary Search Tree for numbers

I wanted to draw a balanced binary search tree for numbers from 1 to 20.
_______10_______
/ \
___5___ 15
/ \ / \
3 8 13 18
/ \ / \ / \ / \
2 4 7 9 12 14 17 19
/ / / /
1 6 11 16
Is the above tree correct and balanced?
In answer to your original question as to whether or not you need to first calculate the height, no, you don't need to. You just have to understand that a balanced tree is one where the height difference between the tallest and shortest node is zero or one, and the simplest way to achieve this is to ensure that you always pick the midpoint of the possible list, when populating the top node in a sub-tree.
Your sample tree is balanced since all leaf nodes are either at the bottom or next-to-bottom level, hence the difference in heights between any two leaf nodes is at most one.
To create a balanced tree from the numbers 1 through 20 inclusive, you can just make the root entry 10 or 11 (the midpoint being 10.5 for those numbers), so that there's an equal quantity of numbers in either sub-tree.
Then just do that recursively for each sub-tree. On the lower side of 10, 5 is the midpoint:
10
/ \
5 11-thru-19 sub-tree
/ \
1-thru-4 6-thru-9
sub-tree sub-tree
Just expand on that and you'll end up with something like:
_______10_______
/ \
___5___ 15
/ \ / \
2 7 13 17
/ \ / \ / / \
1 3 6 8 11 16 18 <- depth of highest leaf node
\ \ \ \
4 9 12 19 <- depth of lowest leaf node
^
|
Difference is 1
The midpoint can be found at the number where the difference between quantities above and below that numbers is one or zero. For the whole list of numbers 1 through 20 inclusive, there are nine less than 10 and ten greater than 10 (or, if you chose 11 as the midpoint, the quantities are ten and nine).
The difference between your sample and mine is probably to do with the fact that I preferred to pick the midpoint by rounding down where there was a choice (meaning my right sub-trees tend to be "heavier"). Because your left sub-trees are heavier, you appear to have rounded up.
After choosing 10 as the initial midpoint, there's no leeway on the left sub-tree, you have to choose 5 since it has four above and below it. Any other midpoint would result in a difference of at least two between the two halves (for example, choosing 4 as the midpoint would have the two halves of size three and five). This can still give you a balanced sub-tree depending on the data but it's "safer" to choose the midpoint.

Permuting rows in an array to eliminate increasing subsequences

The following problem is taken from Problems on Algorithms (Problem 653):
You are given a n x 2 matrix of numbers. Find an O(n log n) algorithm that permutes the rows in the array such that that neither column of the array contains an increasing subsequence (that may not consist of contiguous array elements) longer than ⌈√n.⌉
I'm not sure how to solve this. I think that it might use some sort of divide-and-conquer recurrence, but I can't seem to find one.
Does anyone have any ideas how to solve this?
Heres's my solution.
1) Sort rows according to the first element from greatest to lowest.
1 6 5 1
3 3 -\ 3 3
2 4 -/ 2 4
5 1 1 6
2) Divide it into groups of ⌈√n⌉, and what is left(no more then ⌈√n⌉ groups)
5 1 5 1
3 3 -\ 3 3
2 4 -/
1 6 2 4
1 6
3) Sort rows in each group according to the second element from greatest to lowest
5 1 3 3
3 3 5 1
->
2 4 1 6
1 6 2 4
Proof of correctness:
Increasing subsequences in column 1 can happen only in single group(size is <= ⌈√n⌉),
No 2 elements of increasing subsequences in column 2 are in the same group(no more than ⌈√n⌉ groups)

Resources