change the info part of each node in binary tree - data-structures

i have a binary tree.
2
/ \
3 4
/ \ \
5 1 8
\ /
6 9
I want to change the info part of each node such that the
nodeinfo = nodeinfo + nextInorderNodeInfo
so the actual inorder traversal
5, 6, 3, 1, 2, 4, 9, 8
will change to
5+6,6+3,3+1,1+2,2+4,4+9,9+8,8+0
11, 9, 4, 3, 6, 13, 17, 8
i need to write a function that will modify the binary tree info parts of each node.
i have done the following
calling
change(root,NULL);
function definition
void change(node* n, node *k)
{
if (n)
{
if (n->left) change(n->left,n);
if (n->right) change(n,n->right);
n->info + = k->info;
}
}
in this way i am not able to modify the nodes that are right hand leaf nodes.
can someone give the correct solution..???
thanks in advance

Write a reverse in-order traversal function (as in right, this, left rather than left, this, right) (which is technically still in-order, just with a different definition, but that's besides the point).
So this function will process the nodes in this order:
8, 9, 4, 2, 1, 3, 6, 5
This function must also remember the last processed node's value (before you added to it) and simply add this value to the current node.
And here's even some code which should work:
int last = 0;
void change(node* n)
{
if (n)
{
change(n->right);
int tempLast = n->info;
n->info += last;
last = tempLast;
change(n->left);
}
}

Related

Implementation of the graph algorithm DFS / BFS with some obstacles

I would like to ask you if you can give me an advice about a task that is based on a graph algorithm - either DFS or BFS.
There is a story behind the task. In the universe, there are a lot of planets. Some of these planets are infected by a dangerous virus that kills everyone.
The task is to find a path from one planet to a planet where is a medicine and so it is possible there to cure people from the virus.
To find the path is quite dangerous because of the virus. The crew may go to the planet where the virus is (they know in what planets the virus is), but they go there because they have no other option, since they have to find the medicine. On the planet that is infected the crew become infected and has some time to live (the time is a way from one planet to another planet). The result of this task should be a path from the start planet to a planet where there is the medicine. It should work for any map of known universe.
An example of a known universe with the planets. The starting planet is 0 and ending planet is 13. As you can see, the planets 1, 2, 4 are infected. In this specific example, there is one day to live after the crew become infected. So if the crew goes to the planet 1, they become infected and then on the next planet (4 or 6) dies. If they go to the planet 2, they become infected and they have just one day to live, so on the next planet dies... The result of this is the path 0 3 10 11 12 5 13.
An another example of a known universe with the planets. The starting planet is 0 and ending planet is 9. As you can see, the planets 4, 6, 7 are infected. In this specific example, there are two days to live after the crew become infected. So if the crew goes to the planet 4, they become infected and then after two days (one day = one way from one planet to another planet) dies. The result of this is either the path 0 1 2 3 5 7 6 9 or 0 1 2 3 5 7 8 9. As you can see, in some cases there might be more paths. The task is to find just one and it does not have to be the shortest one. Just one right path where the crew gets from start to end.
I have used the itterative DFS algorithm, but I do not know how to implement the part that if the crew would die on one path, the algorithm should find out another path. You can get it from the pictures of the graphs.
You can do a modified BFS to solve this problem. While doing the BFS, maintain the number of days infected as a part of the state. Then, while traversing, accept traversing to a previously visited node if we would be visiting with a better number of infected days (i.e. less).
This will also be the shortest-path, since BFS will produce shortest path in a non-weighted graph.
Here's a quick sketch in Python, applied to your second example:
from collections import deque
def bfs(graph, virus_nodes, start, target, survive_days):
survive_days = min(survive_days, len(graph))
visited = {start : 0}
queue = deque([(start, 0, (start,))]) # node, days infected, path
while queue:
node, days_infected, path = queue.popleft()
is_infected = days_infected > 0 or node in virus_nodes
nxt_days_infected = days_infected + 1 if is_infected else 0
if nxt_days_infected > survive_days:
continue
for nxt in graph[node]:
if nxt == target:
return path + (target,)
if nxt not in visited or visited[nxt] > nxt_days_infected:
queue.append((nxt, nxt_days_infected, path + (nxt,)))
visited[nxt] = nxt_days_infected
if __name__ == "__main__":
graph = {
0 : [1],
1 : [0, 2],
2 : [1, 3],
3 : [2, 4, 5],
4 : [3, 7],
5 : [3, 7],
6 : [7, 9],
7 : [4, 5, 6, 8],
8 : [7, 9],
9 : [6, 8],
}
virus_nodes = {4, 6, 7}
max_survive_days = 2
print(bfs(graph, virus_nodes, 0, 9, max_survive_days))
Output:
(0, 1, 2, 3, 5, 7, 6, 9)
The easiest way to solve this problem is with BFS, but you start from the end.
Lets say the time to live after infection is TTL days.
Run BFS from the destination, but you can only consider going to infected planets on paths less than TTL long. Once the BFS hits a path with TTL length, then you can only use clean planets from then on, all the way to the start.
This is especially easy if you do the BFS level-by-level. Then you only need to check if level < TTL.
If you don't care if it is shortest path you can use DFS with some adjustments to incorporate time to die feature. JSFiddle and code in javascript:
function findPath(path, infectedNodes, nodesBeforeDeath, initialNode, targetNode, adjacentTable) {
const lastNode = path.visitedNodes[path.visitedNodes.length - 1];
if (lastNode === targetNode) {
return path;
}
if (path.nodesLeftBeforeDeath !== null && path.nodesLeftBeforeDeath !== undefined && path.nodesLeftBeforeDeath == 0) {
return;
}
const adjacentNodes = adjacentTable[lastNode];
for (const node of adjacentNodes) {
if (path.visitedNodes.indexOf(node) > -1) {
continue;
}
const newPath = {
visitedNodes: [...path.visitedNodes, node]
};
if (path.nodesLeftBeforeDeath !== null && path.nodesLeftBeforeDeath !== undefined) {
newPath.nodesLeftBeforeDeath = path.nodesLeftBeforeDeath - 1;
}
else if (infectedNodes.indexOf(node) > - 1) {
newPath.nodesLeftBeforeDeath = nodesBeforeDeath;
}
const nodeResult = findPath(newPath, infectedNodes, nodesBeforeDeath, initialNode, targetNode, adjacentTable);
if (nodeResult) {
return nodeResult;
}
}
}
const firstExampleResult = findPath({
visitedNodes: [0]
},
[1, 2, 4],
1,
0,
13,
[[1,2,3,4],
[0,4,6],
[0, 7, 8],
[0, 9, 10],
[0, 1, 11, 12],
[6, 12, 13],
[1, 5, 7],
[2,6,14],
[2,9,14],
[3,8],
[3, 11],
[4,10,12],
[4,5,11],
[5],
[7,8]]
);
console.log(firstExampleResult.visitedNodes);
const secondExampleResult = findPath({
visitedNodes: [0]
},
[4, 6, 7],
2,
0,
9,
[
[1],
[0,2],
[1,3],
[2,4,5],
[3,7],
[3,7],
[7,9],
[4,5,6,8],
[7,9],
[6,8]
]
);
console.log(secondExampleResult.visitedNodes);
You can use use a shortest path algorithm like Dijkstra's algorithm for finding the shortest path between two nodes.
The edge weight is just the weight of the node you could be going to. In this case, all edges going to non-virus nodes would have a weight of 1. While edges going to a virus node would have a weight of number of nodes + 1. Visiting any virus planet should be easily more costly than visiting all other planets. This way the virus planets are only chosen if there is no other choice.
It also handles the case where you have to visit multiple virus planets, by preferring paths with the least amount of virus planets, not that it exactly matters in this case. Though if you want to list all equally valid solutions you could consider any additional virus planet as having a weight of 1 if the path already includes a virus planet. Then just display it as an another valid solution if it has the same weight as the best solution.
As for time to live, let's call it T, just check the current path. If the current node in the search is not the end node, and it has been T planets since the first virus planet crossed. Then reject the path as invalid.
An alternative handling for time to live would be to use an array weight, [path weight, virus age]. This means, given the same path weight, it will expand the path with the lowest virus age. Virus age is just # of days since exposed to virus.

previous most recent bigger element in array

I try to solve the following problem. Given an array of real numbers [7, 2, 4, 8, 1, 1, 6, 7, 4, 3, 1] for every element I need to find most recent previous bigger element in the array.
For example there is nothing bigger then first element (7) so it has NaN. For the second element (2) 7 is bigger. So in the end the answer looks like:
[NaN, 7, 7, NaN, 8, 8, 8, 8, 7, 4, 3, 1]. Of course I can just check all the previous elements for every element, but this is quadratic in terms of the number of elements of the array.
My another approach was to maintain the sorted list of previous elements and then select the first element bigger then current. This sounds like a log linear to me (am not sure). Is there any better way to approach this problem?
Here's one way to do it
create a stack which is initially empty
for each number N in the array
{
while the stack is not empty
{
if the top item on the stack T is greater than N
{
output T (leaving it on the stack)
break
}
else
{
pop T off of the stack
}
}
if the stack is empty
{
output NAN
}
push N onto the stack
}
Taking your sample array [7, 2, 4, 8, 1, 1, 6, 7, 4, 3, 1], here's how the algorithm would solve it.
stack N output
- 7 NAN
7 2 7
7 2 4 7
7 4 8 NAN
8 1 8
8 1 1 8
8 1 6 8
8 6 7 8
8 7 4 7
8 7 4 3 4
8 7 4 3 1 3
The theory is that the stack doesn't need to keep small numbers since they will never be part of the output. For example, in the sequence 7, 2, 4, the 2 is not needed, because any number less than 2 will also be less than 4. Hence the stack only needs to keep the 7 and the 4.
Complexity Analysis
The time complexity of the algorithm can be shown to be O(n) as follows:
there are exactly n pushes (each number in the input array is
pushed onto the stack once and only once)
there are at most n pops (once a number is popped from the stack,
it is discarded)
there are at most n failed comparisons (since the number is popped
and discarded after a failed comparison)
there are at most n successful comparisons (since the algorithm
moves to the next number in the input array after a successful
comparison)
there are exactly n output operations (since the algorithm
generates one output for each number in the input array)
Hence we conclude that the algorithm executes at most 5n operations to complete the task, which is a time complexity of O(n).
We can keep for each array element the index of the its most recent bigger element. When we process a new element x, we check the previous element y. If y is greater then we found what we want. If not, we check which is the index of the most recent bigger element of y. We continue until we find our needed element and its index. Using python:
a = [7, 2, 4, 8, 1, 1, 6, 7, 4, 3, 1]
idx, result = [], []
for i, v in enumerate(a, -1):
while i >= 0 and v >= a[i]:
i = idx[i]
idx.append(i)
result.append(a[i] if i >= 0 else None)
Result:
[None, 7, 7, None, 8, 8, 8, 8, 7, 4, 3]
The algorithm is linear. When an index j is unsuccessfully checked because we are looking for the most recent bigger element of index i > j then from now on i will point to a smaller index than j and j won't be checked again.
Why not just define a variable 'current_largest' and iterate through your array from left to right? At each element, current largest is largest previous, and if the current element is larger, assign current_largest to the current element. Then move to the next element.
EDIT:
I just re-read your question and I may have misunderstood it. Do you want to find ALL larger previous elements?
EDIT2:
It seems to me like the current largest method will work. You just need to record current_largest before you assign it a new value. For example, in python:
current_largest = 0
for current_element in elements:
print("Largest previous is "+current_largest)
if(current_element>current_largest):
current_largest = current_element
If you want an array of these, then just push the value to an array in place of the print statement.
As per my best understanding of your question. Below is a solution.
Working Example : JSFIDDLE
var item = document.getElementById("myButton");
item.addEventListener("click", myFunction);
function myFunction() {
var myItems = [7, 2, 4, 8, 1, 1, 6, 7, 4, 3, 1];
var previousItem;
var currentItem;
var currentLargest;
for (var i = 0; i < myItems.length; i++) {
currentItem = myItems[i];
if (i == 0) {
previousItem = myItems[0];
currentItem = myItems[0];
myItems[i] = NaN;
}
else {
if (currentItem < previousItem) {
myItems[i] = previousItem;
currentLargest = previousItem;
}
if (currentItem > currentLargest) {
currentLargest = currentItem;
myItems[i] = NaN;
}
else {
myItems[i] = currentLargest;
}
previousItem = currentItem;
}
}
var stringItems = myItems.join(",");
document.getElementById("arrayAnswer").innerHTML = stringItems;
}

How to find last egde connecting vertices from traversing two disjoint, equinumerous sets of vertices

Given two disjoint, equinumerous (of size n) sets (called 0 and 1) with values from 1 to 2n I have to find the last edge (pair of vertices) formed by a specific traversal.
Traversal algorithm:
start from value 1 (it does not matter in which set this value is)
connect it with first, free value from opposite set (first relative to actual value, so if current value is equal to 3, then I will check 4, 5, 6, 7, ..., 2n - 1, 2n, 1, 2)
repeat second step
Example:
n = 5
Set "0": { 1, 2, 4, 8, 9 }
Set "1": { 3, 5, 6, 7, 10 }
Traversal path:
1 -> 3 -> 4 -> 5 -> 8 -> 10 -> 2 -> 6 -> 9 -> 7
Answer -> 9 and 7
I was able to solve this problem with 2 * (1 + 2 ... + n) = 0(n^2) complexity. But I believe that there is a better solution.
You can do this in O(nlogn)
First sort both array and set current = 1
Now find which array contains 1, as you have to start with value 1
Now search the position of the current value in the opposite array(nearby) using binary search in O(logn)
Find the difference of the left and right nearby values and change current value to the value which results smallest difference
Of course set all the values visited which you already worked with. So that you dont work twice with the same value
So the overall complexity is O(nlogn)
4th step Elaboration:
Suppose your current value is in array a and you are searching in array b...
current value = 5
b = { 2 , 3 , 8 , 10}
^
if you do binary search in array b, the position you will get is 2. So now -
set current value = 8 and mark 8 as visited.
Now do step 2 and 3 in array a and so on ...
Update :
A sample C++ implementation:
#include <bits/stdc++.h>
using namespace std;
vector<int>right_a,right_b;
// Using union_find algorithm to find the next available value(which is not visited)
int find1(int x)
{
if(x==right_a[x])
return x;
right_a[x]=find1(right_a[x]);
}
int find2(int x)
{
if(x==right_b[x])
return x;
right_b[x]=find2(right_b[x]);
}
int main()
{
int i,j,k,l,m,n=5;
int a[]={1, 2, 4, 8, 9};
int b[]={3, 5, 6, 7, 10};
for(i=0;i<n;i++)
{
right_a.push_back(i);
right_b.push_back(i);
}
int cur=1,work_with;
if(a[0]==cur)
{
right_a[0]=1;
work_with=0;
}
else
{
right_b[0]=1;
work_with=1;
}
printf("%d",1);
int cnt=1;
while(cnt<2*n)
{
if(work_with==0)
{
// find first relative to actual value in array b
int ind=lower_bound(b,b+n,cur)-b;
if(ind==n)
ind=0;
ind=find2(ind);
int next=ind+1;
if(next==n)
next=0;
right_b[ind]=right_b[next]; // making current value visited
printf(" -> %d",b[ind]);
cur=b[ind];
work_with=1;
}
else
{
// find first relative to actual value in array a
int ind=lower_bound(a,a+n,cur)-a;
if(ind==n)
ind=0;
ind=find1(ind);
int next=ind+1;
if(next==n)
next=0;
right_a[ind]=right_a[next]; // making current value visited
printf(" -> %d",a[ind]);
cur=a[ind];
work_with=0;
}
cnt++;
}
printf("\n");
return 0;
}

Pre-order to post-order traversal

If the pre-order traversal of a binary search tree is 6, 2, 1, 4, 3, 7, 10, 9, 11, how to get the post-order traversal?
You are given the pre-order traversal of the tree, which is constructed by doing: output, traverse left, traverse right.
As the post-order traversal comes from a BST, you can deduce the in-order traversal (traverse left, output, traverse right) from the post-order traversal by sorting the numbers. In your example, the in-order traversal is 1, 2, 3, 4, 6, 7, 9, 10, 11.
From two traversals we can then construct the original tree. Let's use a simpler example for this:
Pre-order: 2, 1, 4, 3
In-order: 1, 2, 3, 4
The pre-order traversal gives us the root of the tree as 2. The in-order traversal tells us 1 falls into the left sub-tree and 3, 4 falls into the right sub-tree. The structure of the left sub-tree is trivial as it contains a single element. The right sub-tree's pre-order traversal is deduced by taking the order of the elements in this sub-tree from the original pre-order traversal: 4, 3. From this we know the root of the right sub-tree is 4 and from the in-order traversal (3, 4) we know that 3 falls into the left sub-tree. Our final tree looks like this:
2
/ \
1 4
/
3
With the tree structure, we can get the post-order traversal by walking the tree: traverse left, traverse right, output. For this example, the post-order traversal is 1, 3, 4, 2.
To generalise the algorithm:
The first element in the pre-order traversal is the root of the tree. Elements less than the root form the left sub-tree. Elements greater than the root form the right sub-tree.
Find the structure of the left and right sub-trees using step 1 with a pre-order traversal that consists of the elements we worked out to be in that sub-tree placed in the order they appear in the original pre-order traversal.
Traverse the resulting tree in post-order to get the post-order traversal associated with the given pre-order traversal.
Using the above algorithm, the post-order traversal associated with the pre-order traversal in the question is: 1, 3, 4, 2, 9, 11, 10, 7, 6. Getting there is left as an exercise.
Pre-order = outputting the values of a binary tree in the order of the current node, then the left subtree, then the right subtree.
Post-order = outputting the values of a binary tree in the order of the left subtree, then the right subtree, the the current node.
In a binary search tree, the values of all nodes in the left subtree are less than the value of the current node; and alike for the right subtree. Hence if you know the start of a pre-order dump of a binary search tree (i.e. its root node's value), you can easily decompose the whole dump into the root node value, the values of the left subtree's nodes, and the values of the right subtree's nodes.
To output the tree in post-order, recursion and output reordering is applied. This task is left upon the reader.
Based on Ondrej Tucny's answer. Valid for BST only
example:
20
/ \
10 30
/\ \
6 15 35
Preorder = 20 10 6 15 30 35
Post = 6 15 10 35 30 20
For a BST, In Preorder traversal; first element of array is 20. This is the root of our tree. All numbers in array which are lesser than 20 form its left subtree and greater numbers form right subtree.
//N = number of nodes in BST (size of traversal array)
int post[N] = {0};
int i =0;
void PretoPost(int pre[],int l,int r){
if(l==r){post[i++] = pre[l]; return;}
//pre[l] is root
//Divide array in lesser numbers and greater numbers and then call this function on them recursively
for(int j=l+1;j<=r;j++)
if(pre[j]>pre[l])
break;
PretoPost(a,l+1,j-1); // add left node
PretoPost(a,j,r); //add right node
//root should go in the end
post[i++] = pre[l];
return;
}
Please correct me if there is any mistake.
you are given the pre-order traversal results. then put the values to a suitable binary search tree and just follow the post-order traversal algorithm for the obtained BST.
This is the code of preorder to postorder traversal in python.
I am constructing a tree so you can find any type of traversal
def postorder(root):
if root==None:
return
postorder(root.left)
print(root.data,end=" ")
postorder(root.right)
def preordertoposorder(a,n):
root=Node(a[0])
top=Node(0)
temp=Node(0)
temp=None
stack=[]
stack.append(root)
for i in range(1,len(a)):
while len(stack)!=0 and a[i]>stack[-1].data:
temp=stack.pop()
if temp!=None:
temp.right=Node(a[i])
stack.append(temp.right)
else:
stack[-1].left=Node(a[i])
stack.append(stack[-1].left)
return root
class Node:
def __init__(self,data):
self.data=data
self.left=None
self.right=None
a=[40,30,35,80,100]
n=5
root=preordertoposorder(a,n)
postorder(root)
# print(root.data)
# print(root.left.data)
# print(root.right.data)
# print(root.left.right.data)
# print(root.right.right.data)
If you have been given preorder and you want to convert it into postorder. Then you should remember that in a BST in order always give numbers in ascending order.Thus you have both Inorder as well as the preorder to construct a tree.
preorder: 6, 2, 1, 4, 3, 7, 10, 9, 11
inorder: 1, 2, 3, 4, 6, 7, 9, 10, 11
And its postorder: 1 3 4 2 9 11 10 7 6
I know this is old but there is a better solution.
We don't have to reconstruct a BST to get the post-order from the pre-order.
Here is a simple python code that does it recursively:
import itertools
def postorder(preorder):
if not preorder:
return []
else:
root = preorder[0]
left = list(itertools.takewhile(lambda x: x < root, preorder[1:]))
right = preorder[len(left) + 1:]
return postorder(left) + postorder(right) + [root]
if __name__ == '__main__':
preorder = [20, 10, 6, 15, 30, 35]
print(postorder(preorder))
Output:
[6, 15, 10, 35, 30, 20]
Explanation:
We know that we are in pre-order. This means that the root is at the index 0 of the list of the values in the BST. And we know that the elements following the root are:
first: the elements less than the root, which belong to the left subtree of the root
second: the elements greater than the root, which belong to the right subtree of the root
We then just call recursively the function on both subtrees (which still are in pre-order) and then chain left + right + root (which is the post-order).
Here pre-order traversal of a binary search tree is given in array.
So the 1st element of pre-order array will root of BST.We will find the left part of BST and right part of BST.All the element in pre-order array is lesser than root will be left node and All the element in pre-order array is greater then root will be right node.
#include <bits/stdc++.h>
using namespace std;
int arr[1002];
int no_ans = 0;
int n = 1000;
int ans[1002] ;
int k = 0;
int find_ind(int l,int r,int x){
int index = -1;
for(int i = l;i<=r;i++){
if(x<arr[i]){
index = i;
break;
}
}
if(index == -1)return index;
for(int i =l+1;i<index;i++){
if(arr[i] > x){
no_ans = 1;
return index;
}
}
for(int i = index;i<=r;i++){
if(arr[i]<x){
no_ans = 1;
return index;
}
}
return index;
}
void postorder(int l ,int r){
if(l < 0 || r >= n || l >r ) return;
ans[k++] = arr[l];
if(l==r) return;
int index = find_ind(l+1,r,arr[l]);
if(no_ans){
return;
}
if(index!=-1){
postorder(index,r);
postorder(l+1,index-1);
}
else{
postorder(l+1,r);
}
}
int main(void){
int t;
scanf("%d",&t);
while(t--){
no_ans = 0;
int n ;
scanf("%d",&n);
for(int i = 0;i<n;i++){
cin>>arr[i];
}
postorder(0,n-1);
if(no_ans){
cout<<"NO"<<endl;
}
else{
for(int i =n-1;i>=0;i--){
cout<<ans[i]<<" ";
}
cout<<endl;
}
}
return 0;
}
As we Know preOrder follow parent, left, right series.
In order to construct tree we need to follow few basic steps-:
your question consist of series 6, 2,1,4,3,7,10,9,11
points-:
First number of series will be root(parent) i.e 6
2.Find the number which is greater than 6 so in this series 7 is first greater number in this series so right node will be starting from here and left to this number(7) is your left subtrees.
6
/ \
2 7
/ \ \
1 4 10
/ / \
3 9 11
3.same way follow the basic rule of BST i.e left,root,right
the series of post order will be L, R, N i.e. 1,3,4,2,9,11,10,7,6
Here is full code )
class Tree:
def __init__(self, data = None):
self.left = None
self.right = None
self.data = data
def add(self, data):
if self.data is None:
self.data = data
else:
if data < self.data:
if self.left is None:
self.left = Tree(data)
else:
self.left.add(data)
elif data > self.data:
if self.right is None:
self.right = Tree(data)
else:
self.right.add(data)
def inOrder(self):
if self.data:
if self.left is not None:
self.left.inOrder()
print(self.data)
if self.right is not None:
self.right.inOrder()
def postOrder(self):
if self.data:
if self.left is not None:
self.left.postOrder()
if self.right is not None:
self.right.postOrder()
print(self.data)
def preOrder(self):
if self.data:
print(self.data)
if self.left is not None:
self.left.preOrder()
if self.right is not None:
self.right.preOrder()
arr = [6, 2, 1, 4, 3, 7, 10, 9, 11]
root = Tree()
for i in range(len(arr)):
root.add(arr[i])
print(root.inOrder())
Since, it is a binary search tree, the inorder traversal will be always be the sorted elements. (left < root < right)
so, you can easily write its in-order traversal results first, which is : 1,2,3,4,6,7,9,10,11
given Pre-order : 6, 2, 1, 4, 3, 7, 10, 9, 11
In-order : left, root, right
Pre-order : root, left, right
Post-order : left, right, root
now, we got from pre-order, that root is 6.
now, using in-order and pre-order results:
Step 1:
6
/ \
/ \
/ \
/ \
{1,2,3,4} {7,9,10,11}
Step 2: next root is, using in-order traversal, 2:
6
/ \
/ \
/ \
/ \
2 {7,9,10,11}
/ \
/ \
/ \
1 {3,4}
Step 3: Similarly, next root is 4:
6
/ \
/ \
/ \
/ \
2 {7,9,10,11}
/ \
/ \
/ \
1 4
/
3
Step 4: next root is 3, but no other element is remaining to be fit in the child tree for "3". Considering next root as 7 now,
6
/ \
/ \
/ \
/ \
2 7
/ \ \
/ \ {9,10,11}
/ \
1 4
/
3
Step 5: Next root is 10 :
6
/ \
/ \
/ \
/ \
2 7
/ \ \
/ \ 10
/ \ / \
1 4 9 11
/
3
This is how, you can construct a tree, and finally find its post-order traversal, which is : 1, 3, 4, 2, 9, 11, 10, 7, 6

Quicksort with 3-way partition

What is QuickSort with a 3-way partition?
Picture an array:
3, 5, 2, 7, 6, 4, 2, 8, 8, 9, 0
A two partition Quick Sort would pick a value, say 4, and put every element greater than 4 on one side of the array and every element less than 4 on the other side. Like so:
3, 2, 0, 2, 4, | 8, 7, 8, 9, 6, 5
A three partition Quick Sort would pick two values to partition on and split the array up that way. Lets choose 4 and 7:
3, 2, 0, 2, | 4, 6, 5, 7, | 8, 8, 9
It is just a slight variation on the regular quick sort.
You continue partitioning each partition until the array is sorted.
The runtime is technically nlog3(n) which varies ever so slightly from regular quicksort's nlog2(n).
http://www.sorting-algorithms.com/static/QuicksortIsOptimal.pdf
See also:
http://www.sorting-algorithms.com/quick-sort-3-way
I thought the interview question version was also interesting. It asks, are there four partition versions of quicksort...
if you really grind out the math using Akra-Bazzi formula leaving the number of partitions as a parameter, and then optimize over that parameter, you'll find that e ( =2.718...) partitions gives the fastest performance. in practice, however, our language constructs, cpus, etc are all optimized for binary operations so the standard partitioning to two sets will be fastest.
I think the 3-way partition is by Djstrka.
Think about an array with elements { 3, 9, 4, 1, 2, 3, 15, 17, 25, 17 }.
Basically you set up 3 partitions: less than, equals to, and greater than a certain pivot. The equal-to partition doesn't need further sorting because all its elements are already equal.
For example, if we pick the first 3 as the pivot, then a 3-way partition using Dijkstra would arrange the original array and return two indices m1 and m2 such that all elements whose index is less than m1 will be lower than 3, all elements whose index is greater than or equal to m1 and less than or equal to m2 will be equal to 3, and all elements whose index is greater than m2 will be bigger than 3.
In this particular case, the resulting array could be { 1, 2, 3, 3, 9, 4, 15, 17, 25, 17 }, and the values m1 and m2 would be m1 = 2 and m2 = 3.
Notice that the resulting array could change depending on the strategy used to partition, but the numbers m1 and m2 would be the same.
I think it is related to the Dijkstra way of partitioning where the partition is of elemnts smaller, equal, and larger than the pivot. Only the smaller and larger partitions have to be sorted recursively. You can see an interactive visualization and play with it at the walnut. The colors I used there are red/white/blue because the method of partitioning is usually called "the dutch flag problem"
3 way quick sort basically partitions the array in 3 parts. First part is lesser than the pivot , Second part is equal to pivot and third part is greater than pivot.It is linear-time partition algorithm.
This partition is similar to Dutch National Flag problem.
//code to implement Dijkstra 3-way partitioning
package Sorting;
public class QuickSortUsing3WayPartitioning {
private int[]original;
private int length;
private int lt;
private int gt;
public QuickSortUsing3WayPartitioning(int len){
length = len;
//original = new int[length];
original = {0,7,8,1,8,9,3,8,8,8,0,7,8,1,8,9,3,8,8,8};
}
public void swap(int a, int b){ //here indexes are passed
int temp = original[a];
original[a] = original[b];
original[b] = temp;
}
public int random(int start,int end){
return (start + (int)(Math.random()*(end-start+1)));
}
public void partition(int pivot, int start, int end){
swap(pivot,start); // swapping pivot and starting element in that subarray
int pivot_value = original[start];
lt = start;
gt = end;
int i = start;
while(i <= gt) {
if(original[i] < pivot_value) {
swap(lt, i);
lt++;
i++;
}
if(original[i] > pivot_value) {
swap(gt, i);
gt--;
}
if(original[i] == pivot_value)
i++;
}
}
public void Sort(int start, int end){
if(start < end) {
int pivot = random(start,end); // choose the index for pivot randomly
partition(pivot, start, end); // about index the array is partitioned
Sort(start, lt-1);
Sort(gt+1, end);
}
}
public void Sort(){
Sort(0,length-1);
}
public void disp(){
for(int i=0; i<length;++i){
System.out.print(original[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
QuickSortUsing3WayPartitioning qs = new QuickSortUsing3WayPartitioning(20);
qs.disp();
qs.Sort();
qs.disp();
}
}

Resources