Trees
Trees
Trees
GivenaBinaryTreeandakeyk,finddistanceoftheclosestleaffromk.
Examples:
A
/\
BC
/\
EF
/\
GH
/\/
IJK
Closestleafto'H'is'K',sodistanceis1for'H'
Closestleafto'C'is'B',sodistanceis2for'C'
Closestleafto'E'iseither'I'or'J',sodistanceis2for'E'
Closestleafto'B'is'B'itself,sodistanceis0for'B'
Westronglyrecommendtominimizeyourbrowserandtrythisyourselffirst
Themainpointtonotehereisthataclosestkeycaneitherbeadescendentofgivenkeyorcanbereached
throughoneoftheancestors.
Theideaistotraversethegiventreeinpreorderandkeeptrackofancestorsinanarray.Whenwereach
thegivenkey,weevaluatedistanceoftheclosestleafinsubtreerootedwithgivenkey.Wealsotraverseall
ancestorsonebyoneandfinddistanceoftheclosestleafinthesubtreerootedwithancestor.Wecompare
alldistancesandreturnminimum.
// A C++ program to find the closesr leaf of a given key in Binary Tree
#include <iostream>
#include <climits>
using namespace std;
/* A binary tree Node has key, pocharer to left and right children */
struct Node
{
char key;
struct Node* left, *right;
};
// Returns distance of the cloest leaf to a given key 'k'. The array
// ancestors is used to keep track of ancestors of current node and
// 'index' is used to keep track of curremt index in 'ancestors[]'
int findClosestUtil(struct Node *root, char k, struct Node *ancestors[],
int index)
{
// Base case
if (root == NULL)
return INT_MAX;
// If key found
if (root->key == k)
{
// Find the cloest leaf under the subtree rooted with given key
int res = closestDown(root);
// If key node found, store current node and recur for left and
// right childrens
ancestors[index] = root;
return getMin(findClosestUtil(root->left, k, ancestors, index+1),
findClosestUtil(root->right, k, ancestors, index+1));
// The main function that returns distance of the closest key to 'k'. It
// mainly uses recursive function findClosestUtil() to find the closes
// distance.
int findClosest(struct Node *root, char k)
{
// Create an array to store ancestors
// Assumptiom: Maximum height of tree is 100
struct Node *ancestors[100];
= newNode('A');
root->left
= newNode('B');
root->right
= newNode('C');
root->right->left
= newNode('E');
root->right->right
= newNode('F');
root->right->left->left = newNode('G');
root->right->left->left->left = newNode('I');
root->right->left->left->right = newNode('J');
root->right->right->right
= newNode('H');
root->right->right->right->left = newNode('K');
char k = 'H';
cout << "Distace of the closest key from " << k << " is "
<< findClosest(root, k) << endl;
k = 'C';
cout << "Distace of the closest key from " << k << " is "
<< findClosest(root, k) << endl;
k = 'E';
cout << "Distace of the closest key from " << k << " is "
<< findClosest(root, k) << endl;
k = 'B';
cout << "Distace of the closest key from " << k << " is "
<< findClosest(root, k) << endl;
return 0;
}
Output:
DistaceoftheclosestkeyfromHis1
DistaceoftheclosestkeyfromCis2
DistaceoftheclosestkeyfromEis2
DistaceoftheclosestkeyfromBis0
Theabovecodecanbeoptimizedbystoringtheleft/rightinformationalsoinancestorarray.Theideais,if
givenkeyisinleftsubtreeofanancestors,thenthereisnopointtocallclosestDown().Also,theloopcan
thattraversesancestorsarraycanbeoptimizedtonottraverseancestorswhichareatmoredistancethan
currentresult.
=======================================================
DiagonalSumofaBinaryTree
Considerlinesofslope1passingbetweennodes(dottedlinesinbelowdiagram).Diagonalsuminabinary
treeissumofallnodesdatalyingbetweentheselines.GivenaBinaryTree,printalldiagonalsums.
Forthefollowinginputtree,outputshouldbe9,19,42.
9issumof1,3and5.
19issumof2,6,4and7.
42issumof9,10,11and12.
Westronglyrecommendtominimizeyourbrowserandtrythisyourselffirst
Algorithm:
Theideaistokeeptrackofverticaldistancefromtopdiagonalpassingthroughroot.Weincrementthe
verticaldistancewegodowntonextdiagonal.
1.Addrootwithverticaldistanceas0tothequeue.
2.Processthesumofallrightchildandrightofrightchildandsoon.
3.Addleftchildcurrentnodeintothequeueforlaterprocessing.Theverticaldistanceofleftchildisvertical
distanceofcurrentnodeplus1.
4.Keepdoing2nd,3rdand4thsteptillthequeueisempty.
FollowingisJavaimplementationofaboveidea.
// Java Program to find diagonal sum in a Binary Tree
import java.util.*;
import java.util.Map.Entry;
//Tree node
class TreeNode
{
int data; //node data
int vd; //vertical distance diagonally
TreeNode left, right; //left and right child's reference
// Tree class
class Tree
{
TreeNode root;//Tree root
// Tree constructor
public Tree(TreeNode root) { this.root = root; }
// Make an iterator
Iterator<Entry<Integer, Integer>> iterator = set.iterator();
//Driver class
public class DiagonalSum
{
public static void main(String[] args)
{
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(9);
root.left.right = new TreeNode(6);
root.right.left = new TreeNode(4);
root.right.right = new TreeNode(5);
root.right.left.left = new TreeNode(12);
root.right.left.right = new TreeNode(7);
root.left.right.left = new TreeNode(11);
root.left.left.right = new TreeNode(10);
Tree tree = new Tree(root);
tree.diagonalSum();
}
}
Output:
9,19,42
=======================================================
BottomViewofaBinaryTree
GivenaBinaryTree,weneedtoprintthebottomviewfromlefttoright.Anodexisthereinoutputifxisthe
bottommostnodeatitshorizontaldistance.Horizontaldistanceofleftchildofanodexisequaltohorizontal
distanceofxminus1,andthatofrightchildishorizontaldistanceofxplus1.
Examples:
20
/\
822
/\\
5325
/\
1014
Fortheabovetreetheoutputshouldbe5,10,3,14,25.
Iftherearemultiplebottommostnodesforahorizontaldistancefromroot,thenprintthelateroneinlevel
traversal.Forexample,inthebelowdiagram,3and4areboththebottommostnodesathorizontaldistance
0,weneedtoprint4.
20
/\
822
/\/\
53425
/\
1014
Fortheabovetreetheoutputshouldbe5,10,4,14,25.
Westronglyrecommendtominimizeyourbrowserandtrythisyourselffirst.
ThefollowingarestepstoprintBottomViewofBianryTree.
1.Weputtreenodesinaqueueforthelevelordertraversal.
2.Startwiththehorizontaldistance(hd)0oftherootnode,keeponaddingleftchildtoqueuealongwiththe
horizontaldistanceashd1andrightchildashd+1.
3.Also,useaTreeMapwhichstoreskeyvaluepairsortedonkey.
4.Everytime,weencounteranewhorizontaldistanceoranexistinghorizontaldistanceputthenodedata
forthehorizontaldistanceaskey.Forthefirsttimeitwilladdtothemap,nexttimeitwillreplacethevalue.
Thiswillmakesurethatthebottommostelementforthathorizontaldistanceispresentinthemapandifyou
seethetreefrombeneaththatyouwillseethatelement.
AJavabasedimplementationisbelow:
// Java Program to print Bottom View of Binary Tree
import java.util.*;
import java.util.Map.Entry;
//Tree class
class Tree
{
TreeNode root; //root node of tree
// Default constructor
public Tree() {}
if (temp.left != null)
{
temp.left.hd = hd-1;
queue.add(temp.left);
}
// If the dequeued node has a left child add it to the
// queue with a horizontal distance hd+1.
if (temp.right != null)
{
temp.right.hd = hd+1;
queue.add(temp.right);
}
}
// Make an iterator
Iterator<Entry<Integer, Integer>> iterator = set.iterator();
Bottomviewofthegivenbinarytree:
51041425
=======================================================
BinaryIndexedTreeorFenwicktree
LetusconsiderthefollowingproblemtounderstandBinaryIndexedTree.
Wehaveanarrayarr[0...n1].Weshouldbeableto
1Findthesumoffirstielements.
2Changevalueofaspecifiedelementofthearrayarr[i]=xwhere0<=i<=n1.
Asimplesolutionistorunaloopfrom0toi1andcalculatesumofelements.Toupdateavalue,simplydo
arr[i]=x.ThefirstoperationtakesO(n)timeandsecondoperationtakesO(1)time.Anothersimplesolution
istocreateanotherarrayandstoresumfromstarttoiattheithindexinthisarray.Sumofagivenrange
cannowbecalculatedinO(1)time,butupdateoperationtakesO(n)timenow.Thisworkswellifthenumber
ofqueryoperationsarelargeandveryfewupdates.
CanweperformboththeoperationsinO(logn)timeoncegiventhearray?
OneEfficientSolutionistouseSegmentTreethatdoesbothoperationsinO(Logn)time.
UsingBinaryIndexedTree,wecandobothtasksinO(Logn)time.TheadvantagesofBinaryIndexedTree
overSegmentare,requireslessspaceandveryeasytoimplement..
Representation
BinaryIndexedTreeisrepresentedasanarray.LetthearraybeBITree[].EachnodeofBinaryIndexed
Treestoressumofsomeelementsofgivenarray.SizeofBinaryIndexedTreeisequaltonwherenissize
ofinputarray.Inthebelowcode,wehaveusedsizeasn+1foreaseofimplementation.
Construction
WeconstructtheBinaryIndexedTreebyfirstinitializingallvaluesinBITree[]as0.Thenwecallupdate()
operationforallindexestostoreactualsums,updateisdiscussedbelow.
Operations
getSum(index):Returnssumofarr[0..index]
//Returnssumofarr[0..index]usingBITree[0..n].Itassumesthat
//BITree[]isconstructedforgivenarrayarr[0..n1]
1)Initializesumas0andindexasindex+1.
2)Dofollowingwhileindexisgreaterthan0.
...a)AddBITree[index]tosum
...b)GotoparentofBITree[index].Parentcanbeobtainedbyremoving
thelastsetbitfromindex,i.e.,index=index(index&(index))
3)Returnsum.
TheabovediagramdemonstratesworkingofgetSum().Followingaresomeimportantobservations.
Nodeatindex0isadummynode.
Anodeatindexyisparentofanodeatindexx,iffycanbeobtainedbyremovinglastsetbitfrombinary
representationofx.
Achildxofanodeystoressumofelementsfromofy(exclusivey)andofx(inclusivex).
update(index,val):UpdatesBITforoperationarr[index]+=val
//Notethatarr[]isnotchangedhere.Itchanges
//onlyBITreeforthealreadymadechangeinarr[].
1)Initializeindexasindex+1.
2)Dofollowingwhileindexissmallerthanorequalton.
...a)AddvaluetoBITree[index]
...b)GotoparentofBITree[index].Parentcanbeobtainedbyremoving
thelastsetbitfromindex,i.e.,index=index(index&(index))
TheupdateprocessneedstomakesurethatallBITreenodesthathavearr[i]aspartofthesectionthey
covermustbeupdated.WegetallsuchnodesofBITreebyrepeatedlyaddingthedecimalnumber
correspondingtothelastsetbit.
HowdoesBinaryIndexedTreework?
Theideaisbasedonthefactthatallpositiveintegerscanberepresentedassumofpowersof2.For
example19canberepresentedas16+2+1.EverynodeofBITreestoressumofnelementswherenisa
powerof2.Forexample,intheabovefirstdiagramforgetSum(),sumoffirst12elementscanbeobtained
bysumoflast4elements(from9to12)plussumof8elements(from1to8).Thenumberofsetbitsin
binaryrepresentationofanumbernisO(Logn).Therefore,wetraverseatmostO(Logn)nodesinboth
getSum()andupdate()operations.TimecomplexityofconstructionisO(nLogn)asitcallsupdate()foralln
elements.
Implementation:
FollowingisC++implementationofBinaryIndexedTree.
// C++ code to demonstrate operations of Binary Index Tree
#include <iostream>
using namespace std;
/*
return BITree;
}
{
int freq[] = {2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9};
int n = sizeof(freq)/sizeof(freq[0]);
int *BITree = constructBITree(freq, n);
cout << "Sum of elements in arr[0..5] is "
<< getSum(BITree, n, 5);
return 0;
}
Output:
Sumofelementsinarr[0..5]is12
Sumofelementsinarr[0..5]afterupdateis18
CanweextendtheBinaryIndexedTreeforrangeSuminLogntime?
Thisissimpletoanswer.TherangeSum(l,r)canbeobtainedasgetSum(r)getSum(l1).
=======================================================
HowtoImplementReverseDNS
LookUpCache?
ReverseDNSlookupisusinganinternetIPaddresstofindadomainname.Forexample,ifyoutype
74.125.200.106inbrowser,itautomaticallyredirectstogoogle.in.
HowtoimplementReverseDNSLookUpcache?Followingaretheoperationsneededfromcache.
1)AddaIPaddresstoURLMappingincache.
2)FindURLforagivenIPaddress.
OnesolutionistouseHashing.
Inthispost,aTriebasedsolutionisdiscussed.OneadvantageofTriebasedsolutionsis,worstcaseupper
boundisO(1)forTrie,forhashing,thebestpossibleaveragecasetimecomplexityisO(1).Also,withTrie
wecanimplementprefixsearch(findingallurlsforacommonprefixofIPaddresses).
ThegeneraldisadvantageofTrieislargeamountofmemoryrequirement,thisisnotamajorproblemhere
asthealphabetsizeisonly11here.Tencharactersareneededfordigitsfrom0to9andonefordot(.).
TheideaistostoreIPaddressesinTrienodesandinthelastnodewestorethecorrespondingdomain
name.FollowingisCstyleimplementationinC++.
// C based program to implement reverse DNS lookup
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
// Trie Node.
struct trieNode
{
bool isLeaf;
char *URL;
struct trieNode *child[CHARS];
};
newNode->URL = NULL;
for (int i=0; i<CHARS; i++)
newNode->child[i] = NULL;
return newNode;
}
// If we find the last node for a given ip address, print the URL.
if (pCrawl!=NULL && pCrawl->isLeaf)
return pCrawl->URL;
return NULL;
}
//Driver function.
int main()
{
/* Change third ipAddress for validation */
char ipAdd[][MAX] = {"107.108.11.123", "107.109.123.255",
"74.125.200.106"};
char URL[][50] = {"www.samsung.com", "www.samsung.net",
"www.google.in"};
int n = sizeof(ipAdd)/sizeof(ipAdd[0]);
struct trieNode *root = newTrieNode();
ReverseDNSlookupresolvedincache:
107.108.11.123>www.samsung.com
=======================================================
Givennappointments,findall
conflictingappointments
Givennappointments,findallconflictingappointments.
Examples:
Input:appointments[]={{1,5}{3,7},{2,6},{10,15},{5,6},{4,100}}
Output:Followingareconflictingintervals
[3,7]Conflictswith[1,5]
[2,6]Conflictswith[1,5]
[5,6]Conflictswith[3,7]
[4,100]Conflictswith[1,5]
Anappointmentisconflicting,ifitconflictswithanyofthepreviousappointmentsinarray.
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
ASimpleSolutionistoonebyoneprocessallappointmentsfromsecondappointmenttolast.Forevery
appointmenti,checkifitconflictswithi1,i2,0.ThetimecomplexityofthismethodisO(n2).
WecanuseIntervalTreetosolvethisprobleminO(nLogn)time.Followingisdetailedalgorithm.
1)CreateanIntervalTree,initiallywiththefirstappointment.
2)Dofollowingforallotherappointmentsstartingfromthesecondone.
a)Checkifthecurrentappointmentconflictswithanyoftheexisting
appointmentsinIntervalTree.Ifconflicts,thenprintthecurrent
appointment.ThisstepcanbedoneO(Logn)time.
b)InsertthecurrentappointmentinIntervalTree.Thisstepalsocan
bedoneO(Logn)time.
FollowingisC++implementationofaboveidea.
// C++ program to print all conflicting appointments in a
// given set of appointments
#include <iostream>
using namespace std;
};
return root;
}
if (res != NULL)
cout << "[" << appt[i].low << "," << appt[i].high
<< "] Conflicts with [" << res->low << ","
<< res->high << "]\n";
Followingareconflictingintervals
[3,7]Conflictswith[1,5]
[2,6]Conflictswith[1,5]
[5,6]Conflictswith[3,7]
[4,100]Conflictswith[1,5]
=======================================================
PerfectBinaryTreeSpecificLevel
OrderTraversal
GivenaPerfectBinaryTreelikebelow:
(clickonimagetogetaclearview)
Printthelevelorderofnodesinfollowingspecificmanner:
12347568159141013111216311730182919282027212622252324
i.e.printnodesinlevelorderbutnodesshouldbefromleftandrightsidealternatively.Here1stand2ndlevels
aretrivial.
While3rdlevel:4(left),7(right),5(left),6(right)areprinted.
While4thlevel:8(left),15(right),9(left),14(right),..areprinted.
While5thlevel:16(left),31(right),17(left),30(right),..areprinted.
Westronglyrecommendtominimizeyourbrowserandtrythisyourselffirst.
InstandardLevelOrderTraversal,weenqueuerootintoaqueue1st,thenwedequeueONEnodefrom
queue,process(print)it,enqueueitschildrenintoqueue.Wekeepdoingthisuntilqueueisempty.
Approach1:
Wecandostandardlevelordertraversalheretoobutinsteadofprintingnodesdirectly,wehavetostore
nodesincurrentlevelinatemporaryarrayorlist1standthentakenodesfromalternateends(leftandright)
andprintnodes.Keeprepeatingthisforalllevels.
Thisapproachtakesmorememorythanstandardtraversal.
Approach2:
Thestandardlevelordertraversalideawillslightlychangehere.InsteadofprocessingONEnodeatatime,
wewillprocessTWOnodesatatime.Andwhilepushingchildrenintoqueue,theenqueueorderwillbe:1st
nodesleftchild,2ndnodesrightchild,1stnodesrightchildand2ndnodesleftchild.
/* C++ program for special order traversal */
#include <iostream>
#include <queue>
if (root->left->left == NULL)
return;
// traversal loop
while (!q.empty())
{
// Pop two items from queue
first = q.front();
q.pop();
second = q.front();
q.pop();
root->left
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
root->left->left->left = newNode(8);
root->left->left->right = newNode(9);
root->left->right->left = newNode(10);
root->left->right->right = newNode(11);
root->right->left->left = newNode(12);
root->right->left->right = newNode(13);
root->right->right->left = newNode(14);
root->right->right->right = newNode(15);
root->left->left->left->left = newNode(16);
root->left->left->left->right = newNode(17);
root->left->left->right->left = newNode(18);
root->left->left->right->right = newNode(19);
root->left->right->left->left = newNode(20);
root->left->right->left->right = newNode(21);
root->left->right->right->left = newNode(22);
root->left->right->right->right = newNode(23);
root->right->left->left->left = newNode(24);
root->right->left->left->right = newNode(25);
root->right->left->right->left = newNode(26);
root->right->left->right->right = newNode(27);
root->right->right->left->left = newNode(28);
root->right->right->left->right = newNode(29);
root->right->right->right->left = newNode(30);
root->right->right->right->right = newNode(31);
return 0;
}
Output:
SpecificLevelOrdertraversalofbinarytreeis
12347568159141013111216311730182919282027212622252324
=======================================================
PrintNodesinTopViewofBinary
Tree
Topviewofabinarytreeisthesetofnodesvisiblewhenthetreeisviewedfromthetop.Givenabinary
tree,printthetopviewofit.Theoutputnodescanbeprintedinanyorder.ExpectedtimecomplexityisO(n)
Anodexisthereinoutputifxisthetopmostnodeatitshorizontaldistance.Horizontaldistanceofleftchild
ofanodexisequaltohorizontaldistanceofxminus1,andthatofrightchildishorizontaldistanceofxplus
1.
1
/\
23
/\/\
4567
Topviewoftheabovebinarytreeis
42137
1
/\
23
\
4
\
5
\
6
Topviewoftheabovebinarytreeis
2136
Westronglyrecommendtominimizeyourbrowserandtrythisyourselffirst.
TheideaistodosomethingsimilartoverticalOrderTraversal.LikeverticalOrderTraversal,weneedto
nodesofsamehorizontaldistancetogether.Wedoalevelordertraversalsothatthetopmostnodeata
horizontalnodeisvisitedbeforeanyothernodeofsamehorizontaldistancebelowit.Hashingisusedto
checkifanodeatgivenhorizontaldistanceisseenornot.
// Java program to print top view of Binary tree
import java.util.*;
// Constructor
public TreeNode(int key)
{
this.key = key;
left = right = null;
}
}
node = n;
hd = h;
}
}
// Constructors
public Tree() { root = null; }
public Tree(TreeNode n) { root = n; }
if (!set.contains(hd))
{
set.add(hd);
System.out.print(n.key + " ");
}
FollowingarenodesintopviewofBinaryTree
1236
=======================================================
KDimensionalTree
AKDTree(alsocalledasKDimensionalTree)isabinarysearchtreewheredataineachnodeisa
KDimensionalpointinspace.Inshort,itisaspacepartitioning(detailsbelow)datastructurefororganizing
pointsinaKDimensionalspace.
AnonleafnodeinKDtreedividesthespaceintotwoparts,calledashalfspaces.
Pointstotheleftofthisspacearerepresentedbytheleftsubtreeofthatnodeandpointstotherightofthe
spacearerepresentedbytherightsubtree.Wewillsoonbeexplainingtheconceptonhowthespaceis
dividedandtreeisformed.
Forthesakeofsimplicity,letusunderstanda2DTreewithanexample.
Therootwouldhaveanxalignedplane,therootschildrenwouldbothhaveyalignedplanes,theroots
grandchildrenwouldallhavexalignedplanes,andtherootsgreatgrandchildrenwouldallhaveyaligned
planesandsoon.
Generalization:
Letusnumbertheplanesas0,1,2,(K1).Fromtheaboveexample,itisquiteclearthatapoint(node)
atdepthDwillhaveAalignedplanewhereAiscalculatedas:
A=DmodK
Howtodetermineifapointwilllieintheleftsubtreeorinrightsubtree?
IftherootnodeisalignedinplaneA,thentheleftsubtreewillcontainallpointswhosecoordinatesinthat
planearesmallerthanthatofrootnode.Similarly,therightsubtreewillcontainallpointswhosecoordinates
inthatplanearegreaterequaltothatofrootnode.
Creationofa2DTree:
Considerfollowingpointsina2Dplane:
(3,6),(17,15),(13,15),(6,12),(9,1),(2,7),(10,19)
1.
Insert(3,6):Sincetreeisempty,makeittherootnode.
2.
Insert(17,15):Compareitwithrootnodepoint.SincerootnodeisXaligned,theXcoordinatevalue
willbecomparedtodetermineifitliesintherightsubtreeorintherightsubtree.Thispointwillbe
Yaligned.
3.
Insert(13,15):XvalueofthispointisgreaterthanXvalueofpointinrootnode.So,thiswillliein
therightsubtreeof(3,6).AgainCompareYvalueofthispointwiththeYvalueofpoint(17,15)
(Why?).Since,theyareequal,thispointwilllieintherightsubtreeof(17,15).Thispointwillbe
Xaligned.
4.
Insert(6,12):XvalueofthispointisgreaterthanXvalueofpointinrootnode.So,thiswilllieinthe
rightsubtreeof(3,6).AgainCompareYvalueofthispointwiththeYvalueofpoint(17,15)(Why?).
Since,12<15,thispointwilllieintheleftsubtreeof(17,15).ThispointwillbeXaligned.
5.
Insert(9,1):Similarly,thispointwilllieintherightof(6,12).
6.
Insert(2,7):Similarly,thispointwilllieintheleftof(3,6).
7.
Insert(10,19):Similarly,thispointwilllieintheleftof(13,15).
Howisspacepartitioned?
All7pointswillbeplottedintheXYplaneasfollows:
1.
Point(3,6)willdividethespaceintotwoparts:DrawlineX=3.
2.
3.
Point(2,7)willdividethespacetotheleftoflineX=3intotwopartshorizontally.
4.
DrawlineY=7totheleftoflineX=3.
5.
6.
Point(17,15)willdividethespacetotherightoflineX=3intotwopartshorizontally.
7.
DrawlineY=15totherightoflineX=3.
8.
Point(6,12)willdividethespacebelowlineY=15andtotherightoflineX=3intotwoparts.
DrawlineX=6totherightoflineX=3andbelowlineY=15.
Point(13,15)willdividethespacebelowlineY=15andtotherightoflineX=6intotwoparts.
DrawlineX=13totherightoflineX=6andbelowlineY=15.
Point(9,1)willdividethespacebetweenlinesX=3,X=6andY=15intotwoparts.
DrawlineY=1betweenlinesX=3andX=6.
Point(10,19)willdividethespacetotherightoflineX=3andabovelineY=15intotwoparts.
DrawlineY=19totherightoflineX=3andabovelineY=15.
FollowingisC++implementationofKDTreebasicoperationslikesearch,insertanddelete.
// A C++ program to demonstrate operations of KD tree
#include <iostream>
#include <cstdio>
#include <cassert>
#include <cstdlib>
using namespace std;
point->k = k;
point->coord = new int[k];
return point;
}
input->n = n;
input->pointArray = new Point*[n];
return input;
}
{
*root = newNode;
return;
}
// Compare the new point with root and decide the left or
// right subtree
if ((newNode->point).coord[axisOfComparison] <
((*root)->point).coord[axisOfComparison])
InsertKDTreeUtil(&((*root)->left), newNode, depth + 1);
else
InsertKDTreeUtil(&((*root)->right), newNode, depth + 1);
}
return 1;
}
if (ArePointsSame(root->point, point))
return 1;
if (point.coord[axisOfComparison] <
(root->point).coord[axisOfComparison])
return SearchKDTreeUtil(root->left, point, depth + 1);
InsertKDTree(&root, input->pointArray[i]);
return root;
}
input->pointArray[itp] = CreatePoint(k);
PrintArray(input->pointArray[itp]->coord, k);
}
return 0;
}
Output:
17
140
94
1818
24
55
17
InordertraversalofKDTreecreatedis:
17
140
24
17
55
94
1818
=======================================================
ConvertaBinaryTreetoThreaded
binarytree
WehavediscussedThreadedBinaryTree.Theideaofthreadedbinarytreesistomakeinordertraversal
fasteranddoitwithoutstackandwithoutrecursion.Inasimplethreadedbinarytree,theNULLrightpointers
areusedtostoreinordersuccessor.WhereeverarightpointerisNULL,itisusedtostoreinorder
successor.
FollowingdiagramshowsanexampleSingleThreadedBinaryTree.Thedottedlinesrepresentthreads.
Followingisstructureofsinglethreadedbinarytree.
struct Node
{
int key;
Node *left, *right;
FollowingisC++implementationoftheaboveidea.
/* C++ program to convert a Binary Tree to Threaded Tree */
#include <iostream>
#include <queue>
using namespace std;
if (root->left)
createThreadedUtil(root->left, q);
q->pop();
if (root->right)
createThreadedUtil(root->right, q);
1
/\
2
/\/\
4 56 7
*/
createThreaded(root);
Inordertraversalofcreeatedthreadedtreeis
4251637
==================================================================================
SerializeandDeserializeanNary
Tree
GivenanNarytreewhereeverynodehasatmostNchildren.Howtoserializeanddeserialzeit?
Serializationistostoretreeinafilesothatitcanbelaterrestored.Thestructureoftreemustbemaintained.
Deserializationisreadingtreebackfromfile.
Thispostismainlyanextensionofbelowpost.
SerializeandDeserializeaBinaryTree
InanNarytree,therearenodesignatedleftandrightchildren.AnNarytreeisrepresentedbystoringan
arrayorlistofchildpointerswitheverynode.
Theideaistostoreanendofchildrenmarkerwitheverynode.Thefollowingdiagramshowsserialization
where)isusedasendofchildrenmarker.Thediagramistakenfromhere.
FollowingisC++implementationofaboveidea.
// A C++ Program serialize and deserialize an N-ary tree
#include<cstdio>
#define MARKER ')'
#define N 5
using namespace std;
{
// Base case
if (root == NULL) return;
// Else create node with this item and recur for children
root = newNode(val);
for (int i = 0; i < N; i++)
if (deSerialize(root->child[i], fp))
break;
// Let us open a file and serialize the tree into the file
FILE *fp = fopen("tree.txt", "w");
if (fp == NULL)
{
puts("Could not open file");
return 0;
}
serialize(root, fp);
fclose(fp);
return 0;
}
Output:
ConstructedNAryTreefromfileis
ABEFKCDGHIJ
==================================================================================
SerializeandDeserializeaBinary
Tree
Serializationistostoretreeinafilesothatitcanbelaterrestored.Thestructureoftreemustbemaintained.
Deserializationisreadingtreebackfromfile.
Followingaresomesimplerversionsoftheproblem:
IfgivenTreeisBinarySearchTree?
IfthegivenBinaryTreeisBinarySearchTree,wecanstoreitbyeitherstoringpreorderorpostorder
traversal.IncaseofBinarySearchTrees,onlypreorderorpostordertraversalissufficienttostorestructure
information.
IfgivenBinaryTreeisCompleteTree?
ABinaryTreeiscompleteifalllevelsarecompletelyfilledexceptpossiblythelastlevelandallnodesoflast
levelareasleftaspossible(BinaryHeapsarecompleteBinaryTree).ForacompleteBinaryTree,level
ordertraversalissufficienttostorethetree.Weknowthatthefirstnodeisroot,nexttwonodesarenodesof
nextlevel,nextfournodesarenodesof2ndlevelandsoon.
IfgivenBinaryTreeisFullTree?
AfullBinaryisaBinaryTreewhereeverynodehaseither0or2children.Itiseasytoserializesuchtreesas
everyinternalnodehas2children.Wecansimplystorepreordertraversalandstoreabitwitheverynodeto
indicatewhetherthenodeisaninternalnodeoraleafnode.
HowtostoreageneralBinaryTree?
AsimplesolutionistostorebothInorderandPreordertraversals.Thissolutionrequiresrequiresspace
twicethesizeofBinaryTree.
WecansavespacebystoringPreordertraversalandamarkerforNULLpointers.
LetthemarkerforNULLpointersbe'1'
Input:
12
/
13
Output:121311
Input:
20
/\
822
Output:208112211
Input:
20
/
8
/\
412
/\
1014
Output:20841112101114111
Input:
20
/
8
/
10
/
5
Output:20810511111
Input:
20
\
8
\
10
\
5
Output:20181101511
Deserializationcanbedonebysimplyreadingdatafromfileonebyone.
FollowingisC++implementationoftheaboveidea.
// A C++ program to demonstrate serialization and deserialiation of
// Binary Tree
#include <stdio.h>
#define MARKER -1
/* A binary tree Node has key, pointer to left and right children */
struct Node
{
int key;
struct Node* left, *right;
};
// Else create node with this item and recur for children
root = newNode(val);
deSerialize(root->left, fp);
deSerialize(root->right, fp);
}
= newNode(20);
root->left
= newNode(8);
root->right
= newNode(22);
root->left->left
= newNode(4);
root->left->right
= newNode(12);
root->left->right->left = newNode(10);
root->left->right->right = newNode(14);
// Let us open a file and serialize the tree into the file
FILE *fp = fopen("tree.txt", "w");
if (fp == NULL)
{
puts("Could not open file");
return 0;
}
serialize(root, fp);
fclose(fp);
return 0;
}
Output:
InorderTraversalofthetreeconstructedfromfile:
481012142022
Howmuchextraspaceisrequiredinabovesolution?
Iftherearenkeys,thentheabovesolutionrequiresn+1markerswhichmaybebetterthansimplesolution
(storingkeystwice)insituationswherekeysarebigorkeyshavebigdataitemsassociatedwiththem.
Canweoptimizeitfurther?
Theabovesolutioncanbeoptimizedinmanyways.Ifwetakeacloserlookataboveserializedtrees,we
canobserverthatallleafnodesrequiretwomarkers.Onesimpleoptimizationistostoreaseparatebitwith
everynodetoindicatethatthenodeisinternalorexternal.Thiswaywedonthavetostoretwomarkerswith
everyleafnodeasleavescanbeidentifiedbyextrabit.Westillneedmarkerforinternalnodeswithone
child.Forexampleinthefollowingdiagramisusedtoindicateaninternalnodesetbit,and/isusedas
NULLmarker.Thediagramistakenfromhere.
PleasenotethattherearealwaysmoreleafnodesthaninternalnodesinaBinaryTree(Numberofleaf
nodesisnumberofinternalnodesplus1,sothisoptimizationmakessense.
Howtoserializenarytree?
Inannarytree,thereisnodesignatedleftorrightchild.Wecanstoreanendofchildrenmarkerwithevery
node.Thefollowingdiagramshowsserializationwhere)isusedasendofchildrenmarker.Wewillsoonbe
coveringimplementationfornarytree.Thediagramistakenfromhere.
==================================================================================
Printnodesbetweentwogivenlevel
numbersofabinarytree
Givenabinarytreeandtwolevelnumberslowandhigh,printnodesfromlevellowtolevelhigh.
Forexampleconsiderthebinarytreegiveninbelowdiagram.
Input:Rootofbelowtree,low=2,high=4
Output:
822
412
1014<>
ASimpleMethodistofirstwritearecursivefunctionthatprintsnodesofagivenlevelnumber.Thencall
recursivefunctioninaloopfromlowtohigh.TimecomplexityofthismethodisO(n2)
WecanprintnodesinO(n)timeusingqueuebasediterativelevelordertraversal.Theideaistodosimple
queuebasedlevelordertraversal.Whiledoinginordertraversal,addamarkernodeattheend.Whenever
weseeamarkernode,weincreaselevelnumber.Iflevelnumberisbetweenlowandhigh,thenprintnodes.
ThefollowingisC++implementationofaboveidea.
// A C++ program to print Nodes level by level berween given two levels.
#include <iostream>
#include <queue>
using namespace std;
/* A binary tree Node has key, pointer to left and right children */
struct Node
{
int key;
struct Node* left, *right;
};
/* Given a binary tree, print nodes from level number 'low' to level
number 'high'*/
void printLevels(Node* root, int low, int high)
{
queue <Node *> Q;
int level = 1;
// Enqueue the only first level node and marker node for end of level
Q.push(root);
Q.push(marker);
= newNode(20);
root->left
= newNode(8);
root->right
= newNode(22);
root->left->left
= newNode(4);
root->left->right
= newNode(12);
root->left->right->left = newNode(10);
root->left->right->right = newNode(14);
cout << "Level Order traversal between given two levels is";
printLevels(root, 2, 3);
return 0;
}
LevelOrdertraversalbetweengiventwolevelsis
822
412
==================================================================================
FindHeightofBinaryTree
representedbyParentarray
Agivenarrayrepresentsatreeinsuchawaythatthearrayvaluegivestheparentnodeofthatparticular
index.Thevalueoftherootnodeindexwouldalwaysbe1.Findtheheightofthetree.
HeightofaBinaryTreeisnumberofnodesonthepathfromroottothedeepestleafnode,thenumber
includesbothrootandleaf.
Input:parent[]={1552213}
Output:4
ThegivenarrayrepresentsfollowingBinaryTree
5
/\
12
//\
034
/
6
Input:parent[]={1,0,0,1,1,3,5}
Output:5
ThegivenarrayrepresentsfollowingBinaryTree
0
/\
12
/\
34
/
5
/
Source:AmazonInterviewexperience|Set128(ForSDET)
Westronglyrecommendtominimizeyourbrowserandtrythisyourselffirst.
Asimplesolutionistofirstconstructthetreeandthenfindheightoftheconstructedbinarytree.Thetree
canbeconstructedrecursivelybyfirstsearchingthecurrentroot,thenrecurringforthefoundindexesand
makingthemleftandrightsubtreesofroot.ThissolutiontakesO(n2)aswehavetolinearlysearchforevery
node.
AnefficientsolutioncansolvetheaboveprobleminO(n)time.Theideaistofirstcalculatedepthofevery
nodeandstoreinanarraydepth[].Oncewehavedepthsofallnodes,wereturnmaximumofalldepths.
1)Finddepthofallnodesandfillinanauxiliaryarraydepth[].
2)Returnmaximumvalueindepth[].
Followingarestepstofinddepthofanodeatindexi.
1)Ifitisroot,depth[i]is1.
2)Ifdepthofparent[i]isevaluated,depth[i]isdepth[parent[i]]+1.
3)Ifdepthofparent[i]isnotevaluated,recurforparentandassigndepth[i]asdepth[parent[i]]+1(sameas
above).
FollowingisC++implementationofaboveidea.
// C++ program to find height using parent array
#include <iostream>
using namespace std;
int n = sizeof(parent)/sizeof(parent[0]);
cout << "Height is " << findHeight(parent, n);
return 0;
}
Output:
Heightis5
==================================================================================
Minimumno.ofiterationstopass
informationtoallnodesinthetree
Givenaverylargenarytree.Wheretherootnodehassomeinformationwhichitwantstopasstoallofits
childrendowntotheleaveswiththeconstraintthatitcanonlypasstheinformationtooneofitschildrenata
time(takeitasoneiteration).
Nowinthenextiterationthechildnodecantransferthatinformationtoonlyoneofitschildrenandatthe
sametimeinstancethechildsparenti.e.rootcanpasstheinfotooneofitsremainingchildren.Continuing
inthiswaywehavetofindtheminimumnoofiterationsrequiredtopasstheinformationtoallnodesinthe
tree.
Minimumnoofiterationsfortreebelowis6.TherootAfirstpassesinformationtoB.Innextiteration,A
passesinformationtoEandBpassesinformationtoHandsoon.
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
ThiscanbedoneusingPostOrderTraversal.Theideaistoconsiderheightandchildrencountoneachand
everynode.
Ifachildnodeitakesciiterationstopassinfobelowitssubtree,thenitsparentwilltake(ci+1)iterationsto
passinfotosubtreerootedatthatchildi.
Ifparenthasmorechildren,itwillpassinfototheminsubsequentiterations.Letssaychildrenofaparent
takesc1,c2,c3,c4,,cniterationstopassinfointheirownsubtree,Nowparenthastopassinfotothese
nchildrenonebyoneinniterations.Ifparentpickschildiinithiteration,thenparentwilltake(i+ci)
iterationstopassinfotochildiandallitssubtree.
Inanyiteration,whenparentpassesinfoachildi+1,children(1toi)whichgotinfofromparentalreadyin
previousiterations,willpassinfotofurtherdowninsubsequentiterations,ifanychild(1toi)hasitsown
childfurtherdown.
Topassinfotowholetreeinminimumiterations,itneedstobemadesurethatbandwidthisutilizedas
efficientlyaspossible(i.e.maximumpassablenoofnodesshouldpassinfofurtherdowninanyiteration)
Thebestpossiblescenariowouldbethatinnthiteration,ndifferentnodespassinfototheirchild.
Nodeswithheight=0:(Trivialcase)Leafnodehasnochildren(noinformationpassingneeded),sonoof
iterationswouldbeZERO.
Nodeswithheight=1:Herenodehastopassinfotoallthechildrenonebyone(allchildrenareleafnode,
sonomoreinformationpassingfurtherdown).Sinceallchildrenareleaf,nodecanpassinfotoanychildin
anyorder(pickanychildwhodidntreceivetheinfoyet).Oneiterationneededforeachchildandsonoof
iterationswouldbenoofchildren.Sonodewithheight1withnchildrenwilltakeniterations.
TakeacounterinitializedwithZERO,loopthroughallchildrenandkeepincrementingcounter.
Nodeswithheight>1:Letsassumethattherearenchildren(1ton)ofanodeandminimumnoiterations
forallnchildrenarec1,c2,.,cn.
Tomakesuremaximumnoofnodesparticipateininfopassinginanyiteration,parentshould1stpassinfo
tothatchildwhowilltakemaximumiterationtopassinfofurtherdowninsubsequentiterations.i.e.inany
iteration,parentshouldchoosethechildwhotakesmaximumiterationlateron.Itcanbethoughtofasa
greedyapproachwhereparentchoosethatchild1st,whoneedsmaximumnoofiterationssothatall
subsequentiterationscanbeutilizedefficiently.
Ifparentgoesinanyotherfashion,thenintheend,therecouldbesomenodeswhicharedonequiteearly,
sittingidleandsobandwidthisnotutilizedefficientlyinfurtheriterations.
Iftherearetwochildreniandjwithminimumiterationsciandcjwhereci>cj,thenIfparentpickschildj1st
thennoofiterationsneededbyparenttopassinfotobothchildrenandtheirsubtreewouldbe:max(1+cj,2
+ci)=2+ci
Ifparentpickschildi1stthennoofiterationsneededbyparenttopassinfotobothchildrenandtheir
subtreewouldbe:max(1+ci,2+cj)=1+ci(Sopickingcigivesbetterresultthanpickingcj)
Thistellsthatparentshouldalwayschoosechildiwithmaxcivalueinanyiteration.
SOheregreedyapproachis:
sortallcivaluesdecreasingorder,
letssayaftersorting,valuesarec1>c2>c3>.>cn
takeacounterc,setc=1+c1(forchildwithmaximumnoofiterations)
forallchildrenifrom2ton,c=c+1+ci
thentotalnoofiterationsneededbyparentismax(n,c)
LetminItr(A)betheminimumiterationneededtopassinfofromnodeAtoitsallthesubtree.Letchild(A)
bethecountofallchildrenfornodeA.Sorecursiverelationwouldbe:
1.GetminItr(B)ofallchildren(B)ofanode(A)
2.SortallminItr(B)indescendingorder
3.GetminItrofAbasedonallminItr(B)
minItr(A)=child(A)
ForchildrenBfromi=0tochild(A)
minItr(A)=max(minItr(A),minItr(B)+i+1)
Basecaseswouldbe:
Ifnodeisleaf,minItr=0
Ifnode'sheightis1,minItr=childrencount
FollowingisC++implementationofaboveidea.
// C++ program to find minimum number of iterations to pass
// information from root to all nodes in an n-ary tree
#include<iostream>
#include<list>
#include<cmath>
#include <stdlib.h>
using namespace std;
// Constructor
NAryTree::NAryTree(int N)
{
this->N = N;
adj = new list<int>[N];
}
// To add a child w to v
void NAryTree::addChild(int v, int w)
{
}
delete[] minItrTemp;
}
tree1.addChild(1, 7);
tree1.addChild(1, 8);
tree1.addChild(1, 9);
tree1.addChild(4, 10);
tree1.addChild(4, 11);
tree1.addChild(6, 12);
tree1.addChild(7, 13);
tree1.addChild(7, 14);
tree1.addChild(10, 15);
tree1.addChild(11, 16);
// TestCase 2
NAryTree tree2(3);
tree2.addChild(0, 1);
tree2.addChild(0, 2);
cout << "TestCase 2 - Minimum Iteration: "
<< tree2.getMinIter() << endl;
// TestCase 3
NAryTree tree3(1);
cout << "TestCase 3 - Minimum Iteration: "
<< tree3.getMinIter() << endl;
// TestCase 4
NAryTree tree4(6);
tree4.addChild(0, 1);
tree4.addChild(1, 2);
tree4.addChild(2, 3);
tree4.addChild(3, 4);
tree4.addChild(4, 5);
// TestCase 5
NAryTree tree5(6);
tree5.addChild(0, 1);
tree5.addChild(0, 2);
tree5.addChild(2, 3);
tree5.addChild(2, 4);
tree5.addChild(2, 5);
cout << "TestCase 5 - Minimum Iteration: "
<< tree5.getMinIter() << endl;
// TestCase 6
NAryTree tree6(6);
tree6.addChild(0, 1);
tree6.addChild(0, 2);
tree6.addChild(2, 3);
tree6.addChild(2, 4);
tree6.addChild(3, 5);
cout << "TestCase 6 - Minimum Iteration: "
<< tree6.getMinIter() << endl;
// TestCase 7
NAryTree tree7(14);
tree7.addChild(0, 1);
tree7.addChild(0, 2);
tree7.addChild(0, 3);
tree7.addChild(1, 4);
tree7.addChild(2, 5);
tree7.addChild(2, 6);
tree7.addChild(4, 7);
tree7.addChild(5, 8);
tree7.addChild(5, 9);
tree7.addChild(7, 10);
tree7.addChild(8, 11);
tree7.addChild(8, 12);
tree7.addChild(10, 13);
cout << "TestCase 7 - Minimum Iteration: "
<< tree7.getMinIter() << endl;
// TestCase 8
NAryTree tree8(14);
tree8.addChild(0, 1);
tree8.addChild(0, 2);
tree8.addChild(0, 3);
tree8.addChild(0, 4);
tree8.addChild(0, 5);
tree8.addChild(1, 6);
tree8.addChild(2, 7);
tree8.addChild(3, 8);
tree8.addChild(4, 9);
tree8.addChild(6, 10);
tree8.addChild(7, 11);
tree8.addChild(8, 12);
tree8.addChild(9, 13);
cout << "TestCase 8 - Minimum Iteration: "
<< tree8.getMinIter() << endl;
// TestCase 9
NAryTree tree9(25);
tree9.addChild(0, 1);
tree9.addChild(0, 2);
tree9.addChild(0, 3);
tree9.addChild(0, 4);
tree9.addChild(0, 5);
tree9.addChild(0, 6);
tree9.addChild(1, 7);
tree9.addChild(2, 8);
tree9.addChild(3, 9);
tree9.addChild(4, 10);
tree9.addChild(5, 11);
tree9.addChild(6, 12);
tree9.addChild(7, 13);
tree9.addChild(8, 14);
tree9.addChild(9, 15);
tree9.addChild(10, 16);
tree9.addChild(11, 17);
tree9.addChild(12, 18);
tree9.addChild(13, 19);
tree9.addChild(14, 20);
tree9.addChild(15, 21);
tree9.addChild(16, 22);
tree9.addChild(17, 23);
tree9.addChild(19, 24);
return 0;
}
Output:
TestCase1MinimumIteration:6
TestCase2MinimumIteration:2
TestCase3MinimumIteration:0
TestCase4MinimumIteration:5
TestCase5MinimumIteration:4
TestCase6MinimumIteration:3
TestCase7MinimumIteration:6
TestCase8MinimumIteration:6
TestCase9MinimumIteration:8
==================================================================================
CloneaBinaryTreewithRandom
Pointers
GivenaBinaryTreewhereeverynodehasfollowingstructure.
structnode{
intkey
structnode*left,*right,*random
}
TherandompointerpointstoanyrandomnodeofthebinarytreeandcanevenpointtoNULL,clonethe
givenbinarytree.
Method1(UseHashing)
Theideaistostoremappingfromgiventreenodestoclonetrenodeinhashtable.Followingaredetailed
steps.
1)RecursivelytraversethegivenBinaryandcopykeyvalue,leftpointerandrightpointertoclonetree.
Whilecopying,storethemappingfromgiventreenodetoclonetreenodeinahashtable.Inthefollowing
pseudocode,cloneNodeiscurrentlyvisitednodeofclonetreeandtreeNodeiscurrentlyvisitednodeof
giventree.
cloneNode>key=treeNode>key
cloneNode>left=treeNode>left
cloneNode>right=treeNode>right
map[treeNode]=cloneNode
2)Recursivelytraversebothtreesandsetrandompointersusingentriesfromhashtable.
cloneNode>random=map[treeNode>random]
FollowingisC++implementationofaboveidea.ThefollowingimplementationusesmapfromC++STL.
Notethatmapdoesntimplementhashtable,itactuallyisbasedonselfbalancingbinarysearchtree.
// A hashmap based C++ program to clone a binary tree with random pointers
#include<iostream>
#include<map>
using namespace std;
/* A binary tree node has data, pointer to left child, a pointer to right
child and a pointer to random node*/
struct Node
{
int key;
struct Node* left, *right, *random;
};
// This function creates clone by copying key and left and right pointers
// This function also stores mapping from given tree node to clone.
Node* copyLeftRightNode(Node* treeNode, map<Node *, Node *> *mymap)
{
if (treeNode == NULL)
return NULL;
Node* cloneNode = newNode(treeNode->key);
(*mymap)[treeNode] = cloneNode;
cloneNode->left = copyLeftRightNode(treeNode->left, mymap);
cloneNode->right = copyLeftRightNode(treeNode->right, mymap);
return cloneNode;
}
// Test No 2
//tree = NULL;
// Test No 3
//tree = newNode(1);
// Test No 4
/*tree = newNode(1);
tree->left = newNode(2);
tree->right = newNode(3);
tree->random = tree->right;
tree->left->random = tree;
*/
return 0;
}
Output:
Inordertraversaloforiginalbinarytreeis:
[41],[2NULL],[53],[15],[3NULL],
Inordertraversalofclonedbinarytreeis:
[41],[2NULL],[53],[15],[3NULL],
Method2(TemporarilyModifytheGivenBinaryTree)
1.Createnewnodesinclonedtreeandinserteachnewnodeinoriginaltreebetweentheleftpointeredge
ofcorrespondingnodeintheoriginaltree(Seethebelowimage).
i.e.ifcurrentnodeisAanditsleftchildisB(A>>B),thennewclonednodewithkeyAwilbecreated
(saycA)anditwillbeputasA>>cA>>B(BcanbeaNULLoranonNULLleftchild).Rightchild
pointerwillbesetcorrectlyi.e.ifforcurrentnodeA,rightchildisCinoriginaltree(A>>C)then
correspondingclonednodescAandcCwilllikecA>>cC
2.Setrandompointerinclonedtreeasperoriginaltree
i.e.ifnodeAsrandompointerpointstonodeB,theninclonedtree,cAwillpointtocB(cAandcBarenew
nodeinclonedtreecorrespondingtonodeAandBinoriginaltree)
3.Restoreleftpointerscorrectlyinbothoriginalandclonedtree
FollowingisC++implementationofabovealgorithm.
#include <iostream>
using namespace std;
/* A binary tree node has data, pointer to left child, a pointer to right
child and a pointer to random node*/
struct Node
{
int key;
struct Node* left, *right, *random;
};
// This function creates new nodes cloned tree and puts new cloned node
// in between current node and it's left child
// i.e. if current node is A and it's left child is B ( A --- >> B ),
//
then new cloned node with key A wil be created (say cA) and
//
it will be put as
//
treeNode->left->right = copyLeftRightNode(treeNode->right);
return treeNode->left;
}
// This function sets random pointer in cloned tree as per original tree
// i.e. if node A's random pointer points to node B, then
// in cloned tree, cA wil point to cB (cA and cB are new node in cloned
// tree corresponding to node A and B in original tree)
void copyRandomNode(Node* treeNode, Node* cloneNode)
{
if (treeNode == NULL)
return;
if(treeNode->random != NULL)
cloneNode->random = treeNode->random->left;
else
cloneNode->random = NULL;
restoreTreeLeftNode(treeNode->left, cloneNode->left);
restoreTreeLeftNode(treeNode->right, cloneNode->right);
}
tree->left = newNode(2);
tree->right = newNode(3);
tree->left->left = newNode(4);
tree->left->right = newNode(5);
tree->random = tree->left->right;
tree->left->left->random = tree;
tree->left->right->random = tree->right;
// Test No 2
// Node *tree = NULL;
/*
// Test No 3
Node *tree = newNode(1);
// Test No 4
Node *tree = newNode(1);
tree->left = newNode(2);
tree->right = newNode(3);
tree->random = tree->right;
tree->left->random = tree;
Test No 5
Node *tree = newNode(1);
tree->left = newNode(2);
tree->right = newNode(3);
tree->left->left = newNode(4);
tree->left->right = newNode(5);
tree->right->left = newNode(6);
tree->right->right = newNode(7);
tree->random = tree->left;
*/
// Test No 6
Node *tree = newNode(10);
Node *n2 = newNode(6);
Node *n3 = newNode(12);
Node *n4 = newNode(5);
Node *n5 = newNode(8);
/* Test No 7
Node *tree = newNode(1);
tree->left = newNode(2);
tree->right = newNode(3);
tree->left->random = tree;
tree->right->random = tree->left;
*/
cout << "Inorder traversal of original binary tree is: \n";
printInorder(tree);
return 0;
}
Output:
Inordertraversaloforiginalbinarytreeis:
[59],[67],[7NULL],[810],[97],[106],[119],[128],[13NULL],
Inordertraversalofclonedbinarytreeis:
[59],[67],[7NULL],[810],[97],[106],[119],[128],[13NULL],
==================================================================================
Checkiftwonodesarecousinsina
BinaryTree
GiventhebinaryTreeandthetwonodessayaandb,determinewhetherthetwonodesarecousinsof
eachotherornot.
Twonodesarecousinsofeachotheriftheyareatsamelevelandhavedifferentparents.
Example
6
/\
35
/\/\
7813
Saytwonodebe7and1,resultisTRUE.
Saytwonodesare3and5,resultisFALSE.
Saytwonodesare7and5,resultisFALSE.
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
Theideaistofindlevelofoneofthenodes.Usingthefoundlevel,checkifaandbareatthislevel.Ifa
andbareatgivenlevel,thenfinallycheckiftheyarenotchildrenofsameparent.
FollowingisCimplementationoftheaboveapproach.
// C program to check if two Nodes in a binary tree are cousins
#include <stdio.h>
#include <stdlib.h>
{
int data;
struct Node *left, *right;
};
return 0;
}
Ouput:
Yes
==================================================================================
Checkifabinarytreeissubtreeof
anotherbinarytree|Set2
Giventwobinarytrees,checkifthefirsttreeissubtreeofthesecondone.AsubtreeofatreeTisatreeS
consistingofanodeinTandallofitsdescendantsinT.
Thesubtreecorrespondingtotherootnodeistheentiretreethesubtreecorrespondingtoanyothernodeis
calledapropersubtree.
Forexample,inthefollowingcase,Tree1isasubtreeofTree2.
Tree1
x
/\
ab
\
c
Tree2
z
/\
xe
/\\
abk
\
c
WehavediscussedaO(n2)solutionforthisproblem.InthispostaO(n)solutionisdiscussed.Theideais
basedonthefactthatinorderandpreorder/postorderuniquelyidentifyabinarytree.TreeSisasubtreeofT
ifbothinorderandpreordertraversalsofSarewsubstringsofinorderandpreordertraversalsofT
respectively.
Followingaredetailedsteps.
1)FindinorderandpreordertraversalsofT,storethemintwoauxiliaryarraysinT[]andpreT[].
2)FindinorderandpreordertraversalsofS,storethemintwoauxiliaryarraysinS[]andpreS[].
3)IfinS[]isasubarrayofinT[]andpreS[]isasubarraypreT[],thenSisasubtreeofT.Elsenot.
Wecanalsousepostordertraversalinplaceofpreorderintheabovealgorithm.
Letusconsidertheaboveexample
InorderandPreordertraversalsofthebigtreeare.
inT[]={a,c,x,b,z,e,k}
preT[]={z,x,a,c,b,e,k}
InorderandPreordertraversalsofsmalltreeare
inS[]={a,c,x,b}
preS[]={x,a,c,b}
WecaneasilyfigureoutthatinS[]isasubarrayof
inT[]andpreS[]isasubarrayofpreT[].
EDIT
Theabovealgorithmdoesn'tworkforcaseswhereatreeispresent
inanothertree,butnotasasubtree.Considerthefollowingexample.
Tree1
x
/\
ab
/
Tree2
x
/\
ab
/\
cd
InorderandPreordertraversalsofthebigtreeorTree2are.
InorderandPreordertraversalsofsmalltreeorTree1are
TheTree2isnotasubtreeofTree1,butinS[]andpreS[]are
subarraysofinT[]andpreT[]respectively.
Theabovealgorithmcanbeextendedtohandlesuchcasesbyaddingaspecialcharacterwheneverwe
encounterNULLininorderandpreordertraversals.ThankstoShivamGoelforsuggestingthisextension.
FollowingisC++implementationofabovealgorithm.
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 100
arr[i++] = root->key;
storeInorder(root->right, arr, i);
}
Node *S = newNode('a');
S->left = newNode('b');
S->left->left = newNode('c');
S->right = newNode('d');
if (isSubtree(T, S))
cout << "Yes: S is a subtree of T";
else
cout << "No: S is NOT a subtree of T";
return 0;
}
Output:
No:SisNOTasubtreeofT
==================================================================================
Inorderpredecessorandsuccessor
foragivenkeyinBST
Irecentlyencounteredwithaquestioninaninterviewatecommercecompany.Theintervieweraskedthe
followingquestion:
ThereisBSTgivenwithrootnodewithkeypartasintegeronly.Thestructureofeachnodeisasfollows:
struct Node
{
int key;
struct Node *left, *right ;
};
Youneedtofindtheinordersuccessorandpredecessorofagivenkey.Incasethegivenkeyisnotfoundin
BST,thenreturnthetwovalueswithinwhichthiskeywilllie.
Followingisthealgorithmtoreachthedesiredresult.Itsarecursivemethod:
Input:rootnode,key
output:predecessornode,successornode
1.IfrootisNULL
thenreturn
2.ifkeyisfoundthen
a.Ifitsleftsubtreeisnotnull
Thenpredecessorwillbetherightmost
childofleftsubtreeorleftchilditself.
b.Ifitsrightsubtreeisnotnull
Thesuccessorwillbetheleftmostchild
ofrightsubtreeorrightchilditself.
return
3.Ifkeyissmallerthenrootnode
setthesuccessorasroot
searchrecursivelyintoleftsubtree
else
setthepredecessorasroot
searchrecursivelyintorightsubtree
FollowingisC++implementationoftheabovealgorithm:
// C++ program to find predecessor and successor in a BST
#include <iostream>
using namespace std;
// BST Node
struct Node
{
int key;
struct Node *left, *right;
};
suc = tmp ;
}
return ;
}
70
/ \/ \
20
40 60
80 */
if (suc != NULL)
cout << "Successor is " << suc->key;
else
cout << "No Successor";
return 0;
}
Output:
Predecessoris60
Successoris70
==================================================================================
Findthemaximumpathsum
betweentwoleavesofabinarytree
Givenabinarytreeinwhicheachnodeelementcontainsanumber.Findthemaximumpossiblesumfrom
oneleafnodetoanother.
Themaximumsumpathmayormaynotgothroughroot.Forexample,inthefollowingbinarytree,the
maximumsumis27(3+6+9+01+10).ExpectedtimecomplexityisO(n).
AsimplesolutionistotraversethetreeanddofollowingforeverytraversednodeX.
1)FindmaximumsumfromleaftorootinleftsubtreeofX(wecanusethispostforthisandnextsteps)
2)FindmaximumsumfromleaftorootinrightsubtreeofX.
3)AddtheabovetwocalculatedvaluesandX>dataandcomparethesumwiththemaximumvalue
obtainedsofarandupdatethemaximumvalue.
4)Returnthemaximumvalue.
ThetimecomplexityofabovesolutionisO(n2)
Wecanfindthemaximumsumusingsingletraversalofbinarytree.Theideaistomaintaintwovalues
inrecursivecalls
1)Maximumroottoleafpathsumforthesubtreerootedundercurrentnode.
2)Themaximumpathsumbetweenleaves(desiredoutput).
ForeveryvisitednodeX,wefindthemaximumroottoleafsuminleftandrightsubtreesofX.Weaddthe
twovalueswithX>data,andcomparethesumwithmaximumpathsumfoundsofar.
FollowingisC++implementationoftheaboveO(n)solution.
// C++ program to find maximum path sum between two leaves of
// a binary tree
#include <iostream>
using namespace std;
// A utility function to find the maximum sum between any two leaves.
// This function calculates two values:
// 1) Maximum path sum between two leaves which is stored in res.
// 2) The maximum root to leaf path sum which is returned.
int maxPathSumUtil(struct Node *root, int &res)
{
// Base case
if (root==NULL) return 0;
root->left->left->right = newNode(6);
root->right->left = newNode(3);
root->right->right = newNode(9);
root->right->right->right= newNode(0);
root->right->right->right->left= newNode(4);
root->right->right->right->right= newNode(-1);
root->right->right->right->right->left= newNode(10);
cout << "Max pathSum of the given binary tree is " << maxPathSum(root);
return 0;
}
Output:
MaxpathSumofthegivenbinarytreeis27.
==================================================================================
Reversealternatelevelsofaperfect
binarytree
GivenaPerfectBinaryTree,reversethealternatelevelnodesofthebinarytree.
Giventree:
a
/\
bc
/\/\
defg
/\/\/\/\
hijklmno
Modifiedtree:
a
/\
cb
/\/\
defg
/\/\/\/\
onmlkjih
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
Asimplesolutionistodofollowingsteps.
1)Accessnodeslevelbylevel.
2)Ifcurrentlevelisodd,thenstorenodesofthislevelinanarray.
3)Reversethearrayandstoreelementsbackintree.
Atrickysolutionistodotwoinordertraversals.Followingarestepstobefollowed.
1)Traversethegiventreeininorderfashionandstorealloddlevelnodesinanauxiliaryarray.Forthe
aboveexamplegiventree,contentsofarraybecome{h,i,b,j,k,l,m,c,n,o}
2)Reversethearray.Thearraynowbecomes{o,n,c,m,l,k,j,b,i,h}
3)Traversethetreeagaininorderfashion.Whiletraversingthetree,onebyonetakeelementsfromarray
andstoreelementsfromarraytoeveryoddleveltraversednode.
Fortheaboveexample,wetraversehfirstinabovearrayandreplacehwitho.Thenwetraverseiand
replaceitwithn.
FollowingisC++implementationoftheabovealgorithm.
// C++ program to reverse alternate levels of a binary tree
#include<iostream>
#define MAX 100
using namespace std;
// binary tree
void printInorder(struct Node *root)
{
if (root == NULL) return;
printInorder(root->left);
cout << root->data << " ";
printInorder(root->right);
}
reverseAlternate(root);
return 0;
}
Output:
InorderTraversalofgiventree
hdibjekalfmcngo
InorderTraversalofmodifiedtree
odncmelakfjbigh
TimecomplexityoftheabovesolutionisO(n)asitdoestwoinordertraversalsofbinarytree.
==================================================================================
TransformaBSTtogreatersumtree
GivenaBST,transformitintogreatersumtreewhereeachnodecontainssumofallnodesgreaterthanthat
node.
Westronglyrecommendtominimizethegbrowserandtrythisyourselffirst.
Method1(Naive):
ThismethoddoesntrequirethetreetobeaBST.Followingaresteps.
1.Traversenodebynode(Inorder,preorder,etc.)
2.Foreachnodefindallthenodesgreaterthanthatofthecurrentnode,sumthevalues.Storeallthese
sums.
3.ReplaceeachnodevaluewiththeircorrespondingsumbytraversinginthesameorderasinStep1.
ThistakesO(n^2)TimeComplexity.
Method2(Usingonlyonetraversal)
ByleveragingthefactthatthetreeisaBST,wecanfindanO(n)solution.TheideaistotraverseBSTin
reverseinorder.ReverseinordertraversalofaBSTgivesuskeysindecreasingorder.Beforevisitinga
node,wevisitallgreaternodesofthatnode.Whiletraversingwekeeptrackofsumofkeyswhichisthesum
ofallthekeysgreaterthanthekeyofcurrentnode.
// C++ program to transform a BST to sum tree
#include<iostream>
using namespace std;
// A BST node
struct Node
{
int data;
struct Node *left, *right;
};
// Update sum
*sum = *sum + root->data;
printInorder(root->left);
cout << root->data << " ";
printInorder(root->right);
}
transformTree(root);
return 0;
}
Output:
InorderTraversalofgiventree
1271115293540
InorderTraversaloftransformedtree
13913713011910475400
TimecomplexityofthismethodisO(n)asitdoesasimpletraversaloftree.
==================================================================================
PrintaBinaryTreeinVertical
Order|Set2(Hashmapbased
Method)
Givenabinarytree,printitvertically.Thefollowingexampleillustratesverticalordertraversal.
1
/\
23
/\/\
4567
\\
89
Theoutputofprintthistreeverticallywillbe:
4
2
156
38
7
9
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
WehavediscussedaO(n2)solutioninthepreviouspost.Inthispost,anefficientsolutionbasedonhash
mapisdiscussed.WeneedtochecktheHorizontalDistancesfromrootforallnodes.Iftwonodeshavethe
sameHorizontalDistance(HD),thentheyareonsameverticalline.TheideaofHDissimple.HDforrootis
0,arightedge(edgeconnectingtorightsubtree)isconsideredas+1horizontaldistanceandaleftedgeis
consideredas1horizontaldistance.Forexample,intheabovetree,HDforNode4isat2,HDforNode2
is1,HDfor5and6is0andHDfornode7is+2.
WecandoinordertraversalofthegivenBinaryTree.Whiletraversingthetree,wecanrecursivelycalculate
HDs.Weinitiallypassthehorizontaldistanceas0forroot.Forleftsubtree,wepasstheHorizontalDistance
asHorizontaldistanceofrootminus1.Forrightsubtree,wepasstheHorizontalDistanceasHorizontal
Distanceofrootplus1.ForeveryHDvalue,wemaintainalistofnodesinahaspmap.Wheneverweseea
nodeintraversal,wegotothehashmapentryandaddthenodetothehashmapusingHDasakeyin
map.
FollowingisC++implementationoftheabovemethod.ThankstoChiragforprovidingthebelowC++
implementation.
// C++ program for printing vertical order of a given binary tree
#include <iostream>
#include <vector>
#include <map>
using namespace std;
Verticalordertraversalis
4
2
156
38
7
9
TimeComplexityofhashingbasedsolutioncanbeconsideredasO(n)undertheassumptionthatwehave
goodhashingfunctionthatallowsinsertionandretrievaloperationsinO(1)time.IntheaboveC++
implementation,mapofSTLisused.mapinSTListypicallyimplementedusingaSelfBalancingBinary
SearchTreewherealloperationstakeO(Logn)time.Thereforetimecomplexityofaboveimplementationis
O(nLogn).
==================================================================================
PrintRightViewofaBinaryTree
GivenaBinaryTree,printRightviewofit.RightviewofaBinaryTreeissetofnodesvisiblewhentreeis
visitedfromRightside.
Rightviewoffollowingtreeis1378
1
/\
23
/\/\
4567
\
8
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
TheRightviewcontainsallnodesthatarelastnodesintheirlevels.Asimplesolutionistodolevelorder
traversalandprintthelastnodeineverylevel.
Theproblemcanalsobesolvedusingsimplerecursivetraversal.Wecankeeptrackoflevelofanodeby
passingaparametertoallrecursivecalls.Theideaistokeeptrackofmaximumlevelalso.Andtraversethe
treeinamannerthatrightsubtreeisvisitedbeforeleftsubtree.Wheneverweseeanodewhoselevelis
morethanmaximumlevelsofar,weprintthenodebecausethisisthelastnodeinitslevel(Notethatwe
traversetherightsubtreebeforeleftsubtree).FollowingisCimplementationofthisapproach.
// C program to print right view of Binary Tree
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int data;
struct Node *left, *right;
};
{
struct Node *root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
root->right->left->right = newNode(8);
rightView(root);
return 0;
}
Output:
1378
TimeComplexity:Thefunctiondoesasimpletraversalofthetree,sothecomplexityisO(n).
==================================================================================
RedBlackTree|Set3(Delete)
WehavediscussedfollowingtopicsonRedBlacktreeinpreviousposts.Westronglyrecommendtorefer
followingpostasprerequisiteofthispost.
RedBlackTreeIntroduction
RedBlackTreeInsert
InsertionVsDeletion:
LikeInsertion,recoloringandrotationsareusedtomaintaintheRedBlackproperties.
Ininsertoperation,wecheckcolorofuncletodecidetheappropriatecase.Indeleteoperation,wecheck
colorofsiblingtodecidetheappropriatecase.
Themainpropertythatviolatesafterinsertionistwoconsecutivereds.Indelete,themainviolatedproperty
is,changeofblackheightinsubtreesasdeletionofablacknodemaycausereducedblackheightinone
roottoleafpath.
Deletionisfairlycomplexprocess.Tounderstanddeletion,notionofdoubleblackisused.Whenablack
nodeisdeletedandreplacedbyablackchild,thechildismarkedasdoubleblack.Themaintasknow
becomestoconvertthisdoubleblacktosingleblack.
DeletionSteps
Followingaredetailedstepsfordeletion.
1)PerformstandardBSTdelete.WhenweperformstandarddeleteoperationinBST,wealwaysendup
deletinganodewhichiseitherleaforhasonlyonechild(Foraninternalnode,wecopythesuccessorand
thenrecursivelycalldeleteforsuccessor,successorisalwaysaleafnodeoranodewithonechild).Sowe
onlyneedtohandlecaseswhereanodeisleaforhasonechild.Letvbethenodedeletedandubethe
childthatreplacesv.
2)SimpleCase:Ifeitheruorvisred,wemarkthereplacedchildasblack(Nochangeinblackheight).
Notethatbothuandvcannotberedasvisparentofuandtwoconsecutiveredsarenotallowedin
redblacktree.
3)IfBothuandvareBlack.
3.1)Coloruasdoubleblack.Nowourtaskreducestoconvertthisdoubleblacktosingleblack.NotethatIf
visleaf,thenuisNULLandcolorofNULLisconsideredasblack.Sothedeletionofablackleafalso
causesadoubleblack.
3.2)Dofollowingwhilethecurrentnodeuisdoubleblackoritisnotroot.Letsiblingofnodebes.
.(a):Ifsiblingsisblackandatleastoneofsiblingschildrenisred,performrotation(s).Letthered
childofsber.Thiscasecanbedividedinfoursubcasesdependinguponpositionsofsandr.
..(i)LeftLeftCase(sisleftchildofitsparentandrisleftchildofsorbothchildrenofsarered).
Thisismirrorofrightrightcaseshowninbelowdiagram.
..(ii)LeftRightCase(sisleftchildofitsparentandrisrightchild).Thisismirrorofrightleftcase
showninbelowdiagram.
..(iii)RightRightCase(sisrightchildofitsparentandrisrightchildofsorbothchildrenofsare
red)
..(iv)RightLeftCase(sisrightchildofitsparentandrisleftchildofs)
..(b):Ifsiblingisblackanditsbothchildrenareblack,performrecoloring,andrecurfortheparentif
parentisblack.
Inthiscase,ifparentwasred,thenwedidntneedtorecurforprent,wecansimplymakeitblack(red+
doubleblack=singleblack)
..(c):Ifsiblingisred,performarotationtomoveoldsiblingup,recolortheoldsiblingandparent.The
newsiblingisalwaysblack(Seethebelowdiagram).Thismainlyconvertsthetreetoblacksiblingcase(by
rotation)andleadstocase(a)or(b).Thiscasecanbedividedintwosubcases.
..(i)LeftCase(sisleftchildofitsparent).Thisismirrorofrightrightcaseshowninbelowdiagram.
Werightrotatetheparentp.
..(iii)RightCase(sisrightchildofitsparent).Weleftrotatetheparentp.
3.3)Ifuisroot,makeitsingleblackandreturn(Blackheightofcompletetreereducesby1).
==================================================================================
ConstructatreefromInorderand
Levelordertraversals
GiveninorderandlevelordertraversalsofaBinaryTree,constructtheBinaryTree.Followingisanexample
toillustratetheproblem.
Input:TwoarraysthatrepresentInorder
andlevelordertraversalsofa
BinaryTree
in[]={4,8,10,12,14,20,22}
level[]={20,8,22,4,12,10,14}
Output:Constructthetreerepresented
bythetwoarrays.
Fortheabovetwoarrays,the
constructedtreeisshownin
thediagramonrightside
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
Thefollowingpostcanbeconsideredasaprerequisiteforthis.
ConstructTreefromgivenInorderandPreordertraversals
Letusconsidertheaboveexample.
in[]={4,8,10,12,14,20,22}
level[]={20,8,22,4,12,10,14}
InaLevelordersequence,thefirstelementistherootofthetree.Soweknow20isrootforgiven
sequences.Bysearching20inInordersequence,wecanfindoutallelementsonleftsideof20areinleft
subtreeandelementsonrightareinrightsubtree.Soweknowbelowstructurenow.
20
/\
/\
{4,8,10,12,14}{22}
Letuscall{4,8,10,12,14}asleftsubarrayinInordertraversaland{22}asrightsubarrayinInordertraversal.
Inlevelordertraversal,keysofleftandrightsubtreesarenotconsecutive.Soweextractallnodesfromlevel
ordertraversalwhichareinleftsubarrayofInordertraversal.Toconstructtheleftsubtreeofroot,werecur
fortheextractedelementsfromlevelordertraversalandleftsubarrayofinordertraversal.Intheabove
example,werecurforfollowingtwoarrays.
//Recurforfollowingarraystoconstructtheleftsubtree
In[]={4,8,10,12,14}
level[]={8,4,12,10,14}
Similarly,werecurforfollowingtwoarraysandconstructtherightsubtree.
//Recurforfollowingarraystoconstructtherightsubtree
In[]={22}
level[]={22}
FollowingisC++implementationoftheaboveapproach.
/* program to construct tree using inorder and levelorder traversals */
#include <iostream>
using namespace std;
return root;
return root;
}
int n = sizeof(in)/sizeof(in[0]);
Node *root = buildTree(in, level, 0, n - 1, n);
return 0;
}
Output:
Inordertraversaloftheconstructedtreeis
481012142022
AnupperboundontimecomplexityofabovemethodisO(n3).Inthemainrecursivefunction,extractNodes()
iscalledwhichtakesO(n2)time.
==================================================================================
Printallnodesatdistancekfroma
givennode
Givenabinarytree,atargetnodeinthebinarytree,andanintegervaluek,printallthenodesthatareat
distancekfromthegiventargetnode.Noparentpointersareavailable.
Considerthetreeshownindiagram
Input:target=pointertonodewithdata8.
root=pointertonodewithdata20.
k=2.
Output:101422
Iftargetis14andkis3,thenoutput
shouldbe"420"
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
Therearetwotypesofnodestobeconsidered.
1)Nodesinthesubtreerootedwithtargetnode.Forexampleifthetargetnodeis8andkis2,thensuch
nodesare10and14.
2)Othernodes,maybeanancestoroftarget,oranodeinsomeothersubtree.Fortargetnode8andkis2,
thenode22comesinthiscategory.
Findingthefirsttypeofnodesiseasytoimplement.Justtraversesubtreesrootedwiththetargetnodeand
decrementkinrecursivecall.Whenthekbecomes0,printthenodecurrentlybeingtraversed(Seethisfor
moredetails).HerewecallthefunctionasprintkdistanceNodeDown().
Howtofindnodesofsecondtype?Fortheoutputnodesnotlyinginthesubtreewiththetargetnodeasthe
root,wemustgothroughallancestors.Foreveryancestor,wefinditsdistancefromtargetnode,letthe
distancebed,nowwegotoothersubtree(iftargetwasfoundinleftsubtree,thenwegotorightsubtreeand
viceversa)oftheancestorandfindallnodesatkddistancefromtheancestor.
FollowingisC++implementationoftheaboveapproach.
#include <iostream>
using namespace std;
{
node *temp = new node;
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
4
20
TimeComplexity:AtfirstlookthetimecomplexitylooksmorethanO(n),butifwetakeacloserlook,wecan
observethatnonodeistraversedmorethantwice.ThereforethetimecomplexityisO(n).
==================================================================================
PrintaBinaryTreeinVertical
Order|Set1
Givenabinarytree,printitvertically.Thefollowingexampleillustratesverticalordertraversal.
1
/\
23
/\/\
4567
\\
89
Theoutputofprintthistreeverticallywillbe:
4
2
156
38
7
9
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
Theideaistotraversethetreeonceandgettheminimumandmaximumhorizontaldistancewithrespectto
root.Forthetreeshownabove,minimumdistanceis2(fornodewithvalue4)andmaximumdistanceis3
(Fornodewithvalue9).
Oncewehavemaximumandminimumdistancesfromroot,weiterateforeachverticallineatdistance
minimumtomaximumfromroot,andforeachverticallinetraversethetreeandprintthenodeswhichlieon
thatverticalline.
Algorithm:
//min>Minimumhorizontaldistancefromroot
//max>Maximumhorizontaldistancefromroot
//hd>Horizontaldistanceofcurrentnodefromroot
findMinMax(tree,min,max,hd)
iftreeisNULLthenreturn
ifhdislessthanminthen
min=hd
elseifhdisgreaterthanmaxthen
*max=hd
findMinMax(tree>left,min,max,hd1)
findMinMax(tree>right,min,max,hd+1)
printVerticalLine(tree,line_no,hd)
iftreeisNULLthenreturn
ifhdisequaltoline_no,then
print(tree>data)
printVerticalLine(tree>left,line_no,hd1)
printVerticalLine(tree>right,line_no,hd+1)
Implementation:
FollowingisC++implementationofabovealgorithm.
#include <iostream>
using namespace std;
}
}
return 0;
}
Output:
Verticalordertraversalis
4
2
156
38
7
9
TimeComplexity:TimecomplexityofabovealgorithmisO(w*n)wherewiswidthofBinaryTreeandnis
numberofnodesinBinaryTree.Inworstcase,thevalueofwcanbeO(n)(consideracompletetreefor
example)andtimecomplexitycanbecomeO(n2).
=======================================================================
IntervalTree
Considerasituationwherewehaveasetofintervalsandweneedfollowingoperationstobeimplemented
efficiently.
1)Addaninterval
2)Removeaninterval
3)Givenanintervalx,findifxoverlapswithanyoftheexistingintervals.
IntervalTree:TheideaistoaugmentaselfbalancingBinarySearchTree(BST)likeRedBlackTree,AVL
Tree,etctomaintainsetofintervalssothatalloperationscanbedoneinO(Logn)time.
EverynodeofIntervalTreestoresfollowinginformation.
a)i:Anintervalwhichisrepresentedasapair[low,high]
b)max:Maximumhighvalueinsubtreerootedwiththisnode.
ThelowvalueofanintervalisusedaskeytomaintainorderinBST.Theinsertanddeleteoperationsare
sameasinsertanddeleteinselfbalancingBSTused.
Themainoperationistosearchforanoverlappinginterval.Followingisalgorithmforsearchingan
overlappingintervalxinanIntervaltreerootedwithroot.
IntervaloverlappingIntervalSearch(root,x)
1)Ifxoverlapswithroot'sinterval,returntheroot'sinterval.
2)Ifleftchildofrootisnotemptyandthemaxinleftchild
isgreaterthanx'slowvalue,recurforleftchild
3)Elserecurforrightchild.
Howdoestheabovealgorithmwork?
Lettheintervaltobesearchedbex.Weneedtoprovethisinforfollowingtwocases.
Case1:Whenwegotorightsubtree,oneofthefollowingmustbetrue.
a)Thereisanoverlapinrightsubtree:Thisisfineasweneedtoreturnoneoverlappinginterval.
b)Thereisnooverlapineithersubtree:WegotorightsubtreeonlywheneitherleftisNULLormaximum
valueinleftissmallerthanx.low.Sotheintervalcannotbepresentinleftsubtree.
Case2:Whenwegotoleftsubtree,oneofthefollowingmustbetrue.
a)Thereisanoverlapinleftsubtree:Thisisfineasweneedtoreturnoneoverlappinginterval.
b)Thereisnooverlapineithersubtree:Thisisthemostimportantpart.Weneedtoconsiderfollowingfacts.
Wewenttoleftsubtreebecausex.low<=maxinleftsubtree
.maxinleftsubtreeisahighofoneoftheintervalsletussay[a,max]inleftsubtree.
.Sincexdoesntoverlapwithanynodeinleftsubtreex.lowmustbesmallerthana.
.AllnodesinBSTareorderedbylowvalue,soallnodesinrightsubtreemusthavelowvaluegreaterthan
a.
.Fromabovetwofacts,wecansayallintervalsinrightsubtreehavelowvaluegreaterthanx.low.Sox
cannotoverlapwithanyintervalinrightsubtree.
ImplementationofIntervalTree:
FollowingisC++implementationofIntervalTree.TheimplementationusesbasicinsertoperationofBSTto
keepthingssimple.IdeallyitshouldbeinsertionofAVLTreeorinsertionofRedBlackTree.Deletionfrom
BSTisleftasanexercise.
#include <iostream>
using namespace std;
return root;
}
inorder(root->left);
cout << "[" << root->i->low << ", " << root->i->high << "]"
<< " max = " << root->max << endl;
inorder(root->right);
}
cout << "\nSearching for interval [" << x.low << "," << x.high << "]";
Interval *res = overlapSearch(root, x);
if (res == NULL)
cout << "\nNo Overlapping Interval";
else
cout << "\nOverlaps with [" << res->low << ", " << res->high << "]";
return 0;
}
Output:
InordertraversalofconstructedIntervalTreeis
[5,20]max=20
[10,30]max=30
[12,15]max=15
[15,20]max=40
[17,19]max=40
[30,40]max=40
Searchingforinterval[6,7]
Overlapswith[5,20]
ApplicationsofIntervalTree:
Intervaltreeismainlyageometricdatastructureandoftenusedforwindowingqueries,forinstance,tofind
allroadsonacomputerizedmapinsidearectangularviewport,ortofindallvisibleelementsinsidea
threedimensionalscene(SourceWiki).
IntervalTreevsSegmentTree
Bothsegmentandintervaltreesstoreintervals.Segmenttreeismainlyoptimizedforqueriesforagiven
point,andintervaltreesaremainlyoptimizedforoverlappingqueriesforagiveninterval.
=======================================================================
CheckifagivenBinaryTreeis
heightbalancedlikeaRedBlack
Tree
InaRedBlackTree,themaximumheightofanodeisatmosttwicetheminimumheight(Thefour
RedBlacktreepropertiesmakesurethisisalwaysfollowed).GivenaBinarySearchTree,weneedtocheck
forfollowingproperty.
Foreverynode,lengthofthelongestleaftonodepathhasnotmorethantwicethenodesonshortestpath
fromnodetoleaf.
1240
\/\
1410100
\/\
1660150
CannotbeaRedBlackTreeItcanbeRedBlackTree
withanycolorassignment
Maxheightof12is1
Minheightof12is3
10
/\
5100
/\
50150
/
40
ItcanalsobeRedBlackTree
ExpectedtimecomplexityisO(n).Thetreeshouldbetraversedatmostonceinthesolution.
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
Foreverynode,weneedtogetthemaximumandminimumheightsandcomparethem.Theideaisto
traversethetreeandforeverynodecheckifitsbalanced.Weneedtowritearecursivefunctionthatreturns
threethings,abooleanvaluetoindicatethetreeisbalancedornot,minimumheightandmaximumheight.
Toreturnmultiplevalues,wecaneitheruseastructureorpassvariablesbyreference.Wehavepassed
maxhandminhbyreferencesothatthevaluescanbeusedinparentcalls.
/* Program to check if a given Binary Tree is balanced like a Red-Black Tree */
#include <iostream>
using namespace std;
struct Node
{
int key;
Node *left, *right;
};
int lmxh, lmnh; // To store max and min heights of left subtree
int rmxh, rmnh; // To store max and min heights of right subtree
// Set the max and min heights of this node for the parent call
maxh = max(lmxh, rmxh) + 1;
minh = min(lmnh, rmnh) + 1;
return false;
}
return 0;
}
Output:
Balanced
TimeComplexity:TimeComplexityofabovecodeisO(n)asthecodedoesasimpletreetraversal.
=======================================================================
Printallnodesthatareatdistancek
fromaleafnode
GivenaBinaryTreeandapositiveintegerk,printallnodesthataredistancekfromaleafnode.
Herethemeaningofdistanceisdifferentfrompreviouspost.Herekdistancefromaleafmeansklevels
higherthanaleafnode.ForexampleifkismorethanheightofBinaryTree,thennothingshouldbeprinted.
ExpectedtimecomplexityisO(n)wherenisthenumbernodesinthegivenBinaryTree.
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
Theideaistotraversethetree.Keepstoringallancestorstillwehitaleafnode.Whenwereachaleafnode,
weprinttheancestoratdistancek.Wealsoneedtokeeptrackofnodesthatarealreadyprintedasoutput.
Forthatweuseabooleanarrayvisited[].
/* Program to print all nodes which are at distance k from a leaf */
#include <iostream>
using namespace std;
#define MAX_HEIGHT 10000
struct Node
{
int key;
Node *left, *right;
};
/* This function prints all nodes that are distance k from a leaf node
path[] --> Store ancestors of a node
visited[] --> Stores true if a node is printed as output. A node may be k
distance away from many leaves, we want to print it once */
void kDistantFromLeafUtil(Node* node, int path[], bool visited[],
int pathLen, int k)
{
// Base case
if (node==NULL) return;
/* Given a binary tree and a nuber k, print all nodes that are k
distant from a leaf*/
void printKDistantfromLeaf(Node* node, int k)
{
int path[MAX_HEIGHT];
bool visited[MAX_HEIGHT] = {false};
return 0;
}
Output:
Nodesatdistance2are:31
TimeComplexity:TimeComplexityofabovecodeisO(n)asthecodedoesasimpletreetraversal.
======================================================================
Finddistancebetweentwogivenkeys
ofaBinaryTree
Findthedistancebetweentwokeysinabinarytree,noparentpointersaregiven.Distancebetweentwo
nodesistheminimumnumberofedgestobetraversedtoreachonenodefromother.
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
Thedistancebetweentwonodescanbeobtainedintermsoflowestcommonancestor.Followingisthe
formula.
Dist(n1,n2)=Dist(root,n1)+Dist(root,n2)2*Dist(root,lca)
'n1'and'n2'arethetwogivenkeys
'root'isrootofgivenBinaryTree.
'lca'islowestcommonancestorofn1andn2
Dist(n1,n2)isthedistancebetweenn1andn2.
FollowingisC++implementationofaboveapproach.Theimplementationisadoptedfromlastcodeprovided
inLowestCommonAncestorPost.
/* Program to find distance between n1 and n2 using one traversal */
#include <iostream>
using namespace std;
// This function returns pointer to LCA of two given values n1 and n2.
// It also sets d1, d2 and dist if one key is not ancestor of other
// d1 --> To store distance of n1 from root
// d2 --> To store distance of n2 from root
// lvl --> Level (or distance from root) of current node
// dist --> To store distance between n1 and n2
Node *findDistUtil(Node* root, int n1, int n2, int &d1, int &d2,
int &dist, int lvl)
{
// Base case
if (root == NULL) return NULL;
return -1;
}
root->right->right = newNode(7);
root->right->left->right = newNode(8);
cout << "Dist(4, 5) = " << findDistance(root, 4, 5);
cout << "\nDist(4, 6) = " << findDistance(root, 4, 6);
cout << "\nDist(3, 4) = " << findDistance(root, 3, 4);
cout << "\nDist(2, 4) = " << findDistance(root, 2, 4);
cout << "\nDist(8, 5) = " << findDistance(root, 8, 5);
return 0;
}
Output:
Dist(4,5)=2
Dist(4,6)=4
Dist(3,4)=3
Dist(2,4)=1
Dist(8,5)=5
TimeComplexity:TimecomplexityoftheabovesolutionisO(n)asthemethoddoesasingletreetraversal.
=======================================================================
LowestCommonAncestorina
BinaryTree|Set1
Givenabinarytree(notabinarysearchtree)andtwovaluessayn1andn2,writeaprogramtofindtheleast
commonancestor.
FollowingisdefinitionofLCAfromWikipedia:
LetTbearootedtree.Thelowestcommonancestorbetweentwonodesn1andn2isdefinedasthelowest
nodeinTthathasbothn1andn2asdescendants(whereweallowanodetobeadescendantofitself).
TheLCAofn1andn2inTisthesharedancestorofn1andn2thatislocatedfarthestfromtheroot.
Computationoflowestcommonancestorsmaybeuseful,forinstance,aspartofaprocedurefor
determiningthedistancebetweenpairsofnodesinatree:thedistancefromn1ton2canbecomputedas
thedistancefromtherootton1,plusthedistancefromtherootton2,minustwicethedistancefromtheroot
totheirlowestcommonancestor.(SourceWiki)
WehavediscussedanefficientsolutiontofindLCAinBinarySearchTree.InBinarySearchTree,using
BSTproperties,wecanfindLCAinO(h)timewherehisheightoftree.Suchanimplementationisnot
possibleinBinaryTreeaskeysBinaryTreenodesdontfollowanyorder.Followingaredifferentapproaches
tofindLCAinBinaryTree.
Method1(ByStoringrootton1androotton2paths):
FollowingissimpleO(n)algorithmtofindLCAofn1andn2.
1)Findpathfromrootton1andstoreitinavectororarray.
2)Findpathfromrootton2andstoreitinanothervectororarray.
3)Traversebothpathstillthevaluesinarraysaresame.Returnthecommonelementjustbeforethe
mismatch.
FollowingisC++implementationofabovealgorithm.
// A O(n) solution to find LCA of two given values n1 and n2
#include <iostream>
#include <vector>
using namespace std;
// Utility function creates a new binary tree node with given key
Node * newNode(int k)
{
// Finds the path from root node to given root of the tree, Stores the
// path in a vector path[], returns true if path exists otherwise false
bool findPath(Node *root, vector<int> &path, int k)
{
// base case
if (root == NULL) return false;
// Returns LCA if node n1, n2 are present in the given binary tree,
// otherwise return -1
int findLCA(Node *root, int n1, int n2)
{
// to store paths to n1 and n2 from the root
LCA(4,5)=2
LCA(4,6)=1
LCA(3,4)=1
LCA(2,4)=2
TimeComplexity:TimecomplexityoftheabovesolutionisO(n).Thetreeistraversedtwice,andthenpath
arraysarecompared.
ThankstoRaviChandraEnagantiforsuggestingtheinitialsolutionbasedonthismethod.
Method2(UsingSingleTraversal)
Themethod1findsLCAinO(n)time,butrequiresthreetreetraversalsplusextraspacesforpatharrays.If
weassumethatthekeysn1andn2arepresentinBinaryTree,wecanfindLCAusingsingletraversalof
BinaryTreeandwithoutextrastorageforpatharrays.
Theideaistotraversethetreestartingfromroot.Ifanyofthegivenkeys(n1andn2)matcheswithroot,
thenrootisLCA(assumingthatbothkeysarepresent).Ifrootdoesntmatchwithanyofthekeys,werecur
forleftandrightsubtree.Thenodewhichhasonekeypresentinitsleftsubtreeandtheotherkeypresentin
rightsubtreeistheLCA.Ifbothkeyslieinleftsubtree,thenleftsubtreehasLCAalso,otherwiseLCAliesin
rightsubtree.
/* Program to find LCA of n1 and n2 using one traversal of Binary Tree */
#include <iostream>
using namespace std;
// This function returns pointer to LCA of two given values n1 and n2.
// This function assumes that n1 and n2 are present in Binary Tree
struct Node *findLCA(struct Node* root, int n1, int n2)
{
// Base case
if (root == NULL) return NULL;
LCA(4,5)=2
LCA(4,6)=1
LCA(3,4)=1
LCA(2,4)=2
ThankstoAtulSinghforsuggestingthissolution.
TimeComplexity:TimecomplexityoftheabovesolutionisO(n)asthemethoddoesasimpletreetraversal
inbottomupfashion.
NotethattheabovemethodassumesthatkeysarepresentinBinaryTree.Ifonekeyispresentandotheris
absent,thenitreturnsthepresentkeyasLCA(IdeallyshouldhavereturnedNULL).
Wecanextendthismethodtohandleallcasesbypassingtwobooleanvariablesv1andv2.v1issetastrue
whenn1ispresentintreeandv2issetastrueifn2ispresentintree.
/* Program to find LCA of n1 and n2 using one traversal of Binary Tree.
It handles all cases even when n1 or n2 is not there in Binary Tree */
#include <iostream>
using namespace std;
// This function returns pointer to LCA of two given values n1 and n2.
// Base Case
if (root == NULL)
return false;
// This function returns LCA of n1 and n2 only if both n1 and n2 are present
// in tree, otherwise returns NULL;
Node *findLCA(Node *root, int n1, int n2)
{
// Initialize n1 and n2 as not visited
bool v1 = false, v2 = false;
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
Node *lca = findLCA(root, 4, 5);
if (lca != NULL)
cout << "LCA(4, 5) = " << lca->key;
else
cout << "Keys are not present ";
return 0;
}
Output:
LCA(4,5)=2
Keysarenotpresent
=======================================================================
Printallnodesthatdonthave
sibling
GivenaBinaryTree,printallnodesthatdonthaveasibling(asiblingisanodethathassameparent.Ina
BinaryTree,therecanbeatmostonesibling).Rootshouldnotbeprintedasrootcannothaveasibling.
Forexample,theoutputshouldbe456forthefollowingtree.
Westronglyrecommendtominimizethebrowserandtrythisyourselffirst.
Thisisatypicaltreetraversalquestion.Westartfromrootandcheckifthenodehasonechild,ifyesthen
printtheonlychildofthatnode.Ifnodehasbothchildren,thenrecurforboththechildren.
/* Program to find singles in a given binary tree */
#include <iostream>
using namespace std;
456
TimeComplexityofabovecodeisO(n)asthecodedoesasimpletreetraversal.
=======================================================================
ConvertagivenBinaryTreeto
DoublyLinkedList|Set3
GivenaBinaryTree(BT),convertittoaDoublyLinkedList(DLL)InPlace.Theleftandrightpointersin
nodesaretobeusedaspreviousandnextpointersrespectivelyinconvertedDLL.Theorderofnodesin
DLLmustbesameasInorderofthegivenBinaryTree.ThefirstnodeofInordertraversal(leftmostnodein
BT)mustbeheadnodeoftheDLL.
Followingtwodifferentsolutionshavebeendiscussedforthisproblem.
ConvertagivenBinaryTreetoDoublyLinkedList|Set1
ConvertagivenBinaryTreetoDoublyLinkedList|Set2
Inthispost,athirdsolutionisdiscussedwhichseemstobethesimplestofall.Theideaistodoinorder
traversalofthebinarytree.Whiledoinginordertraversal,keeptrackofthepreviouslyvisitednodeina
variablesayprev.Foreveryvisitednode,makeitnextofprevandpreviousofthisnodeasprev.
Thankstorahul,wishallandallotherreadersfortheirusefulcommentsontheabovetwoposts.
FollowingisC++implementationofthissolution.
// A C++ program for in-place conversion of Binary Tree to DLL
#include <iostream>
using namespace std;
/* A binary tree node has data, and left and right pointers */
struct node
{
int data;
node* left;
node* right;
};
= newNode(10);
root->left
= newNode(12);
root->right
= newNode(15);
root->left->left = newNode(25);
root->left->right = newNode(30);
root->right->left = newNode(36);
// Convert to DLL
node *head = NULL;
BinaryTree2DoubleLinkedList(root, &head);
return 0;
}
Output:
251230103615
Notethatuseofstaticvariableslikeaboveisnotarecommendedpractice(wehaveusedstaticfor
simplicity).Imagineasituationwheresamefunctioniscalledfortwoormoretrees,theoldvalueofprev
wouldbeusedinnextcallforadifferenttree.Toavoidsuchproblems,wecanusedoublepointeror
referencetoapointer.
TimeComplexity:Theaboveprogramdoesasimpleinordertraversal,sotimecomplexityisO(n)wherenis
thenumberofnodesingivenbinarytree.
=======================================================================
RedBlackTree|Set2(Insert)
Inthepreviouspost,wediscussedintroductiontoRedBlackTrees.Inthispost,insertionisdiscussed.
InAVLtreeinsertion,weusedrotationasatooltodobalancingafterinsertioncausedimbalance.In
RedBlacktree,weusetwotoolstodobalancing.
1)Recoloring
2)Rotation
Wetryrecoloringfirst,ifrecoloringdoesntwork,thenwegoforrotation.Followingisdetailedalgorithm.The
algorithmshasmainlytwocasesdependinguponthecolorofuncle.Ifuncleisred,wedorecoloring.Ifuncle
isblack,wedorotationsand/orrecoloring.
ColorofaNULLnodeisconsideredasBLACK.
Letxbethenewlyinsertednode.
1)PerformstandardBSTinsertionandmakethecolorofnewlyinsertednodesasRED.
2)DofollowingifcolorofxsparentisnotBLACKorxisnotroot.
.a)IfxsuncleisRED(Grandparentmusthavebeenblackfromproperty4)
..(i)ChangecolorofparentanduncleasBLACK.
..(ii)colorofgrandparentasRED.
..(iii)Changex=xsgrandparent,repeatsteps2and3fornewx.
.b)IfxsuncleisBLACK,thentherecanbefourconfigurationsforx,xsparent(p)andxsgrandparent
(g)(ThisissimilartoAVLTree)
..i)LeftLeftCase(pisleftchildofgandxisleftchildofp)
..ii)LeftRightCase(pisleftchildofgandxisrightchildofp)
..iii)RightRightCase(Mirrorofcasea)
..iv)RightLeftCase(Mirrorofcasec)
3)Ifxisroot,changecolorofxasBLACK(Blackheightofcompletetreeincreasesby1).
FollowingareoperationstobeperformedinfoursubcaseswhenuncleisBLACK.
AllfourcaseswhenUncleisBLACK
LeftLeftCase(Seeg,pandx)
LeftRightCase(Seeg,pandx)
RightRightCase(Seeg,pandx)
RightLeftCase(Seeg,pandx)
ExamplesofInsertion
PleasereferCProgramforRedBlackTreeInsertionforcompleteimplementationofabovealgorithm.
=======================================================================
RedBlackTree|Set1(Introduction)
RedBlackTreeisaselfbalancingBinarySearchTree(BST)whereeverynodefollowsfollowingrules.
1)Everynodehasacoloreitherredorblack.
2)Rootoftreeisalwaysblack.
3)Therearenotwoadjacentrednodes(Arednodecannothavearedparentorredchild).
4)EverypathfromroottoaNULLnodehassamenumberofblacknodes.
WhyRedBlackTrees?
MostoftheBSToperations(e.g.,search,max,min,insert,delete..etc)takeO(h)timewherehistheheight
oftheBST.ThecostoftheseoperationsmaybecomeO(n)foraskewedBinarytree.Ifwemakesurethat
heightofthetreeremainsO(Logn)aftereveryinsertionanddeletion,thenwecanguaranteeanupper
boundofO(Logn)foralltheseoperations.TheheightofaRedBlacktreeisalwaysO(Logn)wherenisthe
numberofnodesinthetree.
ComparisonwithAVLTree
TheAVLtreesaremorebalancedcomparedtoRedBlackTrees,buttheymaycausemorerotationsduring
insertionanddeletion.Soifyourapplicationinvolvesmanyfrequentinsertionsanddeletions,thenRed
Blacktreesshouldbepreferred.Andiftheinsertionsanddeletionsarelessfrequentandsearchismore
frequentoperation,thenAVLtreeshouldbepreferredoverRedBlackTree.
HowdoesaRedBlackTreeensurebalance?
Asimpleexampletounderstandbalancingis,achainof3nodesisnotpossibleinredblacktree.Wecantry
anycombinationofcolorsandseeallofthemviolateRedBlacktreeproperty.
Achainof3nodesisnodesisnotpossibleinRedBlackTrees.
FollowingareNOTRedBlackTrees
303030
/\/\/\
20NIL20NIL20NIL
/\/\/\
10NIL10NIL10NIL
ViolatesViolatesViolates
Property4.Property4Property3
FollowingaredifferentpossibleRedBlackTreeswithabove3keys
2020
/\/\
10301030
/\/\/\/\
NILNILNILNILNILNILNILNIL
Fromtheaboveexamples,wegetsomeideahowRedBlacktreesensurebalance.Followingisan
importantfactaboutbalancinginRedBlackTrees.
EveryRedBlackTreewithnnodeshasheight<=
Thiscanbeprovedusingfollowingfacts:
1)ForageneralBinaryTree,letkbetheminimumnumberofnodesonallroottoNULLpaths,thenn>=2k
1(Ex.Ifkis3,thennisatleast7).Thisexpressioncanalsobewrittenask<=
2)Fromproperty4ofRedBlacktreesandaboveclaim,wecansayinaRedBlackTreewithnnodes,there
isaroottoleafpathwithatmost
blacknodes.
3)Fromproperty3ofRedBlacktrees,wecanclaimthatthenumberblacknodesinaRedBlacktreeisat
least
wherenistotalnumberofnodes.
Fromabove2points,wecanconcludethefactthatRedBlackTreewithnnodeshasheight<=
Inthispost,weintroducedRedBlacktreesanddiscussedhowbalanceisensured.Thehardpartisto
maintainbalancewhenkeysareaddedandremoved.Wewillsoonbediscussinginsertionanddeletion
operationsincomingpostsonRedBlacktree.
Exercise:
1)IsitpossibletohaveallblacknodesinaRedBlacktree?
2)DrawaRedBlackTreethatisnotanAVLtreestructurewise?
InsertionandDeletion
RedBlackTreeInsertion
RedBlackTreeDeletion
References:
IntroductiontoAlgorithms3rdEditionbyCliffordStein,ThomasH.Cormen,CharlesE.Leiserson,RonaldL.
Rivest
http://en.wikipedia.org/wiki/Red%E2%80%93black_tree
VideoLectureonRedBlackTreebyTimRoughgarden
MITVideoLectureonRedBlackTree
MITLectureNotesonRedBlackTree
=======================================================================
Sumofallthenumbersthatare
formedfromroottoleafpaths
Givenabinarytree,whereeverynodevalueisaDigitfrom19.Findthesumofallthenumberswhichare
formedfromroottoleafpaths.
ForexampleconsiderthefollowingBinaryTree.
6
/\
35
/\\
254
/\
74
Thereare4leaves,hence4roottoleafpaths:
PathNumber
6>3>2632
6>3>5>76357
6>3>5>46354
6>5>4654
Answer=632+6357+6354+654=13997
Westronglyrecommendyoutominimizethebrowserandtrythisyourselffirst.
Theideaistodoapreordertraversalofthetree.Inthepreordertraversal,keeptrackofthevaluecalculated
tillthecurrentnode,letthisvaluebeval.Foreverynode,weupdatethevalasval*10plusnodesdata.
// C program to find sum of all paths from root to leaves
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *left, *right;
};
// Returns sum of all root to leaf paths. The first parameter is root
// of current subtree, the second parameter is value of the number formed
// by nodes from root to this node
int treePathsSumUtil(struct node *root, int val)
{
// Base case
if (root == NULL) return 0;
// Update val
val = (val*10 + root->data);
= newNode(3);
root->right
= newNode(5);
root->right->right= newNode(7);
root->left->left = newNode(2);
root->left->right = newNode(5);
root->right->right = newNode(4);
root->left->right->left = newNode(7);
root->left->right->right = newNode(4);
printf("Sum of all paths is %d", treePathsSum(root));
return 0;
}
Output:
Sumofallpathsis13997
TimeComplexity:Theabovecodeisasimplepreordertraversalcodewhichvisitseveryexactlyonce.
Therefore,thetimecomplexityisO(n)wherenisthenumberofnodesinthegivenbinarytree.
=======================================================================
SplayTree|Set2(Insert)
Itisrecommendedtoreferfollowingpostasprerequisiteofthispost.
SplayTree|Set1(Search)
Asdiscussedinthepreviouspost,Splaytreeisaselfbalancingdatastructurewherethelastaccessedkey
isalwaysatroot.TheinsertoperationissimilartoBinarySearchTreeinsertwithadditionalstepstomake
surethatthenewlyinsertedkeybecomesthenewroot.
Followingaredifferentcasestoinsertakeykinsplaytree.
1)RootisNULL:Wesimplyallocateanewnodeandreturnitasroot.
2)Splaythegivenkeyk.Ifkisalreadypresent,thenitbecomesthenewroot.Ifnotpresent,thenlast
accessedleafnodebecomesthenewroot.
3)Ifnewrootskeyissameask,dontdoanythingaskisalreadypresent.
4)Elseallocatememoryfornewnodeandcomparerootskeywithk.
.4.a)Ifkissmallerthanrootskey,makerootasrightchildofnewnode,copyleftchildofrootasleft
childofnewnodeandmakeleftchildofrootasNULL.
.4.b)Ifkisgreaterthanrootskey,makerootasleftchildofnewnode,copyrightchildofrootasright
childofnewnodeandmakerightchildofrootasNULL.
5)Returnnewnodeasnewrootoftree.
Example:
100[20]25
/\\/\
50200502050
/insert(25)/\insert(25)/\
40======>30100========>30100
/1.Splay(25)\\2.insert25\\
304020040200
/
[20]
// This code is adopted from
http://algs4.cs.princeton.edu/33balanced/SplayBST.java.html
#include<stdio.h>
#include<stdlib.h>
/* Helper function that allocates a new node with the given key and
NULL left and right pointers. */
struct node* newNode(int key)
{
struct node* node = (struct node*)malloc(sizeof(struct node));
node->key
= key;
if (root->right->left != NULL)
root->right = rightRotate(root->right);
}
else if (root->right->key < key)// Zag-Zag (Right Right)
{
// Bring the key as root of right-right and do first rotation
root->right->right = splay(root->right->right, key);
root = leftRotate(root);
}
preOrder(root);
return 0;
}
Output:
PreordertraversalofthemodifiedSplaytreeis
2520503040100200
=======================================================================
SplayTree|Set1(Search)
TheworstcasetimecomplexityofBinarySearchTree(BST)operationslikesearch,delete,insertisO(n).
Theworstcaseoccurswhenthetreeisskewed.WecangettheworstcasetimecomplexityasO(Logn)with
AVLandRedBlackTrees.
CanwedobetterthanAVLorRedBlacktreesinpracticalsituations?
LikeAVLandRedBlackTrees,SplaytreeisalsoselfbalancingBST.Themainideaofsplaytreeistobring
therecentlyaccesseditemtorootofthetree,thismakestherecentlysearcheditemtobeaccessibleinO(1)
timeifaccessedagain.Theideaistouselocalityofreference(Inatypicalapplication,80%oftheaccess
areto20%oftheitems).Imagineasituationwherewehavemillionsorbillionsofkeysandonlyfewofthem
areaccessedfrequently,whichisverylikelyinmanypracticalapplications.
AllsplaytreeoperationsruninO(logn)timeonaverage,wherenisthenumberofentriesinthetree.Any
singleoperationcantakeTheta(n)timeintheworstcase.
SearchOperation
ThesearchoperationinSplaytreedoesthestandardBSTsearch,inadditiontosearch,italsosplays(move
anodetotheroot).Ifthesearchissuccessful,thenthenodethatisfoundissplayedandbecomesthenew
root.ElsethelastnodeaccessedpriortoreachingtheNULLissplayedandbecomesthenewroot.
Therearefollowingcasesforthenodebeingaccessed.
1)NodeisrootWesimplyreturntheroot,dontdoanythingelseastheaccessednodeisalreadyroot.
2)Zig:Nodeischildofroot(thenodehasnograndparent).Nodeiseitheraleftchildofroot(wedoaright
rotation)ornodeisarightchildofitsparent(wedoaleftrotation).
T1,T2andT3aresubtreesofthetreerootedwithy(onleftside)orx(onrightside)
yx
/\Zig(RightRotation)/\
xT3>T1y
/\</\
T1T2Zag(LeftRotation)T2T3
3)Nodehasbothparentandgrandparent.Therecanbefollowingsubcases.
........3.a)ZigZigandZagZagNodeisleftchildofparentandparentisalsoleftchildofgrandparent(Two
rightrotations)ORnodeisrightchildofitsparentandparentisalsorightchildofgrandparent(TwoLeft
Rotations).
ZigZig(LeftLeftCase):
GPX
/\/\/\
PT4rightRotate(G)XGrightRotate(P)T1P
/\============>/\/\============>/\
XT3T1T2T3T4T2G
/\/\
T1T2T3T4
ZagZag(RightRightCase):
GPX
/\/\/\
T1PleftRotate(G)GXleftRotate(P)PT4
/\============>/\/\============>/\
T2XT1T2T3T4GT3
/\/\
T3T4T1T2
........3.b)ZigZagandZagZigNodeisleftchildofparentandparentisrightchildofgrandparent(Left
Rotationfollowedbyrightrotation)ORnodeisrightchildofitsparentandparentisleftchildofgrandparent
(RightRotationfollowedbyleftrotation).
ZigZag(LeftRightCase):
GGX
/\/\/\
PT4leftRotate(P)XT4rightRotate(G)PG
/\============>/\============>/\/\
T1XPT3T1T2T3T4
/\/\
T2T3T1T2
ZagZig(RightLeftCase):
GGX
/\/\/\
T1PrightRotate(P)T1XleftRotate(P)GP
/\=============>/\============>/\/\
XT4T2PT1T2T3T4
/\/\
T2T3T3T4
Example:
100100[20]
/\/\\
502005020050
/search(20)/search(20)/\
40======>[20]========>30100
/1.ZigZig\2.ZigZig\\
30at4030at10040200
/\
[20]40
Theimportantthingtonoteis,thesearchorsplayoperationnotonlybringsthesearchedkeytoroot,but
alsobalancestheBST.Forexampleinabovecase,heightofBSTisreducedby1.
Implementation:
// The code is adopted from http://goo.gl/SDH9hH
#include<stdio.h>
#include<stdlib.h>
/* Helper function that allocates a new node with the given key and
NULL left and right pointers. */
struct node* newNode(int key)
{
struct node* node = (struct node*)malloc(sizeof(struct node));
node->key
= key;
return (node);
}
}
else if (root->right->key < key)// Zag-Zag (Right Right)
{
// Bring the key as root of right-right and do first rotation
root->right->right = splay(root->right->right, key);
root = leftRotate(root);
}
// The search function for Splay tree. Note that this function
// returns the new root of Splay Tree. If key is present in tree
// then, it is moved to root.
struct node *search(struct node *root, int key)
{
return splay(root, key);
}
root->left = newNode(50);
root->right = newNode(200);
root->left->left = newNode(40);
root->left->left->left = newNode(30);
root->left->left->left->left = newNode(20);
PreordertraversalofthemodifiedSplaytreeis
20503040100200
Summary
1)Splaytreeshaveexcellentlocalityproperties.Frequentlyaccesseditemsareeasytofind.Infrequent
itemsareoutofway.
2)AllsplaytreeoperationstakeO(Logn)timeonaverage.Splaytreescanberigorouslyshowntorunin
O(logn)averagetimeperoperation,overanysequenceofoperations(assumingwestartfromanempty
tree)
3)SplaytreesaresimplercomparedtoAVLandRedBlackTreesasnoextrafieldisrequiredineverytree
node.
4)UnlikeAVLtree,asplaytreecanchangeevenwithreadonlyoperationslikesearch.
ApplicationsofSplayTrees
Splaytreeshavebecomethemostwidelyusedbasicdatastructureinventedinthelast30years,because
they'rethefastesttypeofbalancedsearchtreeformanyapplications.
SplaytreesareusedinWindowsNT(inthevirtualmemory,networking,andfilesystemcode),thegcc
compilerandGNUC++library,thesedstringeditor,ForeSystemsnetworkrouters,themostpopular
implementationofUnixmalloc,Linuxloadablekernelmodules,andinmuchothersoftware(Source:
http://www.cs.berkeley.edu/~jrs/61b/lec/36)
=======================================================================
Findnextrightnodeofagivenkey
GivenaBinarytreeandakeyinthebinarytree,findthenoderighttothegivenkey.Ifthereisnonodeon
rightside,thenreturnNULL.ExpectedtimecomplexityisO(n)wherenisthenumberofnodesinthegiven
binarytree.
Forexample,considerthefollowingBinaryTree.Outputfor2is6,outputfor4is5.Outputfor10,6and5is
NULL.
10
/\
26
/\\
845
Westronglyrecommendyoutominimizethebrowserandtrythisyourselffirst.
Solution:TheideaistodolevelordertraversalofgivenBinaryTree.Whenwefindthegivenkey,wejust
checkifthenextnodeinlevelordertraversalisofsamelevel,ifyes,wereturnthenextnode,otherwise
returnNULL.
/* Program to find next right of a given key */
#include <iostream>
#include <queue>
using namespace std;
if (node->right != NULL)
{
qn.push(node->right);
ql.push(level+1);
}
}
root->right->right = newNode(5);
root->left->left = newNode(8);
root->left->right = newNode(4);
test(root, 10);
test(root, 2);
test(root, 6);
test(root, 5);
test(root, 8);
test(root, 4);
return 0;
}
Output:
Nonextrightnodefoundfor10
NextRightof2is6
Nonextrightnodefoundfor6
Nonextrightnodefoundfor5
NextRightof8is4
NextRightof4is5
TimeComplexity:TheabovecodeisasimpleBFStraversalcodewhichvisitseveryenqueueand
dequeuesanodeatmostonce.Therefore,thetimecomplexityisO(n)wherenisthenumberofnodesin
thegivenbinarytree.
=======================================================================
Deepestleftleafnodeinabinarytree
GivenaBinaryTree,findthedeepestleafnodethatisleftchildofitsparent.Forexample,considerthe
followingtree.Thedeepestleftleafnodeisthenodewithvalue9.
1
/\
23
//\
456
\\
78
/\
910
Westronglyrecommendyoutominimizethebrowserandtrythisyourselffirst.
Theideaistorecursivelytraversethegivenbinarytreeandwhiletraversing,maintainlevelwhichwillstore
thecurrentnodeslevelinthetree.Ifcurrentnodeisleftleaf,thencheckifitslevelismorethanthelevelof
deepestleftleafseensofar.Iflevelismorethenupdatetheresult.Ifcurrentnodeisnotleaf,then
recursivelyfindmaximumdepthinleftandrightsubtrees,andreturnmaximumofthetwodepths.Thanksto
Coder011forsuggestingthisapproach.
// A C++ program to find the deepest left leaf in a given binary tree
#include <stdio.h>
#include <iostream>
using namespace std;
struct Node
{
int val;
struct Node *left, *right;
};
return;
// Update result if this node is left leaf and its level is more
// than the maxl level of the current result
if (isLeft && !root->left && !root->right && lvl > *maxlvl)
{
*resPtr = root;
*maxlvl = lvl;
return;
}
root->right->right->right->right = newNode(10);
return 0;
}
Output:
Thedeepestleftchildis9
TimeComplexity:Thefunctiondoesasimpletraversalofthetree,sothecomplexityisO(n).
=======================================================================
ExtractLeavesofaBinaryTreeina
DoublyLinkedList
GivenaBinaryTree,extractallleavesofitinaDoublyLinkedList(DLL).NotethattheDLLneedtobe
createdinplace.AssumethatthenodestructureofDLLandBinaryTreeissame,onlythemeaningofleft
andrightpointersaredifferent.InDLL,leftmeanspreviouspointerandrightmeansnextpointer.
Letthefollowingbeinputbinarytree
1
/\
23
/\\
456
/\/\
78910
Output:
DoublyLinkedList
7<>8<>5<>9<>10
ModifiedTree:
1
/\
23
/\
46
Westronglyrecommendyoutominimizethebrowserandtrythisyourselffirst.
Weneedtotraverseallleavesandconnectthembychangingtheirleftandrightpointers.Wealsoneedto
removethemfromBinaryTreebychangingleftorrightpointersinparentnodes.Therecanbemanyways
tosolvethis.Inthefollowingimplementation,weaddleavesatthebeginningofcurrentlinkedlistand
updateheadofthelistusingpointertoheadpointer.Sinceweinsertatthebeginning,weneedtoprocess
leavesinreverseorder.Forreverseorder,wefirsttraversetherightsubtreethentheleftsubtree.Weuse
returnvaluestoupdateleftorrightpointersinparentnodes.
// C program to extract leaves of a Binary Tree in a Doubly Linked List
#include <stdio.h>
#include <stdlib.h>
// Main function which extracts all leaves from given Binary Tree.
// The function returns new root of Binary Tree (Note that root may change
// if Binary Tree has only one node). The function also sets *head_ref as
// head of doubly linked list. left pointer of tree is used as prev in DLL
// and right pointer is used as next
struct Node* extractLeafList(struct Node *root, struct Node **head_ref)
{
// Base cases
if (root == NULL) return NULL;
return root;
}
print(root->right);
}
}
InorderTrvaersalofgivenTreeis:
74825139610
ExtractedDoubleLinkedlistis:
785910
Inordertraversalofmodifiedtreeis:
42136
TimeComplexity:O(n),thesolutiondoesasingletraversalofgivenBinaryTree.
=======================================================================
Removeallnodeswhichdontliein
anypathwithsum>=k
Givenabinarytree,acompletepathisdefinedasapathfromroottoaleaf.Thesumofallnodesonthat
pathisdefinedasthesumofthatpath.GivenanumberK,youhavetoremove(prunethetree)allnodes
whichdontlieinanypathwithsum>=k.
Note:Anodecanbepartofmultiplepaths.Sowehavetodeleteitonlyincasewhenallpathsfromithave
sumlessthanK.
ConsiderthefollowingBinaryTree
1
/\
23
/\/\
4567
/\//
891210
/\\
131411
/
15
Forinputk=20,thetreeshouldbechangedtofollowing
(Nodeswithvalues6and8aredeleted)
1
/\
23
/\\
457
\//
91210
/\\
131411
/
15
Forinputk=45,thetreeshouldbechangedtofollowing.
1
/
2
/
4
\
9
\
14
/
15
Westronglyrecommendyoutominimizethebrowserandtrythisyourselffirst.
Theideaistotraversethetreeanddeletenodesinbottomupmanner.Whiletraversingthetree,recursively
calculatethesumofnodesfromroottoleafnodeofeachpath.Foreachvisitednode,checksthetotal
calculatedsumagainstgivensumk.Ifsumislessthank,thenfree(delete)thatnode(leafnode)and
returnthesumbacktothepreviousnode.Sincethepathisfromroottoleafandnodesaredeletedin
bottomupmanner,anodeisdeletedonlywhenallofitsdescendantsaredeleted.Therefore,whenanode
isdeleted,itmustbealeafinthecurrentBinaryTree.
FollowingisCimplementationoftheaboveapproach.
#include <stdio.h>
#include <stdlib.h>
// A utility function to create a new Binary Tree node with given data
struct Node* newNode(int data)
{
struct Node* node = (struct Node*) malloc(sizeof(struct Node));
node->data = data;
node->left = node->right = NULL;
return node;
}
return root;
}
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
root->left->left->left = newNode(8);
root->left->left->right = newNode(9);
root->left->right->left = newNode(12);
root->right->right->left = newNode(10);
root->right->right->left->right = newNode(11);
root->left->left->right->left = newNode(13);
root->left->left->right->right = newNode(14);
root->left->left->right->right->left = newNode(15);
return 0;
}
Output:
Treebeforetruncation
841391514212516310117
Treeaftertruncation
49151421
TimeComplexity:O(n),thesolutiondoesasingletraversalofgivenBinaryTree.
=======================================================================
Addallgreatervaluestoeverynode
inagivenBST
GivenaBinarySearchTree(BST),modifyitsothatallgreatervaluesinthegivenBSTareaddedtoevery
node.Forexample,considerthefollowingBST.
50
/\
3070
/\/\
20406080
Theabovetreeshouldbemodifiedtofollowing
260
/\
330150
/\/\
35030021080
Westronglyrecommendyoutominimizethebrowserandtrythisyourselffirst.
Asimplemethodforsolvingthisistofindsumofallgreatervaluesforeverynode.Thismethodwouldtake
O(n^2)time.
Wecandoitusingasingletraversal.TheideaistousefollowingBSTproperty.IfwedoreverseInorder
traversalofBST,wegetallnodesindecreasingorder.WedoreverseInordertraversalandkeeptrackof
thesumofallnodesvisitedsofar,weaddthissumtoeverynode.
// C program to add all greater values in every node of BST
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *left, *right;
};
{
inorder(root->left);
printf("%d ", root->data);
inorder(root->right);
}
}
70
/ \/ \
20
40 60
80 */
insert(root, 70);
insert(root, 60);
insert(root, 80);
modifyBST(root);
return 0;
}
Output
35033030026021015080
TimeComplexity:O(n)wherenisnumberofnodesinthegivenBST.
Asasidenote,wecanalsousereverseInordertraversaltofindkthlargestelementinaBST.
=======================================================================
BTree|Set3(Delete)
Itisrecommendedtoreferfollowingpostsasprerequisiteofthispost.
BTree|Set1(Introduction)
BTree|Set2(Insert)
BTreeisatypeofamultiwaysearchtree.So,ifyouarenotfamiliarwithmultiwaysearchtreesingeneral,
itisbettertotakealookatthisvideolecturefromIITDelhi,beforeproceedingfurther.Onceyougetthe
basicsofamultiwaysearchtreeclear,BTreeoperationswillbeeasiertounderstand.
SourceofthefollowingexplanationandalgorithmisIntroductiontoAlgorithms3rdEditionbyCliffordStein,
ThomasH.Cormen,CharlesE.Leiserson,RonaldL.Rivest
Deletionprocess:
DeletionfromaBtreeismorecomplicatedthaninsertion,becausewecandeleteakeyfromanynodenot
justaleafandwhenwedeleteakeyfromaninternalnode,wewillhavetorearrangethenodeschildren.
Asininsertion,wemustmakesurethedeletiondoesntviolatetheBtreeproperties.Justaswehadto
ensurethatanodedidntgettoobigduetoinsertion,wemustensurethatanodedoesntgettoosmall
duringdeletion(exceptthattherootisallowedtohavefewerthantheminimumnumbert1ofkeys).Justas
asimpleinsertionalgorithmmighthavetobackupifanodeonthepathtowherethekeywastobeinserted
wasfull,asimpleapproachtodeletionmighthavetobackupifanode(otherthantheroot)alongthepathto
wherethekeyistobedeletedhastheminimumnumberofkeys.
Thedeletionproceduredeletesthekeykfromthesubtreerootedatx.Thisprocedureguaranteesthat
wheneveritcallsitselfrecursivelyonanodex,thenumberofkeysinxisatleasttheminimumdegreet.
NotethatthisconditionrequiresonemorekeythantheminimumrequiredbytheusualBtreeconditions,so
thatsometimesakeymayhavetobemovedintoachildnodebeforerecursiondescendstothatchild.This
strengthenedconditionallowsustodeleteakeyfromthetreeinonedownwardpasswithouthavingtoback
up(withoneexception,whichwellexplain).Youshouldinterpretthefollowingspecificationfordeletion
fromaBtreewiththeunderstandingthatiftherootnodexeverbecomesaninternalnodehavingnokeys
(thissituationcanoccurincases2cand3bthenwedeletex,andxsonlychildx.c1becomesthenewroot
ofthetree,decreasingtheheightofthetreebyoneandpreservingthepropertythattherootofthetree
containsatleastonekey(unlessthetreeisempty).
WesketchhowdeletionworkswithvariouscasesofdeletingkeysfromaBtree.
1.
Ifthekeykisinnodexandxisaleaf,deletethekeykfromx.
2.
Ifthekeykisinnodexandxisaninternalnode,dothefollowing.
a)
Ifthechildythatprecedeskinnodexhasatleasttkeys,thenfindthepredecessork0ofkinthe
subtreerootedaty.Recursivelydeletek0,andreplacekbyk0inx.(Wecanfindk0anddeleteitinasingle
downwardpass.)
b)
Ifyhasfewerthantkeys,then,symmetrically,examinethechildzthatfollowskinnodex.Ifzhas
atleasttkeys,thenfindthesuccessork0ofkinthesubtreerootedatz.Recursivelydeletek0,andreplace
kbyk0inx.(Wecanfindk0anddeleteitinasingledownwardpass.)
c)Otherwise,ifbothyandzhaveonlyt1keys,mergekandallofzintoy,sothatxlosesbothkandthe
pointertoz,andynowcontains2t1keys.Thenfreezandrecursivelydeletekfromy.
3.
Ifthekeykisnotpresentininternalnodex,determinetherootx.c(i)oftheappropriatesubtreethat
mustcontaink,ifkisinthetreeatall.Ifx.c(i)hasonlyt1keys,executestep3aor3basnecessaryto
guaranteethatwedescendtoanodecontainingatleasttkeys.Thenfinishbyrecursingontheappropriate
childofx.
a)
Ifx.c(i)hasonlyt1keysbuthasanimmediatesiblingwithatleasttkeys,givex.c(i)anextrakeyby
movingakeyfromxdownintox.c(i),movingakeyfromx.c(i)simmediateleftorrightsiblingupintox,and
movingtheappropriatechildpointerfromthesiblingintox.c(i).
b)
Ifx.c(i)andbothofx.c(i)simmediatesiblingshavet1keys,mergex.c(i)withonesibling,which
involvesmovingakeyfromxdownintothenewmergednodetobecomethemediankeyforthatnode.
SincemostofthekeysinaBtreeareintheleaves,deletionoperationsaremostoftenusedtodeletekeys
fromleaves.Therecursivedeleteprocedurethenactsinonedownwardpassthroughthetree,without
havingtobackup.Whendeletingakeyinaninternalnode,however,theproceduremakesadownward
passthroughthetreebutmayhavetoreturntothenodefromwhichthekeywasdeletedtoreplacethekey
withitspredecessororsuccessor(cases2aand2b).
ThefollowingfiguresfromCLRSbookexplainthedeletionporcess.
Implementation:
FollowingisC++implementationofdeletionprocess.
/* The following program performs deletion on a B-Tree. It contains functions
specific for deletion along with all the other functions provided in the
previous articles on B-Trees. See
http://www.geeksforgeeks.org/b-tree-set-1-introduction-2/
for previous article.
The deletion function has been compartmentalized into 8 functions for ease
of understanding and clarity
4) getPred
5) getSucc
6) borrowFromPrev
7) borrowFromNext
8) merge
9) findKey
In class BTree:
1) remove
The removal of a key from a B-Tree is a fairly complicated process. The program
handles
all the 6 different cases that might arise while removing a key.
Testing: The code has been tested using the B-Tree provided in the CLRS book(
included
in the main function ) along with other cases.
#include<iostream>
using namespace std;
// A BTree node
class BTreeNode
{
int *keys; // An array of keys
int t;
public:
// Constructor
// A function that returns the index of the first key that is greater
// or equal to k
int findKey(int k);
class BTree
{
BTreeNode *root; // Pointer to root node
int t; // Minimum degree
public:
void traverse()
{
if (root != NULL) root->traverse();
}
};
// A utility function that returns the index of the first key that is
// greater than or equal to k
int BTreeNode::findKey(int k)
{
int idx=0;
while (idx<n && keys[idx] < k)
++idx;
return idx;
}
// A function to remove the key k from the sub-tree rooted with this node
void BTreeNode::remove(int k)
{
int idx = findKey(k);
// If this node is a leaf node, then the key is not present in tree
if (leaf)
{
cout << "The key "<< k <<" is does not exist in the tree\n";
return;
}
// The key to be removed is present in the sub-tree rooted with this node
// The flag indicates whether the key is present in the sub-tree rooted
// with the last child of this node
bool flag = ( (idx==n)? true : false );
// If the child where the key is supposed to exist has less that t keys,
// we fill that child
if (C[idx]->n < t)
fill(idx);
// If the last child has been merged, it must have merged with the previous
// child and so we recurse on the (idx-1)th child. Else, we recurse on the
// (idx)th child which now has atleast t keys
if (flag && idx > n)
C[idx-1]->remove(k);
else
C[idx]->remove(k);
}
return;
}
// A function to remove the idx-th key from this node - which is a leaf node
void BTreeNode::removeFromLeaf (int idx)
{
// Move all the keys after the idx-th pos one place backward
for (int i=idx+1; i<n; ++i)
keys[i-1] = keys[i];
return;
}
// A function to remove the idx-th key from this node - which is a non-leaf node
void BTreeNode::removeFromNonLeaf(int idx)
{
int k = keys[idx];
// If both C[idx] and C[idx+1] has less that t keys,merge k and all of C[idx+1]
// into C[idx]
// Now C[idx] contains 2t-1 keys
// Free C[idx+1] and recursively delete k from C[idx]
else
{
merge(idx);
C[idx]->remove(k);
}
return;
}
{
// Keep moving to the right most node until we reach a leaf
BTreeNode *cur=C[idx];
while (!cur->leaf)
cur = cur->C[cur->n];
// Keep moving the left most node starting from C[idx+1] until we reach a leaf
BTreeNode *cur = C[idx+1];
while (!cur->leaf)
cur = cur->C[0];
// A function to fill child C[idx] which has less than t-1 keys
void BTreeNode::fill(int idx)
{
// If the previous child(C[idx-1]) has more than t-1 keys, borrow a key
// from that child
if (idx!=0 && C[idx-1]->n>=t)
borrowFromPrev(idx);
// If the next child(C[idx+1]) has more than t-1 keys, borrow a key
// from that child
else if (idx!=n && C[idx+1]->n>=t)
borrowFromNext(idx);
// If C[idx] is the last child, merge it with with its previous sibling
// Otherwise merge it with its next sibling
else
{
if (idx != n)
merge(idx);
else
merge(idx-1);
}
return;
}
BTreeNode *child=C[idx];
BTreeNode *sibling=C[idx-1];
// The last key from C[idx-1] goes up to the parent and key[idx-1]
// from parent is inserted as the first key in C[idx]. Thus, the loses
// sibling one key and child gains one key
// If C[idx] is not a leaf, move all its child pointers one step ahead
if (!child->leaf)
{
for(int i=child->n; i>=0; --i)
child->C[i+1] = child->C[i];
}
// Setting child's first key equal to keys[idx-1] from the current node
child->keys[0] = keys[idx-1];
child->n += 1;
sibling->n -= 1;
return;
}
BTreeNode *child=C[idx];
BTreeNode *sibling=C[idx+1];
return;
}
// Pulling a key from the current node and inserting it into (t-1)th
// position of C[idx]
child->keys[t-1] = keys[idx];
// Moving all keys after idx in the current node one step before // to fill the gap created by moving keys[idx] to C[idx]
for (int i=idx+1; i<n; ++i)
keys[i-1] = keys[i];
// Moving the child pointers after (idx+1) in the current node one
// step before
for (int i=idx+2; i<=n; ++i)
C[i-1] = C[i];
// Split the old root and move 1 key to the new root
s->splitChild(0, root);
// Change root
root = s;
}
else // If root is not full, call insertNonFull for root
root->insertNonFull(k);
}
}
// of y
BTreeNode *z = new BTreeNode(y->t, y->leaf);
z->n = t - 1;
void BTree::remove(int k)
{
if (!root)
{
cout << "The tree is empty\n";
return;
}
// If the root node has 0 keys, make its first child as the new root
// if it has a child, otherwise set root as NULL
if (root->n==0)
{
BTreeNode *tmp = root;
if (root->leaf)
root = NULL;
else
root = root->C[0];
t.insert(1);
t.insert(3);
t.insert(7);
t.insert(10);
t.insert(11);
t.insert(13);
t.insert(14);
t.insert(15);
t.insert(18);
t.insert(16);
t.insert(19);
t.insert(24);
t.insert(25);
t.insert(26);
t.insert(21);
t.insert(4);
t.insert(5);
t.insert(20);
t.insert(22);
t.insert(2);
t.insert(17);
t.insert(12);
t.insert(6);
t.remove(6);
cout << "Traversal of tree after removing 6\n";
t.traverse();
cout << endl;
t.remove(13);
cout << "Traversal of tree after removing 13\n";
t.traverse();
cout << endl;
t.remove(7);
cout << "Traversal of tree after removing 7\n";
t.traverse();
cout << endl;
t.remove(4);
cout << "Traversal of tree after removing 4\n";
t.traverse();
cout << endl;
t.remove(2);
cout << "Traversal of tree after removing 2\n";
t.traverse();
cout << endl;
t.remove(16);
cout << "Traversal of tree after removing 16\n";
t.traverse();
cout << endl;
return 0;
}
Output:
Traversaloftreeconstructedis
123456710111213141516171819202122242526
Traversaloftreeafterremoving6
12345710111213141516171819202122242526
Traversaloftreeafterremoving13
123457101112141516171819202122242526
Traversaloftreeafterremoving7
12345101112141516171819202122242526
Traversaloftreeafterremoving4
1235101112141516171819202122242526
Traversaloftreeafterremoving2
135101112141516171819202122242526
Traversaloftreeafterremoving16
1351011121415171819202122242526
=======================================================================
PrintLeftViewofaBinaryTree
GivenaBinaryTree,printleftviewofit.LeftviewofaBinaryTreeissetofnodesvisiblewhentreeisvisited
fromleftside.Leftviewoffollowingtreeis12,10,25.
12
/\
1030
/\
2540
Theleftviewcontainsallnodesthatarefirstnodesintheirlevels.Asimplesolutionistodolevelorder
traversalandprintthefirstnodeineverylevel.
Theproblemcanalsobesolvedusingsimplerecursivetraversal.Wecankeeptrackoflevelofanodeby
passingaparametertoallrecursivecalls.Theideaistokeeptrackofmaximumlevelalso.Wheneverwe
seeanodewhoselevelismorethanmaximumlevelsofar,weprintthenodebecausethisisthefirstnode
initslevel(Notethatwetraversetheleftsubtreebeforerightsubtree).FollowingisCimplementationofthis
approach.
// C program to print left view of Binary Tree
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *left, *right;
};
leftView(root);
return 0;
}
Output:
121025
TimeComplexity:Thefunctiondoesasimpletraversalofthetree,sothecomplexityisO(n).
=======================================================================
Checkifallleavesareatsamelevel
GivenaBinaryTree,checkifallleavesareatsamelevelornot.
12
/\
57
/\
31
Leavesareatsamelevel
12
/\
57
LeavesareNotatsamelevel
12
/
5
/\
39
//
12
Leavesareatsamelevel
Westronglyrecommendyoutominimizethebrowserandtrythisyourselffirst.
TheideaistofirstfindleveloftheleftmostleafandstoreitinavariableleafLevel.Thencomparelevelofall
otherleaveswithleafLevel,ifsame,returntrue,elsereturnfalse.WetraversethegivenBinaryTreein
Preorderfashion.Anargumentleaflevelispassedtoallcalls.ThevalueofleafLevelisinitializedas0to
indicatethatthefirstleafisnotyetseenyet.Thevalueisupdatedwhenwefindfirstleaf.Levelof
subsequentleaves(inpreorder)iscomparedwithleafLevel.
// C program to check if all leaves are at same level
#include <stdio.h>
#include <stdlib.h>
/* Recursive function which checks whether all leaves are at same level */
bool checkUtil(struct Node *root, int level, int *leafLevel)
{
// Base case
if (root == NULL) return true;
// If this node is not leaf, recursively check left and right subtrees
return checkUtil(root->left, level+1, leafLevel) &&
checkUtil(root->right, level+1, leafLevel);
}
return 0;
}
Output:
Leavesareatsamelevel
TimeComplexity:Thefunctiondoesasimpletraversalofthetree,sothecomplexityisO(n).
=======================================================================
Finddepthofthedeepestoddlevel
leafnode
WriteaCcodetogetthedepthofthedeepestoddlevelleafnodeinabinarytree.Considerthatlevelstarts
with1.Depthofaleafnodeisnumberofnodesonthepathfromroottoleaf(includingbothleafandroot).
Forexample,considerthefollowingtree.Thedeepestoddlevelnodeisthenodewithvalue9anddepthof
thisnodeis5.
1
/\
23
//\
456
\\
78
/\
910
/
11
Westronglyrecommendyoutominimizethebrowserandtrythisyourselffirst.
Theideaistorecursivelytraversethegivenbinarytreeandwhiletraversing,maintainavariablelevel
whichwillstorethecurrentnodeslevelinthetree.Ifcurrentnodeisleafthenchecklevelisoddornot.If
levelisoddthenreturnit.Ifcurrentnodeisnotleaf,thenrecursivelyfindmaximumdepthinleftandright
subtrees,andreturnmaximumofthetwodepths.
// C program to find depth of the deepest odd level leaf node
#include <stdio.h>
#include <stdlib.h>
// If this node is a leaf and its level is odd, return its level
if (root->left==NULL && root->right==NULL && level&1)
return level;
// If not leaf, return the maximum value from left and right subtrees
return max(depthOfOddLeafUtil(root->left, level+1),
depthOfOddLeafUtil(root->right, level+1));
}
/* Main function which calculates the depth of deepest odd level leaf.
This function mainly uses depthOfOddLeafUtil() */
int depthOfOddLeaf(struct Node *root)
{
int level = 1, depth = 0;
return depthOfOddLeafUtil(root, level);
}
5istherequireddepth
TimeComplexity:Thefunctiondoesasimpletraversalofthetree,sothecomplexityisO(n).
=======================================================================
PrintPostordertraversalfromgiven
InorderandPreordertraversals
GivenInorderandPreordertraversalsofabinarytree,printPostordertraversal.
Example:
Input:
Inordertraversalin[]={4,2,5,1,3,6}
Preordertraversalpre[]={1,2,4,5,3,6}
Output:
Postordertraversalis{4,5,2,6,3,1}
Trversalsintheaboveexamplerepresentsfollowingtree
1
/\
23
/\\
456
Anaivemethodistofirstconstructthetree,thenusesimplerecursivemethodtoprintpostordertraversalof
theconstructedtree.
Wecanprintpostordertraversalwithoutconstructingthetree.Theideais,rootisalwaysthefirstitem
inpreordertraversalanditmustbethelastiteminpostordertraversal.Wefirstrecursivelyprintleftsubtree,
thenrecursivelyprintrightsubtree.Finally,printroot.Tofindboundariesofleftandrightsubtreesinpre[]
andin[],wesearchrootinin[],allelementsbeforerootinin[]areelementsofleftsubtreeandallelements
afterrootareelementsofrightsubtree.Inpre[],allelementsafterindexofrootinin[]areelementsofright
subtree.Andelementsbeforeindex(includingtheelementatindexandexcludingthefirstelement)are
elementsofleftsubtree.
// C++ program to print postorder traversal from preorder and inorder traversals
#include <iostream>
using namespace std;
{
// The first element in pre[] is always root, search it
// in in[] to find left and right subtrees
int root = search(in, pre[0], n);
// Print root
cout << pre[0] << " ";
}
Postordertraversal
452631
TimeComplexity:Theabovefunctionvisitseverynodeinarray.Foreveryvisit,itcallssearchwhichtakes
O(n)time.Therefore,overalltimecomplexityofthefunctionisO(n2)
=======================================================================
Differencebetweensumsofoddlevel
andevenlevelnodesofaBinaryTree
GivenaaBinaryTree,findthedifferencebetweenthesumofnodesatoddlevelandthesumofnodesat
evenlevel.Considerrootaslevel1,leftandrightchildrenofrootaslevel2andsoon.
Forexample,inthefollowingtree,sumofnodesatoddlevelis(5+1+4+8)whichis18.Andsumof
nodesatevenlevelis(2+6+3+7+9)whichis27.Theoutputforfollowingtreeshouldbe1827which
is9.
5
/\
26
/\\
148
//\
379
Astraightforwardmethodistouselevelordertraversal.Inthetraversal,checklevelofcurrentnode,ifitis
odd,incrementoddsumbydataofcurrentnode,otherwiseincrementevensum.Finallyreturndifference
betweenoddsumandevensum.Seefollowingforimplementationofthisapproach.
Cimplementationoflevelordertraversalbasedapproachtofindthedifference.
Theproblemcanalsobesolvedusingsimplerecursivetraversal.Wecanrecursivelycalculatethe
requireddifferenceas,valueofrootsdatasubtractedbythedifferenceforsubtreeunderleftchildandthe
differenceforsubtreeunderrightchild.FollowingisCimplementationofthisapproach.
// A recursive program to find difference between sum of nodes at
// odd level and sum at even level
#include <stdio.h>
#include <stdlib.h>
// The main function that return difference between odd and even level
// nodes
int getLevelDiff(struct node *root)
{
// Base case
if (root == NULL)
return 0;
Output:
9istherequireddifference
TimecomplexityofbothmethodsisO(n),butthesecondmethodissimpleandeasytoimplement.
=======================================================================
Printancestorsofagivenbinarytree
nodewithoutrecursion
GivenaBinaryTreeandakey,writeafunctionthatprintsalltheancestorsofthekeyinthegivenbinary
tree.
Forexample,considerthefollowingBinaryTree
1
/\
23
/\/\
4567
/\/
8910
Followingaredifferentinputkeysandtheirancestorsintheabovetree
InputKeyListofAncestors
21
31
421
521
631
731
8421
9521
10731
Recursivesolutionforthisproblemisdiscussedhere.
ItisclearthatweneedtouseastackbasediterativetraversaloftheBinaryTree.Theideaistohaveall
ancestorsinstackwhenwereachthenodewithgivenkey.Oncewereachthekey,allwehavetodois,
printcontentsofstack.
Howtogetallancestorsinstackwhenwereachthegivennode?WecantraverseallnodesinPostorder
way.Ifwetakeacloserlookattherecursivepostordertraversal,wecaneasilyobservethat,whenrecursive
functioniscalledforanode,therecursioncallstackcontainsancestorsofthenode.Soideaisdoiterative
Postordertraversalandstopthetraversalwhenwereachthedesirednode.
FollowingisCimplementationoftheaboveapproach.
// C program to print all ancestors of a given key
#include <stdio.h>
#include <stdlib.h>
return stack->array[stack->top];
}
// Traverse the complete tree in postorder way till we find the key
while (1)
{
// Traverse the left side. While traversing, push the nodes into
// the stack so that their right subtrees can be traversed later
while (root && root->data != key)
{
push(stack, root);
// If the popped node is right child of top, then remove the top
// as well. Left child of the top must have processed before.
// Consider the following tree for example and key = 3. If we
//
//
//
\
3
//
//
//
// if stack is not empty then simply set the root as right child
// of top and start traversing right sub-tree.
root = isEmpty(stack)? NULL: peek(stack)->right;
}
root->right->right->left = newNode(10);
getchar();
return 0;
}
Output:
Followingareallkeysandtheirancestors
1:
2:1
3:1
4:21
5:21
6:31
7:31
8:421
9:521
10:731
Exercise
NotethattheabovesolutionassumesthatthegivenkeyispresentinthegivenBinaryTree.Itmaygoin
infiniteloopifkeyisnotpresent.Extendtheabovesolutiontoworkevenwhenthekeyisnotpresentintree.
=======================================================================
ConvertagivenBinaryTreeto
DoublyLinkedList|Set2
GivenaBinaryTree(BT),convertittoaDoublyLinkedList(DLL).Theleftandrightpointersinnodesareto
beusedaspreviousandnextpointersrespectivelyinconvertedDLL.TheorderofnodesinDLLmustbe
sameasInorderofthegivenBinaryTree.ThefirstnodeofInordertraversal(leftmostnodeinBT)mustbe
headnodeoftheDLL.
Asolutiontothisproblemisdiscussedinthispost.
Inthispost,anothersimpleandefficientsolutionisdiscussed.Thesolutiondiscussedherehastwosimple
steps.
1)FixLeftPointers:Inthisstep,wechangeleftpointerstopointtopreviousnodesinDLL.Theideais
simple,wedoinordertraversaloftree.Ininordertraversal,wekeeptrackofpreviousvisitednodeand
changeleftpointertothepreviousnode.SeefixPrevPtr()inbelowimplementation.
2)FixRightPointers:Theaboveisintuitiveandsimple.Howtochangerightpointerstopointtonextnode
inDLL?Theideaistouseleftpointersfixedinstep1.WestartfromtherightmostnodeinBinaryTree(BT).
TherightmostnodeisthelastnodeinDLL.SinceleftpointersarechangedtopointtopreviousnodeinDLL,
wecanlinearlytraversethecompleteDLLusingthesepointers.Thetraversalwouldbefromlasttofirst
node.WhiletraversingtheDLL,wekeeptrackofthepreviouslyvisitednodeandchangetherightpointerto
thepreviousnode.SeefixNextPtr()inbelowimplementation.
// A simple inorder traversal based program to convert a Binary Tree to DLL
#include<stdio.h>
#include<stdlib.h>
// A tree node
struct node
{
int data;
if (root != NULL)
{
fixPrevPtr(root->left);
root->left = pre;
pre = root;
fixPrevPtr(root->right);
}
// Start from the rightmost node, traverse back using left pointers.
// While traversing, change right pointer of nodes.
while (root && root->left != NULL)
{
prev = root;
root = root->left;
root->right = prev;
}
// The main function that converts BST to DLL and returns head of DLL
struct node *BTToDLL(struct node *root)
{
// Set the previous pointer
fixPrevPtr(root);
= newNode(12);
root->right
= newNode(15);
root->left->left = newNode(25);
root->left->right = newNode(30);
root->right->left = newNode(36);
printf("\n\n\t\tDLL Traversal\n\n");
printList(head);
return 0;
}
Output:
InorderTreeTraversal
251230103615
DLLTraversal
251230103615
TimeComplexity:O(n)wherenisthenumberofnodesingivenBinaryTree.Thesolutionsimplydoestwo
traversalsofallBinaryTreenodes.
=======================================================================
CheckforIdenticalBSTswithout
buildingthetrees
Giventwoarrayswhichrepresentasequenceofkeys.ImaginewemakeaBinarySearchTree(BST)from
eacharray.WeneedtotellwhethertwoBSTswillbeidenticalornotwithoutactuallyconstructingthetree.
Examples
Forexample,theinputarraysare{2,4,3,1}and{2,1,4,3}willconstructthesametree
Lettheinputarraysbea[]andb[]
Example1:
a[]={2,4,1,3}willconstructfollowingtree.
2
/\
14
/
3
b[]={2,4,3,1}willalsoalsoconstructthesametree.
2
/\
14
/
3
Sotheoutputis"True"
Example2:
a[]={8,3,6,1,4,7,10,14,13}
b[]={8,10,14,3,6,4,1,7,13}
TheybothconstructthesamefollowingBST,sooutputis"True"
8
/\
310
/\\
1614
/\/
4713
Solution:
AccordingtoBSTproperty,elementsofleftsubtreemustbesmallerandelementsofrightsubtreemustbe
greaterthanroot.
TwoarraysrepresentsaneBSTifforeveryelementx,theelementsinleftandrightsubtreesofxappear
afteritinbotharrays.Andsameistrueforrootsofleftandrightsubtrees.
Theideaistocheckofifnextsmallerandgreaterelementsaresameinbotharrays.Samepropertiesare
recursivelycheckedforleftandrightsubtrees.Theidealookssimple,butimplementationrequireschecking
allconditionsforallelements.Followingisaninterestingrecursiveimplementationoftheidea.
// A C program to check for Identical BSTs without building the trees
#include<stdio.h>
#include<limits.h>
#include<stdbool.h>
/* The main function that checks if two arrays a[] and b[] of size n construct
same BST. The two values 'min' and 'max' decide whether the call is made for
left subtree or right subtree of a parent element. The indexes i1 and i2 are
the indexes in (a[] and b[]) after which we search the left or right child.
Initially, the call is made for INT_MIN and INT_MAX as 'min' and 'max'
respectively, because root has no parent.
i1 and i2 are just after the indexes of the parent element in a[] and b[]. */
bool isSameBSTUtil(int a[], int b[], int n, int i1, int i2, int min, int max)
{
int j, k;
/* Search for a value satisfying the constraints of min and max in a[] and
b[]. If the parent element is a leaf node then there must be some
elements in a[] and b[] satisfying constraint. */
for (j=i1; j<n; j++)
if (a[j]>min && a[j]<max)
break;
for (k=i2; k<n; k++)
if (b[k]>min && b[k]<max)
break;
/* Make the current child as parent and recursively check for left and right
subtrees of it. Note that we can also pass a[k] in place of a[j] as they
are both are same */
return isSameBSTUtil(a, b, n, j+1, k+1, a[j], max) && // Right Subtree
isSameBSTUtil(a, b, n, j+1, k+1, min, a[j]);
}
// Left Subtree
BSTsaresame
=======================================================================
CustomTreeProblem
Youaregivenasetoflinks,e.g.
a>b
b>c
b>d
a>e
Printthetreethatwouldformwheneachpairoftheselinksthathasthesamecharacterasstartandend
pointisjoinedtogether.Youhavetomaintainfidelityw.r.t.theheightofnodes,i.e.nodesatheightnfrom
rootshouldbeprintedatsameroworcolumn.Forsetoflinksgivenabove,treeprintedshouldbe
>a
|>b
||>c
||>d
|>e
Notethattheselinksneednotformasingletreetheycouldform,ahem,aforest.Considerthefollowing
links
a>b
a>g
b>c
c>d
d>e
c>f
z>y
y>x
x>w
Theoutputwouldbefollowingforest.
>a
|>b
||>c
|||>d
||||>e
|||>f
|>g
>z
|>y
||>x
|||>w
Youcanassumethatgivenlinkscanformatreeorforestoftreesonly,andtherearenoduplicatesamong
links.
Solution:Theideaistomaintaintwoarrays,onearrayfortreenodesandotherfortreesthemselves(we
callthisarrayforest).AnelementofthenodearraycontainstheTreeNodeobjectthatcorrespondsto
respectivecharacter.AnelementoftheforestarraycontainsTreeobjectthatcorrespondstorespectiveroot
oftree.
Itshouldbeobviousthatthecrucialpartiscreatingtheforesthere,onceitiscreated,printingitoutin
requiredformatisstraightforward.Tocreatetheforest,followingprocedureisused
Dofollowingforeachinputlink,
1.Ifstartoflinkisnotpresentinnodearray
CreateTreeNodeobjectsforstartcharacter
Addentriesofstartinbotharrays.
2.Ifendoflinkisnotpresentinnodearray
CreateTreeNodeobjectsforstartcharacter
Addentryofendinnodearray.
3.Ifendoflinkispresentinnodearray.
Ifendoflinkispresentinforestarray,thenremoveit
fromthere.
4.Addanedge(intree)betweenstartandendnodesoflink.
Itshouldbeclearthatthisprocedurerunsinlineartimeinnumberofnodesaswellasoflinksitmakes
onlyonepassoverthelinks.Italsorequireslinearspaceintermsofalphabetsize.
FollowingisJavaimplementationofabovealgorithm.Inthefollowingimplementationcharactersare
assumedtobeonlylowercasecharactersfromatoz.
// Java program to create a custom tree from a given set of links.
// The main class that represents tree and has main method
public class Tree {
// Constructor
public Tree(TreeNode root) { this.root = root; }
String [] links2 = {"a b", "a g", "b c", "c d", "d e", "c f",
"z y", "y x", "x w"};
System.out.println("------------ Forest 2 ----------------");
printForest(links2);
}
// Constructor
public TreeNode(char c) { this.c = c; this.children = new TreeNode[26];}
Forest1
>a
|>b
||>c
||>d
|>e
Forest2
>a
|>b
||>c
|||>d
||||>e
|||>f
|");
|>g
>z
|>y
||>x
|||>w
=======================================================================
IterativeMethodtofindHeightof
BinaryTree
TherearetwoconventionstodefineheightofBinaryTree
1)Numberofnodesonlongestpathfromroottothedeepestnode.
2)Numberofedgesonlongestpathfromroottothedeepestnode.
Inthispost,thefirstconventionisfollowed.Forexample,heightofthebelowtreeis3.
ExampleTree
RecursivemethodtofindheightofBinaryTreeisdiscussedhere.Howtofindheightwithoutrecursion?We
canuselevelordertraversaltofindheightwithoutrecursion.Theideaistotraverselevelbylevel.Whenever
movedowntoalevel,incrementheightby1(heightisinitializedas0).Countnumberofnodesateachlevel,
stoptraversingwhencountofnodesatnextlevelis0.
Followingisdetailedalgorithmtofindlevelordertraversalusingqueue.
Createaqueue.
Pushrootintothequeue.
height=0
Loop
nodeCount=sizeofqueue
//Ifnumberofnodesatthislevelis0,returnheight
ifnodeCountis0
returnHeight
else
increaseHeight
//Removenodesofthislevelandaddnodesof
//nextlevel
while(nodeCount>0)
popnodefromfront
pushitschildrentoqueue
decreasenodeCount
//Atthispoint,queuehasnodesofnextlevel
FollowingisC++implementationofabovealgorithm.
/* Program to find height of the tree by Iterative Method */
#include <iostream>
#include <queue>
using namespace std;
// Base Case
if (root == NULL)
return 0;
while (1)
{
// nodeCount (queue size) indicates number of nodes
// at current lelvel.
int nodeCount = q.size();
if (nodeCount == 0)
return height;
height++;
Heightoftreeis3
TimeComplexity:O(n)wherenisnumberofnodesingivenbinarytree.
=======================================================================
Findallpossibleinterpretationsofan
arrayofdigits
Consideracodingsystemforalphabetstointegerswhereaisrepresentedas1,bas2,..zas26.Given
anarrayofdigits(1to9)asinput,writeafunctionthatprintsallvalidinterpretationsofinputarray.
Examples
Input:{1,1}
Output:("aa",'k")
[2interpretations:aa(1,1),k(11)]
Input:{1,2,1}
Output:("aba","au","la")
[3interpretations:aba(1,2,1),au(1,21),la(12,1)]
Input:{9,1,8}
Output:{"iah","ir"}
[2interpretations:iah(9,1,8),ir(9,18)]
Pleasenotewecannotchangeorderofarray.Thatmeans{1,2,1}cannotbecome{2,1,1}
Onfirstlookitlookslikeaproblemofpermutation/combination.Butoncloserlookyouwillfigureoutthatthis
isaninterestingtreeproblem.
Theideahereisstringcantakeatmosttwopaths:
1.Processingledigit
2.Processtwodigits
Thatmeanswecanusebinarytreehere.Processingwithsingledigitwillbeleftchildandtwodigitswillbe
rightchild.Ifvaluetwodigitsisgreaterthan26thenourrightchildwillbenullaswedonthavealphabetfor
greaterthan26.
Letsunderstandwithanexample.Arraya={1,2,1}.Belowdiagramshowsthathowourtreegrows.
{1,2,1}Codesusedintree
/\"a">1
/\"b">2
"a"{2,1}"l"{1}"l">12
/\/\
/\/\
"ab"{1}"au""la"null
/\
/\
"aba"null
Braces{}containarraystillpendingforprocessing.Notethatwitheverylevel,ourarraysizedecreases.If
youwillseecarefully,itisnothardtofindthattreeheightisalwaysn(arraysize)
Howtoprintallstrings(interpretations)?Outputstringsareleafnodeoftree.i.efor{1,2,1},outputis{abaau
la}.
Wecanconcludethattherearemainlytwostepstoprintallinterpretationsofgivenintegerarray.
Step1:Createabinarytreewithallpossibleinterpretationsinleafnodes.
Step2:Printallleafnodesfromthebinarytreecreatedinstep1.
FollowingisJavaimplementationofabovealgorithm.
String dataString;
Node left;
Node right;
Node(String dataString) {
this.dataString = dataString;
//Be default left and right child are null.
}
data = arr[0];
// left child
root.left = createTree(data, dataToStr, newArr);
printleaf(root.left);
printleaf(root.right);
}
// For simplicity I am taking it as string array. Char Array will save space
private static final String[] alphabet = {"", "a", "b", "c", "d", "e",
"f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
"s", "t", "u", "v", "w", "x", "v", "z"};
// bf(2,6) z(26)
int[] arr3 = {2, 6};
printAllInterpretations(arr3);
// ab(1,2), l(12)
int[] arr4 = {1, 2};
printAllInterpretations(arr4);
// a(1,0} j(10)
int[] arr5 = {1, 0};
printAllInterpretations(arr5);
aacdamdkcd
aaaakka
bfz
abl
aj
abbaabuavalbalu
=======================================================================
TreeIsomorphismProblem
Writeafunctiontodetectiftwotreesareisomorphic.Twotreesarecalledisomorphicifoneofthemcanbe
obtainedfromotherbyaseriesofflips,i.e.byswappingleftandrightchildrenofanumberofnodes.Any
numberofnodesatanylevelcanhavetheirchildrenswapped.Twoemptytreesareisomorphic.
Forexample,followingtwotreesareisomorphicwithfollowingsubtreesflipped:2and3,NULLand6,7and
8.
Wesimultaneouslytraversebothtrees.Letthecurrentinternalnodesoftwotreesbeingtraversedben1and
n2respectively.Therearefollowingtwoconditionsforsubtreesrootedwithn1andn2tobeisomorphic.
1)Dataofn1andn2issame.
2)Oneofthefollowingtwoistrueforchildrenofn1andn2
a)Leftchildofn1isisomorphictoleftchildofn2andrightchildofn1isisomorphictorightchildofn2.
b)Leftchildofn1isisomorphictorightchildofn2andrightchildofn1isisomorphictoleftchildofn2.
// A C++ program to check if two given trees are isomorphic
#include <iostream>
using namespace std;
/* A binary tree node has data, pointer to left and right children */
struct node
{
int data;
struct node* left;
struct node* right;
};
if (n1->data != n2->data)
return false;
return (temp);
}
= newNode(2);
n1->right
= newNode(3);
n1->left->left = newNode(4);
n1->left->right = newNode(5);
n1->right->left = newNode(6);
n1->left->right->left = newNode(7);
n1->left->right->right = newNode(8);
= newNode(3);
n2->right
= newNode(2);
n2->right->left
n2->right->right
n2->left->right
= newNode(4);
= newNode(5);
= newNode(6);
n2->right->right->left = newNode(8);
n2->right->right->right = newNode(7);
return 0;
}
Output:
Yes
TimeComplexity:Theabovesolutiondoesatraversalofbothtrees.SotimecomplexityisO(m+n)where
mandnarenumberofnodesingiventrees.
=======================================================================
LongestprefixmatchingATrie
basedsolutioninJava
Givenadictionaryofwordsandaninputstring,findthelongestprefixofthestringwhichisalsoawordin
dictionary.
Examples:
Letthedictionarycontainsthefollowingwords:
{are,area,base,cat,cater,children,basement}
Belowaresomeinput/outputexamples:
InputStringOutput
caterercater
basemexybase
child<Empty>
Solution
WebuildaTrieofalldictionarywords.OncetheTrieisbuilt,traversethroughitusingcharactersofinput
string.Ifprefixmatchesadictionaryword,storecurrentlengthandlookforalongermatch.Finally,return
thelongestmatch.
FollowingisJavaimplementationoftheabovesolutionbased.
import java.util.HashMap;
return children; }
return value;
bIsEnd = val;
return bIsEnd; }
{
TrieNode temp = new TrieNode(ch);
child.put( ch, temp );
crawl = temp;
}
}
// The main method that finds out the longest string 'input'
public String getMatchingPrefix(String input) {
String result = ""; // Initialize resultant string
int length = input.length(); // Find length of the input string
//Update result
// Testing class
public class Test {
public static void main(String[] args) {
");
System.out.println(dict.getMatchingPrefix(input));
input = "basement";
System.out.print(input + ":
");
System.out.println(dict.getMatchingPrefix(input));
input = "are";
System.out.print(input + ":
");
System.out.println(dict.getMatchingPrefix(input));
input = "arex";
System.out.print(input + ":
");
System.out.println(dict.getMatchingPrefix(input));
input = "basemexz";
System.out.print(input + ":
");
System.out.println(dict.getMatchingPrefix(input));
input = "xyz";
System.out.print(input + ":
");
System.out.println(dict.getMatchingPrefix(input));
}
}
Output:
caterer:cater
basement:basement
are:are
arex:are
basemexz:base
xyz:
TimeComplexity:TimecomplexityoffindingthelongestprefixisO(n)wherenislengthoftheinputstring.
ReferthisfortimecomplexityofbuildingtheTrie.
=======================================================================
BTree|Set2(Insert)
Inthepreviouspost,weintroducedBTree.Wealsodiscussedsearch()andtraverse()functions.
Inthispost,insert()operationisdiscussed.Anewkeyisalwaysinsertedatleafnode.Letthekeytobe
insertedbek.LikeBST,westartfromrootandtraversedowntillwereachaleafnode.Oncewereachaleaf
node,weinsertthekeyinthatleafnode.UnlikeBSTs,wehaveapredefinedrangeonnumberofkeysthata
nodecancontain.Sobeforeinsertingakeytonode,wemakesurethatthenodehasextraspace.
Howtomakesurethatanodehasspaceavailableforkeybeforethekeyisinserted?Weuseanoperation
calledsplitChild()thatisusedtosplitachildofanode.Seethefollowingdiagramtounderstandsplit.Inthe
followingdiagram,childyofxisbeingsplitintotwonodesyandz.NotethatthesplitChildoperationmoves
akeyupandthisisthereasonBTreesgrowupunlikeBSTswhichgrowdown.
Asdiscussedabove,toinsertanewkey,wegodownfromroottoleaf.Beforetraversingdowntoanode,
wefirstcheckifthenodeisfull.Ifthenodeisfull,wesplitittocreatespace.Followingiscompletealgorithm.
Insertion
1)Initializexasroot.
2)Whilexisnotleaf,dofollowing
..a)Findthechildofxthatisgoingtotobetraversednext.Letthechildbey.
..b)Ifyisnotfull,changextopointtoy.
..c)Ifyisfull,splititandchangextopointtooneofthetwopartsofy.Ifkissmallerthanmidkeyiny,then
setxasfirstpartofy.Elsesecondpartofy.Whenwesplity,wemoveakeyfromytoitsparentx.
3)Theloopinstep2stopswhenxisleaf.xmusthavespacefor1extrakeyaswehavebeensplittingall
nodesinadvance.Sosimplyinsertktox.
NotethatthealgorithmfollowstheCormenbook.Itisactuallyaproactiveinsertionalgorithmwherebefore
goingdowntoanode,wesplititifitisfull.Theadvantageofsplittingbeforeis,wenevertraverseanode
twice.Ifwedontsplitanodebeforegoingdowntoitandsplititonlyifnewkeyisinserted(reactive),we
mayenduptraversingallnodesagainfromleaftoroot.Thishappensincaseswhenallnodesonthepath
fromroottoleafarefull.Sowhenwecometotheleafnode,wesplititandmoveakeyup.Movingakeyup
willcauseasplitinparentnode(becauseparentwasalreadyfull).Thiscascadingeffectneverhappensin
thisproactiveinsertionalgorithm.Thereisadisadvantageofthisproactiveinsertionthough,wemaydo
unnecessarysplits.
Letusunderstandthealgorithmwithanexampletreeofminimumdegreetas3andasequenceofintegers
10,20,30,40,50,60,70,80and90inaninitiallyemptyBTree.
InitiallyrootisNULL.Letusfirstinsert10.
Letusnowinsert20,30,40and50.Theyallwillbeinsertedinrootbecausemaximumnumberofkeysa
nodecanaccommodateis2*t1whichis5.
Letusnowinsert60.Sincerootnodeisfull,itwillfirstsplitintotwo,then60willbeinsertedintothe
appropriatechild.
Letusnowinsert70and80.Thesenewkeyswillbeinsertedintotheappropriateleafwithoutanysplit.
Letusnowinsert90.Thisinsertionwillcauseasplit.Themiddlekeywillgouptotheparent.
Seethisformoreexamples.
FollowingisC++implementationoftheaboveproactivealgorithm.
// C++ program for B-Tree insertion
#include<iostream>
using namespace std;
// A BTree node
class BTreeNode
{
int *keys; // An array of keys
int t;
// Constructor
// Make BTree friend of this so that we can access private members of this
// class in BTree functions
friend class BTree;
};
// A BTree
class BTree
{
BTreeNode *root; // Pointer to root node
int t; // Minimum degree
public:
// Constructor (Initializes tree as empty)
BTree(int _t)
{ root = NULL; t = _t; }
// Split the old root and move 1 key to the new root
s->splitChild(0, root);
// Change root
root = s;
}
else // If root is not full, call insertNonFull for root
root->insertNonFull(k);
}
}
void BTreeNode::insertNonFull(int k)
{
// Initialize index as index of rightmost element
int i = n-1;
i++;
}
C[i+1]->insertNonFull(k);
}
}
int k = 6;
(t.search(k) != NULL)? cout << "\nPresent" : cout << "\nNot Present";
k = 15;
(t.search(k) != NULL)? cout << "\nPresent" : cout << "\nNot Present";
return 0;
}
Output:
Traversaloftheconstuctedtreeis5671012172030
Present
NotPresent
=======================================================================
BTree|Set1(Introduction)
BTreeisaselfbalancingsearchtree.Inmostoftheotherselfbalancingsearchtrees(likeAVLandRed
BlackTrees),itisassumedthateverythingisinmainmemory.TounderstanduseofBTrees,wemustthink
ofhugeamountofdatathatcannotfitinmainmemory.Whenthenumberofkeysishigh,thedataisread
fromdiskintheformofblocks.Diskaccesstimeisveryhighcomparedtomainmemoryaccesstime.The
mainideaofusingBTreesistoreducethenumberofdiskaccesses.Mostofthetreeoperations(search,
insert,delete,max,min,..etc)requireO(h)diskaccesseswherehisheightofthetree.Btreeisafattree.
HeightofBTreesiskeptlowbyputtingmaximumpossiblekeysinaBTreenode.Generally,aBTreenode
sizeiskeptequaltothediskblocksize.SincehislowforBTree,totaldiskaccessesformostofthe
operationsarereducedsignificantlycomparedtobalancedBinarySearchTreeslikeAVLTree,RedBlack
Tree,..etc.
PropertiesofBTree
1)Allleavesareatsamelevel.
2)ABTreeisdefinedbythetermminimumdegreet.Thevalueoftdependsupondiskblocksize.
3)Everynodeexceptrootmustcontainatleastt1keys.Rootmaycontainminimum1key.
4)Allnodes(includingroot)maycontainatmost2t1keys.
5)Numberofchildrenofanodeisequaltothenumberofkeysinitplus1.
6)Allkeysofanodearesortedinincreasingorder.Thechildbetweentwokeysk1andk2containsallkeys
inrangefromk1andk2.
7)BTreegrowsandshrinksfromrootwhichisunlikeBinarySearchTree.BinarySearchTreesgrow
downwardandalsoshrinkfromdownward.
8)LikeotherbalancedBinarySearchTrees,timecomplexitytosearch,insertanddeleteisO(Logn).
FollowingisanexampleBTreeofminimumdegree3.NotethatinpracticalBTrees,thevalueofminimum
degreeismuchmorethan3.
Search
SearchissimilartosearchinBinarySearchTree.Letthekeytobesearchedbek.Westartfromrootand
recursivelytraversedown.Foreveryvisitednonleafnode,ifthenodehaskey,wesimplyreturnthenode.
Otherwisewerecurdowntotheappropriatechild(Thechildwhichisjustbeforethefirstgreaterkey)ofthe
node.Ifwereachaleafnodeanddontfindkintheleafnode,wereturnNULL.
Traverse
TraversalisalsosimilartoInordertraversalofBinaryTree.Westartfromtheleftmostchild,recursivelyprint
theleftmostchild,thenrepeatthesameprocessforremainingchildrenandkeys.Intheend,recursively
printtherightmostchild.
// C++ implemntation of search() and traverse() methods
#include<iostream>
using namespace std;
// A BTree node
class BTreeNode
{
int *keys; // An array of keys
int t;
// Constructor
// Make BTree friend of this so that we can access private members of this
// class in BTree functions
friend class BTree;
};
// A BTree
class BTree
{
BTreeNode *root; // Pointer to root node
int t; // Minimum degree
public:
// Constructor (Initializes tree as empty)
BTree(int _t)
{ root = NULL; t = _t; }
=======================================================================
ConvertagivenBinaryTreeto
DoublyLinkedList|Set1
GivenaBinaryTree(Bt),convertittoaDoublyLinkedList(DLL).Theleftandrightpointersinnodesareto
beusedaspreviousandnextpointersrespectivelyinconvertedDLL.TheorderofnodesinDLLmustbe
sameasInorderofthegivenBinaryTree.ThefirstnodeofInordertraversal(leftmostnodeinBT)mustbe
headnodeoftheDLL.
Icameacrossthisinterviewduringoneofmyinterviews.Asimilarproblemisdiscussedinthispost.The
problemhereissimpleraswedontneedtocreatecircularDLL,butasimpleDLL.Theideabehindits
solutionisquitesimpleandstraight.
1.Ifleftsubtreeexists,processtheleftsubtree
..1.a)RecursivelyconverttheleftsubtreetoDLL.
..1.b)Thenfindinorderpredecessorofrootinleftsubtree(inorderpredecessorisrightmostnodeinleft
subtree).
..1.c)Makeinorderpredecessoraspreviousofrootandrootasnextofinorderpredecessor.
2.Ifrightsubtreeexists,processtherightsubtree(Below3stepsaresimilartoleftsubtree).
..2.a)RecursivelyconverttherightsubtreetoDLL.
..2.b)Thenfindinordersuccessorofrootinrightsubtree(inordersuccessorisleftmostnodeinright
subtree).
..2.c)Makeinordersuccessorasnextofrootandrootaspreviousofinordersuccessor.
3.Findtheleftmostnodeandreturnit(theleftmostnodeisalwaysheadofconvertedDLL).
Belowisthesourcecodeforabovealgorithm.
// A C++ program for in-place conversion of Binary Tree to DLL
#include <stdio.h>
/* A binary tree node has data, and left and right pointers */
struct node
{
int data;
node* left;
node* right;
};
/* This is the core function to convert Tree to list. This function follows
steps 1 and 2 of the above algorithm */
node* bintree2listUtil(node* root)
{
// Base case
if (root == NULL)
return root;
return root;
}
// The main function that first calls bintree2listUtil(), then follows step 3
// of the above algorithm
node* bintree2list(node *root)
{
// Base case
if (root == NULL)
return root;
return (root);
}
new_node->data = data;
new_node->left = new_node->right = NULL;
return (new_node);
}
= newNode(10);
root->left
= newNode(12);
root->right
= newNode(15);
root->left->left = newNode(25);
root->left->right = newNode(30);
root->right->left = newNode(36);
// Convert to DLL
node *head = bintree2list(root);
return 0;
}
Output:
251230103615
=======================================================================
RemoveBSTkeysoutsidethegiven
range
GivenaBinarySearchTree(BST)andarange[min,max],removeallkeyswhichareoutsidethegiven
range.ThemodifiedtreeshouldalsobeBST.Forexample,considerthefollowingBSTandrange[10,13].
Thegiventreeshouldbechangedtofollowing.Notethatallkeysoutsidetherange[10,13]areremoved
andmodifiedtreeisBST.
Therearetwopossiblecasesforeverynode.
1)Nodeskeyisoutsidethegivenrange.Thiscasehastwosubcases.
.a)Nodeskeyissmallerthantheminvalue.
.b)Nodeskeyisgreaterthatthemaxvalue.
2)Nodeskeyisinrange.
Wedontneedtodoanythingforcase2.Incase1,weneedtoremovethenodeandchangerootof
subtreerootedwiththisnode.
TheideaistofixthetreeinPostorderfashion.Whenwevisitanode,wemakesurethatitsleftandright
subtreesarealreadyfixed.Incase1.a),wesimplyremoverootandreturnrightsubtreeasnewroot.In
case1.b),weremoverootandreturnleftsubtreeasnewroot.
FollowingisC++implementationoftheaboveapproach.
// A C++ program to remove BST keys outside the given range
#include<stdio.h>
#include <iostream>
// Resmoves all nodes having value outside the given range and returns the root
// of modified tree
node* removeOutsideRange(node *root, int min, int max)
{
// Base Case
if (root == NULL)
return NULL;
// Now fix the root. There are 2 possible cases for toot
// 1.a) Root's key is smaller than min value (root is not in range)
if (root->key < min)
{
node *rChild = root->right;
delete root;
return rChild;
}
// 1.b) Root's key is greater than max value (root is not in range)
if (root->key > max)
{
node *lChild = root->left;
delete root;
return lChild;
}
// 2. Root is in range
return root;
}
// A utility function to create a new BST node with key as given num
node* newNode(int num)
{
node* temp = new node;
temp->key = num;
temp->left = temp->right = NULL;
return temp;
}
return 0;
}
Output:
Inordertraversalofthegiventreeis:13867131415
Inordertraversalofthemodifiedtreeis:86713
TimeComplexity:O(n)wherenisthenumberofnodesingivenBST.
=======================================================================
ConstructCompleteBinaryTree
fromitsLinkedListRepresentation
GivenLinkedListRepresentationofCompleteBinaryTree,constructtheBinarytree.Acompletebinarytree
canberepresentedinanarrayinthefollowingapproach.
Ifrootnodeisstoredatindexi,itsleft,andrightchildrenarestoredatindices2*i+1,2*i+2respectively.
Supposetreeisrepresentedbyalinkedlistinsameway,howdoweconvertthisintonormallinked
representationofbinarytreewhereeverynodehasdata,leftandrightpointers?Inthelinkedlist
representation,wecannotdirectlyaccessthechildrenofthecurrentnodeunlesswetraversethelist.
Wearemainlygivenlevelordertraversalinsequentialaccessform.Weknowheadoflinkedlistisalwaysis
rootofthetree.Wetakethefirstnodeasrootandwealsoknowthatthenexttwonodesareleftandright
childrenofroot.SoweknowpartialBinaryTree.TheideaistodoLevelordertraversalofthepartiallybuilt
BinaryTreeusingqueueandtraversethelinkedlistatthesametime.Ateverystep,wetaketheparent
nodefromqueue,makenexttwonodesoflinkedlistaschildrenoftheparentnode,andenqueuethenext
twonodestoqueue.
1.Createanemptyqueue.
2.Makethefirstnodeofthelistasroot,andenqueueittothequeue.
3.Untilwereachtheendofthelist,dothefollowing.
a.Dequeueonenodefromthequeue.Thisisthecurrentparent.
b.Traversetwonodesinthelist,addthemaschildrenofthecurrentparent.
c.Enqueuethetwonodesintothequeue.
BelowisthecodewhichimplementsthesameinC++.
// C++ program to create a Complete Binary tree from its Linked List
// Representation
#include <iostream>
#include <string>
#include <queue>
using namespace std;
= new_node;
// method to create a new binary tree node from the given data
BinaryTreeNode* newBinaryTreeNode(int data)
{
BinaryTreeNode *temp = new BinaryTreeNode;
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
// converts a given linked list representing a complete binary tree into the
// linked representation of binary tree.
void convertList2Binary(ListNode *head, BinaryTreeNode* &root)
{
// queue to store the parent nodes
queue<BinaryTreeNode *> q;
// Base Case
if (head == NULL)
{
root = NULL; // Note that root is passed by reference
return;
}
// 1.) The first node is always the root node, and add it to the queue
root = newBinaryTreeNode(head->data);
q.push(root);
// 2.a) take the parent node from the q and remove it from q
BinaryTreeNode* parent = q.front();
q.pop();
// 2.c) take next two nodes from the linked list. We will add
// them as children of the current parent node in step 2.b. Push them
// into the queue so that they will be parents to the future nodes
BinaryTreeNode *leftChild = NULL, *rightChild = NULL;
leftChild = newBinaryTreeNode(head->data);
q.push(leftChild);
head = head->next;
if (head)
{
rightChild = newBinaryTreeNode(head->data);
q.push(rightChild);
head = head->next;
}
{
// create a linked list shown in above diagram
struct ListNode* head = NULL;
push(&head, 36); /* Last node of Linked List */
push(&head, 30);
push(&head, 25);
push(&head, 15);
push(&head, 12);
push(&head, 10); /* First node of Linked List */
BinaryTreeNode *root;
convertList2Binary(head, root);
cout << "Inorder Traversal of the constructed Binary Tree is: \n";
inorderTraversal(root);
return 0;
}
Output:
InorderTraversaloftheconstructedBinaryTreeis:
251230103615
TimeComplexity:TimecomplexityoftheabovesolutionisO(n)wherenisthenumberofnodes
=======================================================================
ReverseLevelOrderTraversal
Wehavediscussedlevelordertraversalofapostinpreviouspost.Theideaistoprintlastlevelfirst,then
secondlastlevel,andsoon.LikeLevelordertraversal,everylevelisprintedfromlefttoright.
ExampleTree
ReverseLevelordertraversaloftheabovetreeis45231.
Bothmethodsfornormallevelordertraversalcanbeeasilymodifiedtodoreverselevelordertraversal.
METHOD1(Recursivefunctiontoprintagivenlevel)
Wecaneasilymodifythemethod1ofthenormallevelordertraversal.Inmethod1,wehaveamethod
printGivenLevel()whichprintsagivenlevelnumber.Theonlythingweneedtochangeis,insteadofcalling
printGivenLevel()fromfirstleveltolastlevel,wecallitfromlastleveltofirstlevel.
// A recursive C program to print REVERSE level order traversal
#include <stdio.h>
#include <stdlib.h>
/* A binary tree node has data, pointer to left and right child */
struct node
{
int data;
struct node* left;
struct node* right;
};
/*Function protoypes*/
void printGivenLevel(struct node* root, int level);
int height(struct node* node);
struct node* newNode(int data);
{
int h = height(root);
int i;
for (i=h; i>=1; i--) //THE ONLY LINE DIFFERENT FROM NORMAL LEVEL ORDER
printGivenLevel(root, i);
}
else return(rheight+1);
}
}
return(node);
}
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
return 0;
}
Output:
LevelOrdertraversalofbinarytreeis
45231
TimeComplexity:TheworstcasetimecomplexityofthismethodisO(n^2).Foraskewedtree,
printGivenLevel()takesO(n)timewherenisthenumberofnodesintheskewedtree.Sotimecomplexityof
printLevelOrder()isO(n)+O(n1)+O(n2)+..+O(1)whichisO(n^2).
METHOD2(UsingQueueandStack)
Themethod2ofnormallevelordertraversalcanalsobeeasilymodifiedtoprintlevelordertraversalin
reverseorder.Theideaistouseastacktogetthereverselevelorder.Ifwedonormallevelordertraversal
andinsteadofprintinganode,pushthenodetoastackandthenprintcontentsofstack,weget54321
foraboveexampletree,butoutputshouldbe45231.Sotogetthecorrectsequence(lefttorightatevery
level),weprocesschildrenofanodeinreverseorder,wefirstpushtherightsubtreetostack,thenleft
subtree.
// A C++ program to print REVERSE level order traversal using stack and queue
// This approach is adopted from following link
// http://tech-queries.blogspot.in/2008/12/level-order-tree-traversal-in-reverse.html
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
/* A binary tree node has data, pointer to left and right children */
struct node
{
int data;
struct node* left;
struct node* right;
};
// Do something like normal level order traversal order. Following are the
// differences with normal level order traversal
// 1) Instead of printing a node, we push the node to stack
// 2) Right subtree is visited before left subtree
while (Q.empty() == false)
{
/* Dequeue node and make it root */
root = Q.front();
Q.pop();
S.push(root);
// Now pop all items from stack one by one and print them
while (S.empty() == false)
{
root = S.top();
cout << root->data << " ";
S.pop();
}
}
return (temp);
}
int main()
{
struct node *root = newNode(1);
root->left
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
return 0;
}
Output:
LevelOrdertraversalofbinarytreeis
4567231
TimeComplexity:O(n)wherenisnumberofnodesinthebinarytree.
=======================================================================
Findapairwithgivensumina
BalancedBST
GivenaBalancedBinarySearchTreeandatargetsum,writeafunctionthatreturnstrueifthereisapair
withsumequalstotargetsum,otherwisereturnfalse.ExpectedtimecomplexityisO(n)andonlyO(Logn)
extraspacecanbeused.AnymodificationtoBinarySearchTreeisnotallowed.Notethatheightofa
BalancedBSTisalwaysO(Logn).
Thisproblemismainlyextensionofthepreviouspost.HerewearenotallowedtomodifytheBST.
TheBruteForceSolutionistoconsidereachpairinBSTandcheckwhetherthesumequalstoX.Thetime
complexityofthissolutionwillbeO(n^2).
ABetterSolutionistocreateanauxiliaryarrayandstoreInordertraversalofBSTinthearray.Thearray
willbesortedasInordertraversalofBSTalwaysproducessorteddata.OncewehavetheInordertraversal,
wecanpairinO(n)time(Seethisfordetails).ThissolutionworksinO(n)time,butrequiresO(n)auxiliary
space.
Aspaceoptimizedsolutionisdiscussedinpreviouspost.TheideawastofirstinplaceconvertBSTto
DoublyLinkedList(DLL),thenfindpairinsortedDLLinO(n)time.ThissolutiontakesO(n)timeand
O(Logn)extraspace,butitmodifiesthegivenBST.
ThesolutiondiscussedbelowtakesO(n)time,O(Logn)spaceanddoesntmodifyBST.Theideais
sameasfindingthepairinsortedarray(Seemethod1ofthisfordetails).WetraverseBSTinNormal
InorderandReverseInordersimultaneously.Inreverseinorder,westartfromtherightmostnodewhichis
themaximumvaluenode.Innormalinorder,westartfromtheleftmostnodewhichisminimumvaluenode.
Weaddsumofcurrentnodesinbothtraversalsandcomparethissumwithgiventargetsum.Ifthesumis
sameastargetsum,wereturntrue.Ifthesumismorethantargetsum,wemovetonextnodeinreverse
inordertraversal,otherwisewemovetonextnodeinnormalinordertraversal.Ifanyofthetraversalsis
finishedwithoutfindingapair,wereturnfalse.FollowingisC++implementationofthisapproach.
/* In a balanced binary search tree isPairPresent two element which sums to
a given value time O(n) space O(logn) */
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100
// A BST node
struct node
{
int val;
struct node *left, *right;
};
// Stack type
struct Stack
{
int size;
int top;
struct node* *array;
};
// Returns true if a pair with target sum exists in BST, otherwise false
bool isPairPresent(struct node *root, int target)
{
// Create two stacks. s1 is used for normal inorder traversal
// and s2 is used for reverse inorder traversal
struct Stack* s1 = createStack(MAX_SIZE);
struct Stack* s2 = createStack(MAX_SIZE);
// Note the sizes of stacks is MAX_SIZE, we can find the tree size and
// fix stack size as O(Logn) for balanced trees like AVL and Red Black
// tree. We have used MAX_SIZE to keep the code simple
// done1, val1 and curr1 are used for normal inorder traversal using s1
// done2, val2 and curr2 are used for reverse inorder traversal using s2
bool done1 = false, done2 = false;
int val1 = 0, val2 = 0;
struct node *curr1 = root, *curr2 = root;
// The loop will break when we either find a pair or one of the two
// traversals is complete
while (1)
{
// Find next node in normal Inorder traversal. See following post
// http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion/
while (done1 == false)
{
if (curr1 != NULL)
{
push(s1, curr1);
curr1 = curr1->left;
}
else
{
if (isEmpty(s1))
done1 = 1;
else
{
curr1 = pop(s1);
val1 = curr1->val;
curr1 = curr1->right;
done1 = 1;
}
}
}
}
}
}
// If we find a pair, then print the pair and return. The first
// condition makes sure that two same values are not added
if ((val1 != val2) && (val1 + val2) == target)
{
printf("\n Pair Found: %d + %d = %d\n", val1, val2, target);
return true;
}
\
20
/ \
16 25*/
getchar();
return 0;
}
Output:
PairFound:8+25=33
=======================================================================
FindifthereisatripletinaBalanced
BSTthataddstozero
GivenaBalancedBinarySearchTree(BST),writeafunctionisTripletPresent()thatreturnstrueifthereisa
tripletingivenBSTwithsumequalsto0,otherwisereturnsfalse.ExpectedtimecomplexityisO(n^2)and
onlyO(Logn)extraspacecanbeused.YoucanmodifygivenBinarySearchTree.Notethatheightofa
BalancedBSTisalwaysO(Logn)
Forexample,isTripletPresent()shouldreturntrueforfollowingBSTbecausethereisatripletwithsum0,the
tripletis{13,6,7}.
TheBruteForceSolutionistoconsidereachtripletinBSTandcheckwhetherthesumaddsuptozero.
ThetimecomplexityofthissolutionwillbeO(n^3).
ABetterSolutionistocreateanauxiliaryarrayandstoreInordertraversalofBSTinthearray.Thearray
willbesortedasInordertraversalofBSTalwaysproducessorteddata.OncewehavetheInordertraversal,
wecanusemethod2ofthisposttofindthetripletwithsumequalsto0.ThissolutionworksinO(n^2)time,
butrequiresO(n)auxiliaryspace.
FollowingisthesolutionthatworksinO(n^2)timeandusesO(Logn)extraspace:
1)ConvertgivenBSTtoDoublyLinkedList(DLL)
2)NowiteratethrougheverynodeofDLLandifthekeyofnodeisnegative,thenfindapairinDLLwithsum
equaltokeyofcurrentnodemultipliedby1.Tofindthepair,wecanusetheapproachusedin
hasArrayTwoCandidates()inmethod1ofthispost.
// A C++ program to check if there is a triplet with sum equal to 0 in
// a given BST
#include<stdio.h>
{
int key;
struct node *left;
struct node *right;
};
// A function to convert given BST to Doubly Linked List. left pointer is used
// as previous pointer and right pointer is used as next pointer. The function
// sets *head to point to first and *tail to point to last node of converted DLL
void convertBSTtoDLL(node* root, node** head, node** tail)
{
// Base case
if (root == NULL)
return;
// If tail is not NULL, then set right of tail as root, else current
// node is head
if (*tail)
(*tail)->right = root;
else
*head = root;
// Update tail
*tail = root;
// This function returns true if there is pair in DLL with sum equal
// to given sum. The algorithm is similar to hasArrayTwoCandidates()
// in method 1 of http://tinyurl.com/dy6palr
bool isPresentInDLL(node* head, node* tail, int sum)
{
while (head != tail)
{
int curr = head->key + tail->key;
if (curr == sum)
return true;
else if (curr > sum)
tail = tail->left;
else
head = head->right;
}
return false;
}
// Convert given BST to doubly linked list. head and tail store the
// pointers to first and last nodes in DLLL
node* head = NULL;
node* tail = NULL;
convertBSTtoDLL(root, &head, &tail);
// Now iterate through every node and find if there is a pair with sum
// equal to -1 * heaf->key where head is current node
while ((head->right != tail) && (head->key < 0))
{
// If there is a pair with sum equal to -1*head->key, then return
// A utility function to create a new BST node with key as given num
node* newNode(int num)
{
node* temp = new node;
temp->key = num;
temp->left = temp->right = NULL;
return temp;
}
Present
NotethattheabovesolutionmodifiesgivenBST.
TimeComplexity:TimetakentoconvertBSTtoDLLisO(n)andtimetakentofindtripletinDLLisO(n^2).
AuxiliarySpace:Theauxiliaryspaceisneededonlyforfunctioncallstackinrecursivefunction
convertBSTtoDLL().Sincegiventreeisbalanced(heightisO(Logn)),thenumberoffunctionsincallstack
willneverbemorethanO(Logn).
=======================================================================
IterativePostorderTraversal|Set2
(UsingOneStack)
Wehavediscussedasimpleiterativepostordertraversalusingtwostacksinthepreviouspost.Inthispost,
anapproachwithonlyonestackisdiscussed.
Theideaistomovedowntoleftmostnodeusingleftpointer.Whilemovingdown,pushrootandrootsright
childtostack.Oncewereachleftmostnode,printitifitdoesnthavearightchild.Ifithasarightchild,then
changerootsothattherightchildisprocessedbefore.
Followingisdetailedalgorithm.
1.1Createanemptystack
2.1DofollowingwhilerootisnotNULL
a)Pushroot'srightchildandthenroottostack.
b)Setrootasroot'sleftchild.
2.2Popanitemfromstackandsetitasroot.
a)Ifthepoppeditemhasarightchildandtherightchild
isattopofstack,thenremovetherightchildfromstack,
pushtherootbackandsetrootasroot'srightchild.
b)Elseprintroot'sdataandsetrootasNULL.
2.3Repeatsteps2.1and2.2whilestackisnotempty.
Letusconsiderthefollowingtree
Followingarethestepstoprintpostordertraversaloftheabovetreeusingonestack.
1.Rightchildof1exists.
Push3tostack.Push1tostack.Movetoleftchild.
Stack:3,1
2.Rightchildof2exists.
Push5tostack.Push2tostack.Movetoleftchild.
Stack:3,1,5,2
3.Rightchildof4doesn'texist.'
Push4tostack.Movetoleftchild.
Stack:3,1,5,2,4
4.CurrentnodeisNULL.
Pop4fromstack.Rightchildof4doesn'texist.
Print4.SetcurrentnodetoNULL.
Stack:3,1,5,2
5.CurrentnodeisNULL.
Pop2fromstack.Sincerightchildof2equalsstacktopelement,
pop5fromstack.Nowpush2tostack.
Movecurrentnodetorightchildof2i.e.5
Stack:3,1,2
6.Rightchildof5doesn'texist.Push5tostack.Movetoleftchild.
Stack:3,1,2,5
7.CurrentnodeisNULL.Pop5fromstack.Rightchildof5doesn'texist.
Print5.SetcurrentnodetoNULL.
Stack:3,1,2
8.CurrentnodeisNULL.Pop2fromstack.
Rightchildof2isnotequaltostacktopelement.
Print2.SetcurrentnodetoNULL.
Stack:3,1
9.CurrentnodeisNULL.Pop1fromstack.
Sincerightchildof1equalsstacktopelement,pop3fromstack.
Nowpush1tostack.Movecurrentnodetorightchildof1i.e.3
Stack:1
10.RepeatthesameasabovestepsandPrint6,7and3.
Pop1andPrint1.
// C program for iterative postorder traversal using one stack
#include <stdio.h>
#include <stdlib.h>
// A tree node
struct Node
{
int data;
struct Node *left, *right;
};
// Stack type
struct Stack
{
int size;
int top;
struct Node* *array;
};
if (isFull(stack))
return;
stack->array[++stack->top] = node;
}
// If the popped item has a right child and the right child is not
// processed yet, then make sure right child is processed before root
if (root->right && peek(stack) == root->right)
{
pop(stack); // remove right child from stack
push(stack, root); // push root back to stack
root = root->right; // change root so that the right
// child is processed next
}
else // Else print root's data and set root as NULL
{
printf("%d ", root->data);
root = NULL;
}
} while (!isEmpty(stack));
}
postOrderIterative(root);
return 0;
}
Output:
4526731
=======================================================================
IterativePostorderTraversal|Set1
(UsingTwoStacks)
Wehavediscussediterativeinorderanditerativepreordertraversals.Inthispost,iterativepostorder
traversalisdiscussedwhichismorecomplexthantheothertwotraversals(duetoitsnatureofnontail
recursion,thereisanextrastatementafterthefinalrecursivecalltoitself).Thepostordertraversalcan
easilybedoneusingtwostacksthough.Theideaistopushreversepostordertraversaltoastack.Oncewe
havereversepostordertraversalinastack,wecanjustpopallitemsonebyonefromthestackandprint
them,thisorderofprintingwillbeinpostorderbecauseofLIFOpropertyofstacks.Nowthequestionis,how
togetreversepostorderelementsinastacktheotherstackisusedforthispurpose.Forexample,inthe
followingtree,weneedtoget1,3,7,6,2,5,4inastack.Iftakeacloserlookatthissequence,wecan
observethatthissequenceisverysimilartopreordertraversal.Theonlydifferenceisrightchildisvisited
beforeleftchildandthereforesequenceisrootrightleftinsteadofrootleftright.Sowecandosomething
likeiterativepreordertraversalwithfollowingdifferences.
a)Insteadofprintinganitem,wepushittoastack.
b)Wepushleftsubtreebeforerightsubtree.
Followingisthecompletealgorithm.Afterstep2,wegetreversepostordertraversalinsecondstack.We
usefirststacktogetthisorder.
1.Pushroottofirststack.
2.Loopwhilefirststackisnotempty
2.1Popanodefromfirststackandpushittosecondstack
2.2Pushleftandrightchildrenofthepoppednodetofirststack
3.Printcontentsofsecondstack
Letusconsiderthefollowingtree
Followingarethestepstoprintpostordertraversaloftheabovetreeusingtwostacks.
1.Push1tofirststack.
Firststack:1
Secondstack:Empty
2.Pop1fromfirststackandpushittosecondstack.
Pushleftandrightchildrenof1tofirststack
Firststack:2,3
Secondstack:1
3.Pop3fromfirststackandpushittosecondstack.
Pushleftandrightchildrenof3tofirststack
Firststack:2,6,7
Secondstack:1,3
4.Pop7fromfirststackandpushittosecondstack.
Firststack:2,6
Secondstack:1,3,7
5.Pop6fromfirststackandpushittosecondstack.
Firststack:2
Secondstack:1,3,7,6
6.Pop2fromfirststackandpushittosecondstack.
Pushleftandrightchildrenof2tofirststack
Firststack:4,5
Secondstack:1,3,7,6,2
7.Pop5fromfirststackandpushittosecondstack.
Firststack:4
Secondstack:1,3,7,6,2,5
8.Pop4fromfirststackandpushittosecondstack.
Firststack:Empty
Secondstack:1,3,7,6,2,5,4
Thealgorithmstopssincethereisnomoreiteminfirststack.
Observethatcontentofsecondstackisinpostorderfashion.Printthem.
FollowingisCimplementationofiterativepostordertraversalusingtwostacks.
#include <stdio.h>
#include <stdlib.h>
// A tree node
struct Node
{
int data;
struct Node *left, *right;
};
// Stack type
struct Stack
{
int size;
int top;
struct Node* *array;
};
{
struct Node* node = (struct Node*) malloc(sizeof(struct Node));
node->data = data;
node->left = node->right = NULL;
return node;
}
return stack->array[stack->top--];
}
int main()
{
// Let us construct the tree shown in above figure
struct Node* root = NULL;
root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
postOrderIterative(root);
return 0;
}
Output:
4526731
=======================================================================
DynamicProgramming|Set26
(LargestIndependentSetProblem)
GivenaBinaryTree,findsizeoftheLargestIndependentSet(LIS)init.Asubsetofalltreenodesisan
independentsetifthereisnoedgebetweenanytwonodesofthesubset.
Forexample,considerthefollowingbinarytree.Thelargestindependentset(LIS)is{10,40,60,70,80}and
sizeoftheLISis5.
ADynamicProgrammingsolutionsolvesagivenproblemusingsolutionsofsubproblemsinbottomup
manner.Canthegivenproblembesolvedusingsolutionstosubproblems?Ifyes,thenwhatarethe
subproblems?Canwefindlargestindependentsetsize(LISS)foranodeXifweknowLISSforall
descendantsofX?IfanodeisconsideredaspartofLIS,thenitschildrencannotbepartofLIS,butits
grandchildrencanbe.Followingisoptimalsubstructureproperty.
1)OptimalSubstructure:
LetLISS(X)indicatessizeoflargestindependentsetofatreewithrootX.
LISS(X)=MAX{(1+sumofLISSforallgrandchildrenofX),
(sumofLISSforallchildrenofX)}
Theideaissimple,therearetwopossibilitiesforeverynodeX,eitherXisamemberofthesetornota
member.IfXisamember,thenthevalueofLISS(X)is1plusLISSofallgrandchildren.IfXisnota
member,thenthevalueissumofLISSofallchildren.
2)OverlappingSubproblems
Followingisrecursiveimplementationthatsimplyfollowstherecursivestructurementionedabove.
// A naive recursive implementation of Largest Independent Set problem
#include <stdio.h>
#include <stdlib.h>
/* A binary tree node has data, pointer to left child and a pointer to
right child */
struct node
{
int data;
struct node *left, *right;
};
= newNode(20);
root->left
= newNode(8);
root->left->left
= newNode(4);
root->left->right
= newNode(12);
root->left->right->left
= newNode(10);
root->left->right->right = newNode(14);
root->right
= newNode(22);
root->right->right
= newNode(25);
return 0;
}
Output:
SizeoftheLargestIndependentSetis5
Timecomplexityoftheabovenaiverecursiveapproachisexponential.Itshouldbenotedthattheabove
functioncomputesthesamesubproblemsagainandagain.Forexample,LISSofnodewithvalue50is
evaluatedfornodewithvalues10and20as50isgrandchildof10andchildof20.
Sincesamesuproblemsarecalledagain,thisproblemhasOverlappingSubprolemsproperty.SoLISS
problemhasbothproperties(seethisandthis)ofadynamicprogrammingproblem.Likeothertypical
DynamicProgramming(DP)problems,recomputationsofsamesubproblemscanbeavoidedbystoringthe
solutionstosubproblemsandsolvingproblemsinbottomupmanner.
FollowingisCimplementationofDynamicProgrammingbasedsolution.Inthefollowingsolution,an
additionalfieldlissisaddedtotreenodes.Theinitialvalueoflississetas0forallnodes.Therecursive
functionLISS()calculateslissforanodeonlyifitisnotalreadyset.
/* Dynamic programming based program for Largest Independent Set problem */
#include <stdio.h>
#include <stdlib.h>
/* A binary tree node has data, pointer to left child and a pointer to
right child */
struct node
{
int data;
int liss;
struct node *left, *right;
};
if (root->liss)
return root->liss;
return root->liss;
}
= newNode(20);
root->left
= newNode(8);
root->left->left
= newNode(4);
root->left->right
= newNode(12);
root->left->right->left
= newNode(10);
root->left->right->right = newNode(14);
root->right
= newNode(22);
root->right->right
= newNode(25);
return 0;
}
Output
SizeoftheLargestIndependentSetis5
TimeComplexity:O(n)wherenisthenumberofnodesingivenBinarytree.
Followingextensionstoabovesolutioncanbetriedasanexercise.
1)Extendtheabovesolutionfornarytree.
2)Theabovesolutionmodifiesthegiventreestructurebyaddinganadditionalfieldlisstotreenodes.
Extendthesolutionsothatitdoesntmodifythetreestructure.
3)TheabovesolutiononlyreturnssizeofLIS,itdoesntprintelementsofLIS.Extendthesolutiontoprintall
nodesthatarepartofLIS.
=======================================================================
SegmentTree|Set2(Range
MinimumQuery)
Wehaveintroducedsegmenttreewithasimpleexampleinthepreviouspost.Inthispost,RangeMinimum
QueryproblemisdiscussedasanotherexamplewhereSegmentTreecanbeused.Followingisproblem
statement.
Wehaveanarrayarr[0...n1].Weshouldbeabletoefficientlyfindtheminimumvaluefromindexqs
(querystart)toqe(queryend)where0<=qs<=qe<=n1.Thearrayisstatic(elementsarenotdeletedand
insertedduringtheseriesofqueries).
Asimplesolutionistorunaloopfromqstoqeandfindminimumelementingivenrange.Thissolution
takesO(n)timeinworstcase.
Anothersolutionistocreatea2Darraywhereanentry[i,j]storestheminimumvalueinrangearr[i..j].
MinimumofagivenrangecannowbecalculatedinO(1)time,butpreprocessingtakesO(n^2)time.Also,
thisapproachneedsO(n^2)extraspacewhichmaybecomehugeforlargeinputarrays.
Segmenttreecanbeusedtodopreprocessingandqueryinmoderatetime.Withsegmenttree,
preprocessingtimeisO(n)andtimetoforrangeminimumqueryisO(Logn).Theextraspacerequiredis
O(n)tostorethesegmenttree.
RepresentationofSegmenttrees
1.LeafNodesaretheelementsoftheinputarray.
2.Eachinternalnoderepresentsminimumofallleavesunderit.
AnarrayrepresentationoftreeisusedtorepresentSegmentTrees.Foreachnodeatindexi,theleftchildis
atindex2*i+1,rightchildat2*i+2andtheparentisat
ConstructionofSegmentTreefromgivenarray
Westartwithasegmentarr[0...n1].andeverytimewedividethecurrentsegmentintotwohalves(ifithas
notyetbecomeasegmentoflength1),andthencallthesameprocedureonbothhalves,andforeachsuch
segment,westoretheminimumvalueinasegmenttreenode.
Alllevelsoftheconstructedsegmenttreewillbecompletelyfilledexceptthelastlevel.Also,thetreewillbe
aFullBinaryTreebecausewealwaysdividesegmentsintwohalvesateverylevel.Sincetheconstructed
treeisalwaysfullbinarytreewithnleaves,therewillben1internalnodes.Sototalnumberofnodeswillbe
2*n1.
Heightofthesegmenttreewillbe
.Sincethetreeisrepresentedusingarrayandrelation
betweenparentandchildindexesmustbemaintained,sizeofmemoryallocatedforsegmenttreewillbe
.
Queryforminimumvalueofgivenrange
Oncethetreeisconstructed,howtodorangeminimumqueryusingtheconstructedsegmenttree.
Followingisalgorithmtogettheminimum.
//qs>querystartindex,qe>queryendindex
intRMQ(node,qs,qe)
{
ifrangeofnodeiswithinqsandqe
returnvalueinnode
elseifrangeofnodeiscompletelyoutsideqsandqe
returnINFINITE
else
returnmin(RMQ(node'sleftchild,qs,qe),RMQ(node'srightchild,qs,qe))
}
Implementation:
// Program for range minimum query using segment tree
#include <stdio.h>
#include <math.h>
#include <limits.h>
return INT_MAX;
// If there are more than one elements, then recur for left and
// right subtrees and store the minimum of two values in this node
int mid = getMid(ss, se);
return 0;
}
Output:
Minimumofvaluesinrange[1,5]is=2
TimeComplexity:
TimeComplexityfortreeconstructionisO(n).Therearetotal2n1nodes,andvalueofeverynodeis
calculatedonlyonceintreeconstruction.
TimecomplexitytoqueryisO(Logn).Toqueryarangeminimum,weprocessatmosttwonodesatevery
levelandnumberoflevelsisO(Logn).
=======================================================================
SegmentTree|Set1(Sumofgiven
range)
LetusconsiderthefollowingproblemtounderstandSegmentTrees.
Wehaveanarrayarr[0...n1].Weshouldbeableto
1Findthesumofelementsfromindexltorwhere0<=l<=r<=n1
2Changevalueofaspecifiedelementofthearrayarr[i]=xwhere0<=i<=n1.
Asimplesolutionistorunaloopfromltorandcalculatesumofelementsingivenrange.Toupdatea
value,simplydoarr[i]=x.ThefirstoperationtakesO(n)timeandsecondoperationtakesO(1)time.
Anothersolutionistocreateanotherarrayandstoresumfromstarttoiattheithindexinthisarray.Sum
ofagivenrangecannowbecalculatedinO(1)time,butupdateoperationtakesO(n)timenow.Thisworks
wellifthenumberofqueryoperationsarelargeandveryfewupdates.
Whatifthenumberofqueryandupdatesareequal?CanweperformboththeoperationsinO(logn)
timeoncegiventhearray?WecanuseaSegmentTreetodobothoperationsinO(Logn)time.
RepresentationofSegmenttrees
1.LeafNodesaretheelementsoftheinputarray.
2.Eachinternalnoderepresentssomemergingoftheleafnodes.Themergingmaybedifferentfordifferent
problems.Forthisproblem,mergingissumofleavesunderanode.
AnarrayrepresentationoftreeisusedtorepresentSegmentTrees.Foreachnodeatindexi,theleftchildis
atindex2*i+1,rightchildat2*i+2andtheparentisat
ConstructionofSegmentTreefromgivenarray
Westartwithasegmentarr[0...n1].andeverytimewedividethecurrentsegmentintotwohalves(ifithas
notyetbecomeasegmentoflength1),andthencallthesameprocedureonbothhalves,andforeachsuch
segmentwestorethesumincorrespondingnode.
Alllevelsoftheconstructedsegmenttreewillbecompletelyfilledexceptthelastlevel.Also,thetreewillbe
aFullBinaryTreebecausewealwaysdividesegmentsintwohalvesateverylevel.Sincetheconstructed
treeisalwaysfullbinarytreewithnleaves,therewillben1internalnodes.Sototalnumberofnodeswillbe
2*n1.
Heightofthesegmenttreewillbe
.Sincethetreeisrepresentedusingarrayandrelation
betweenparentandchildindexesmustbemaintained,sizeofmemoryallocatedforsegmenttreewillbe
.
QueryforSumofgivenrange
Oncethetreeisconstructed,howtogetthesumusingtheconstructedsegmenttree.Followingisalgorithm
togetthesumofelements.
intgetSum(node,l,r)
{
ifrangeofnodeiswithinlandr
returnvalueinnode
elseifrangeofnodeiscompletelyoutsidelandr
return0
else
returngetSum(node'sleftchild,l,r)+
getSum(node'srightchild,l,r)
}
Updateavalue
Liketreeconstructionandqueryoperations,updatecanalsobedonerecursively.Wearegivenanindex
whichneedstoupdated.Letdiffbethevaluetobeadded.Westartfromrootofthesegmenttree,andadd
difftoallnodeswhichhavegivenindexintheirrange.Ifanodedoesnthavegivenindexinitsrange,we
dontmakeanychangestothatnode.
Implementation:
Followingisimplementationofsegmenttree.Theprogramimplementsconstructionofsegmenttreeforany
givenarray.Italsoimplementsqueryandupdateoperations.
// Program to show segment tree operations like construction, query and update
#include <stdio.h>
#include <math.h>
/* A recursive function to get the sum of values in given range of the array.
The following are parameters for this function.
/* A recursive function to update the nodes which have the given index in
their range. The following are parameters
st, index, ss and se are same as getSumUtil()
i --> index of the element to be updated. This index is in input array.
diff --> Value to be added to all nodes which have i in range */
void updateValueUtil(int *st, int ss, int se, int i, int diff, int index)
{
// Base Case: If the input index lies outside the range of this segment
if (i < ss || i > se)
return;
// If the input index is in range of this node, then update the value
// of the node and its children
st[index] = st[index] + diff;
if (se != ss)
{
int mid = getMid(ss, se);
updateValueUtil(st, ss, mid, i, diff, 2*index + 1);
updateValueUtil(st, mid+1, se, i, diff, 2*index + 2);
}
}
{
// If there is one element in array, store it in current node of
// segment tree and return
if (ss == se)
{
st[si] = arr[ss];
return arr[ss];
}
// If there are more than one elements, then recur for left and
// right subtrees and store the sum of values in this node
int mid = getMid(ss, se);
st[si] = constructSTUtil(arr, ss, mid, st, si*2+1) +
constructSTUtil(arr, mid+1, se, st, si*2+2);
return st[si];
}
return 0;
}
Output:
Sumofvaluesingivenrange=15
Updatedsumofvaluesingivenrange=22
TimeComplexity:
TimeComplexityfortreeconstructionisO(n).Therearetotal2n1nodes,andvalueofeverynodeis
calculatedonlyonceintreeconstruction.
TimecomplexitytoqueryisO(Logn).Toqueryasum,weprocessatmostfournodesateveryleveland
numberoflevelsisO(Logn).
ThetimecomplexityofupdateisalsoO(Logn).Toupdatealeafvalue,weprocessonenodeateverylevel
andnumberoflevelsisO(Logn).
=======================================================================
TernarySearchTree
Aternarysearchtreeisaspecialtriedatastructurewherethechildnodesofastandardtrieareorderedas
abinarysearchtree.
Representationofternarysearchtrees:
Unliketrie(standard)datastructurewhereeachnodecontains26pointersforitschildren,eachnodeina
ternarysearchtreecontainsonly3pointers:
1.Theleftpointerpointstothenodewhosevalueislessthanthevalueinthecurrentnode.
2.Theequalpointerpointstothenodewhosevalueisequaltothevalueinthecurrentnode.
3.Therightpointerpointstothenodewhosevalueisgreaterthanthevalueinthecurrentnode.
Apartfromabovethreepointers,eachnodehasafieldtoindicatedata(characterincaseofdictionary)and
anotherfieldtomarkendofastring.
So,moreorlessitissimilartoBSTwhichstoresdatabasedonsomeorder.However,datainaternary
searchtreeisdistributedoverthenodes.e.g.Itneeds4nodestostorethewordGeek.
Belowfigureshowshowexactlythewordsinaternarysearchtreearestored?
Oneoftheadvantageofusingternarysearchtreesovertriesisthatternarysearchtreesareamorespace
efficient(involveonlythreepointerspernodeascomparedto26instandardtries).Further,ternarysearch
treescanbeusedanytimeahashtablewouldbeusedtostorestrings.
Triesaresuitablewhenthereisaproperdistributionofwordsoverthealphabetssothatspacesareutilized
mostefficiently.Otherwiseternarysearchtreesarebetter.Ternarysearchtreesareefficienttouse(interms
ofspace)whenthestringstobestoredshareacommonprefix.
Applicationsofternarysearchtrees:
1.TernarysearchtreesareefficientforquerieslikeGivenaword,findthenextwordin
dictionary(nearneighborlookups)orFindalltelephonenumbersstartingwith9342ortypingfewstarting
charactersinawebbrowserdisplaysallwebsitenameswiththisprefix(Autocompletefeature).
2.Usedinspellchecks:Ternarysearchtreescanbeusedasadictionarytostoreallthewords.Oncethe
wordistypedinaneditor,thewordcanbeparallelysearchedintheternarysearchtreetocheckforcorrect
spelling.
Implementation:
FollowingisCimplementationofternarysearchtree.Theoperationsimplementedare,search,insertand
traversal.
// C program to demonstrate Ternary Search Tree (TST) insert, travese
// and search operations
#include <stdio.h>
#include <stdlib.h>
#define MAX 50
if (!(*root))
*root = newNode(*word);
buffer[depth+1] = '\0';
printf( "%s\n", buffer);
}
else
{
if (*(word+1) == '\0')
return root->isEndOfString;
insert(&root, "cat");
insert(&root, "cats");
insert(&root, "up");
insert(&root, "bug");
return 0;
}
Output:
Followingistraversalofternarysearchtree
bug
cat
cats
up
Followingaresearchresultsforcats,buandcatrespectively
Found
NotFound
Found
TimeComplexity:Thetimecomplexityoftheternarysearchtreeoperationsissimilartothatofbinary
searchtree.i.e.theinsertion,deletionandsearchoperationstaketimeproportionaltotheheightofthe
ternarysearchtree.Thespaceisproportionaltothelengthofthestringtobestored.
=======================================================================
Linkedcompletebinarytree&its
creation
Acompletebinarytreeisabinarytreewhereeachlevellexceptthelasthas2^lnodesandthenodesat
thelastlevelareallleftaligned.Completebinarytreesaremainlyusedinheapbaseddatastructures.
Thenodesinthecompletebinarytreeareinsertedfromlefttorightinonelevelatatime.Ifalevelisfull,the
nodeisinsertedinanewlevel.
Belowaresomeofthecompletebinarytrees.
1
/\
23
1
/\
23
/\/
456
Belowbinarytreesarenotcomplete:
1
/\
23
//
45
1
/\
23
/\/
456
/
7
Completebinarytreesaregenerallyrepresentedusingarrays.Thearrayrepresentationisbetterbecauseit
doesntcontainanyemptyslot.Givenparentindexi,itsleftchildisgivenby2*i+1anditsrightchildis
givenby2*i+2.Sonoextraspaceiswastedandspacetostoreleftandrightpointersissaved.However,
itmaybeaninterestingprogrammingquestiontocreatedaCompleteBinaryTreeusinglinked
representation.HereLinkedmeananonarrayrepresentationwhereleftandrightpointers(orreferences)
areusedtoreferleftandrightchildrenrespectively.Howtowriteaninsertfunctionthatalwaysaddsanew
nodeinthelastlevelandattheleftmostavailableposition?
Tocreatealinkedcompletebinarytree,weneedtokeeptrackofthenodesinalevelorderfashionsuch
thatthenextnodetobeinsertedliesintheleftmostposition.Aqueuedatastructurecanbeusedtokeep
trackoftheinsertednodes.
FollowingarestepstoinsertanewnodeinCompleteBinaryTree.
1.Ifthetreeisempty,initializetherootwithnewnode.
2.Else,getthefrontnodeofthequeue.
.Iftheleftchildofthisfrontnodedoesntexist,settheleftchildasthenewnode.
.elseiftherightchildofthisfrontnodedoesntexist,settherightchildasthenewnode.
3.Ifthefrontnodehasboththeleftchildandrightchild,Dequeue()it.
4.Enqueue()thenewnode.
Belowistheimplementation:
// Program for linked implementation of complete binary tree
#include <stdio.h>
#include <stdlib.h>
// A tree node
struct node
{
int data;
struct node *right,*left;
};
// A queue node
struct Queue
{
int front, rear;
int size;
struct node* *array;
};
int i;
for (i = 0; i < size; ++i)
queue->array[i] = NULL;
return queue;
}
queue->array[++queue->rear] = root;
if (isEmpty(queue))
++queue->front;
}
if (hasOnlyOneItem(queue))
queue->front = queue->rear = -1;
else
++queue->front;
return temp;
}
// A utility function to check if a tree node has both left and right children
int hasBothChild(struct node* temp)
{
return temp && temp->left && temp->right;
}
else
{
// get the front node of the queue.
struct node* front = getFront(queue);
// If the left child of this front node doesnt exist, set the
// left child as the new node
if (!front->left)
front->left = temp;
// If the right child of this front node doesnt exist, set the
// right child as the new node
else if (!front->right)
front->right = temp;
// If the front node has both the left child and right child,
// Dequeue() it.
if (hasBothChild(front))
Dequeue(queue);
}
Enqueue(root, queue);
while (!isEmpty(queue))
{
struct node* temp = Dequeue(queue);
if (temp->left)
Enqueue(temp->left, queue);
if (temp->right)
Enqueue(temp->right, queue);
}
}
levelOrder(root);
return 0;
}
Output:
123456789101112
=======================================================================
MorristraversalforPreorder
UsingMorrisTraversal,wecantraversethetreewithoutusingstackandrecursion.Thealgorithmfor
PreorderisalmostsimilartoMorristraversalforInorder.
1...Ifleftchildisnull,printthecurrentnodedata.Movetorightchild.
.Else,Maketherightchildoftheinorderpredecessorpointtothecurrentnode.Twocasesarise:
a)Therightchildoftheinorderpredecessoralreadypointstothecurrentnode.Setrightchildto
NULL.Movetorightchildofcurrentnode.
b)TherightchildisNULL.Setittocurrentnode.Printcurrentnodesdataandmovetoleftchildof
currentnode.
2...IterateuntilcurrentnodeisnotNULL.
FollowingisCimplementationoftheabovealgorithm.
// C program for Morris Preorder traversal
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *left, *right;
};
}
}
}
root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
root->left->left->left = newNode(8);
root->left->left->right = newNode(9);
root->left->right->left = newNode(10);
root->left->right->right = newNode(11);
morrisTraversalPreorder(root);
printf("\n");
preorder(root);
return 0;
}
Output:
1248951011367
1248951011367
Limitations:
Morristraversalmodifiesthetreeduringtheprocess.Itestablishestherightlinkswhilemovingdownthe
treeandresetstherightlinkswhilemovingupthetree.Sothealgorithmcannotbeappliedifwrite
operationsarenotallowed.
=======================================================================
ConvertaBSTtoaBinaryTreesuch
thatsumofallgreaterkeysisadded
toeverykey
GivenaBinarySearchTree(BST),convertittoaBinaryTreesuchthateverykeyoftheoriginalBSTis
changedtokeyplussumofallgreaterkeysinBST.
Examples:
Input:RootoffollowingBST
5
/\
213
Output:ThegivenBSTisconvertedtofollowingBinaryTree
18
/\
2013
Source:ConvertaBST
Solution:DoreverseInoordertraversal.Keeptrackofthesumofnodesvisitedsofar.Letthissumbesum.
Foreverynodecurrentlybeingvisited,firstaddthekeyofthisnodetosum,i.e.sum=sum+node>key.
Thenchangethekeyofcurrentnodetosum,i.e.,node>key=sum.
WhenaBSTisbeingtraversedinreverseInorder,foreverykeycurrentlybeingvisited,allkeysthatare
alreadyvisitedareallgreaterkeys.
// Program to change a BST to Binary Tree such that key of a node becomes
// original key plus sum of all greater keys in BST
#include <stdio.h>
#include <stdlib.h>
/* Helper function that allocates a new node with the given key and
NULL left and right pointers.*/
struct node* newNode(int key)
{
struct node* node = (struct node*)malloc(sizeof(struct node));
node->key = key;
node->left = NULL;
node->right = NULL;
return (node);
}
// A recursive function that traverses the given BST in reverse inorder and
// for every key, adds all greater keys to it
void addGreaterUtil(struct node *root, int *sum_ptr)
{
// Base Case
if (root == NULL)
return;
5
/
2 13 */
node *root = newNode(5);
root->left = newNode(2);
root->right = newNode(13);
addGreater(root);
return 0;
}
Output:
Inordertraversalofthegiventree
2513
Inordertraversalofthemodifiedtree
201813
TimeComplexity:O(n)wherenisthenumberofnodesingivenBinarySearchTree.
=======================================================================
IterativePreorderTraversal
GivenaBinaryTree,writeaniterativefunctiontoprintPreordertraversalofthegivenbinarytree.
ReferthisforrecursivepreordertraversalofBinaryTree.Toconvertaninherentlyrecursiveproceduresto
iterative,weneedanexplicitstack.FollowingisasimplestackbasediterativeprocesstoprintPreorder
traversal.
1)CreateanemptystacknodeStackandpushrootnodetostack.
2)DofollowingwhilenodeStackisnotempty.
.a)Popanitemfromstackandprintit.
.b)Pushrightchildofpoppeditemtostack
.c)Pushleftchildofpoppeditemtostack
Rightchildispushedbeforeleftchildtomakesurethatleftsubtreeisprocessedfirst.
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <stack>
/* A binary tree node has data, left child and right child */
struct node
{
int data;
struct node* left;
struct node* right;
};
/* Helper function that allocates a new node with the given data and
NULL left and right pointers.*/
struct node* newNode(int data)
{
struct node* node = new struct node;
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
nodeStack.push(root);
/* Pop all items one by one. Do following for every popped item
a) print it
b) push its right child
c) push its left child
Note that right child is pushed first so that left is processed first */
while (nodeStack.empty() == false)
{
// Pop the top item from stack and print it
struct node *node = nodeStack.top();
printf ("%d ", node->data);
nodeStack.pop();
/ \
3 5 2
*/
struct node *root = newNode(10);
root->left
= newNode(8);
root->right
= newNode(2);
root->left->left = newNode(3);
root->left->right = newNode(5);
root->right->left = newNode(2);
iterativePreorder(root);
return 0;
}
Output:
1083522
=======================================================================
FloorandCeilfromaBST
Therearenumerousapplicationsweneedtofindfloor(ceil)valueofakeyinabinarysearchtreeorsorted
array.Forexample,considerdesigningmemorymanagementsysteminwhichfreenodesarearrangedin
BST.Findbestfitfortheinputrequest.
CeilValueNode:Nodewithsmallestdatalargerthanorequaltokeyvalue.
Imaginewearemovingdownthetree,andassumewearerootnode.Thecomparisonyieldsthree
possibilities,
A)Rootdataisequaltokey.Wearedone,rootdataisceilvalue.
B)Rootdata<keyvalue,certainlytheceilvaluecantbeinleftsubtree.Proceedtosearchonrightsubtree
asreducedprobleminstance.
C)Rootdata>keyvalue,theceilvaluemaybeinleftsubtree.Wemayfindanodewithislargerdatathan
keyvalueinleftsubtree,ifnottherootitselfwillbeceilnode.
HereiscodeinCforceilvalue.
// Program to find ceil of a given value in BST
#include <stdio.h>
#include <stdlib.h>
/* A binary tree node has key, left child and right child */
struct node
{
int key;
struct node* left;
struct node* right;
};
/* Helper function that allocates a new node with the given key and
root->left = newNode(4);
root->right = newNode(12);
root->left->left = newNode(2);
root->left->right = newNode(6);
root->right->left = newNode(10);
root->right->right = newNode(14);
return 0;
}
Output:
02
12
22
34
44
56
66
78
88
910
1010
1112
1212
1314
1414
151
=======================================================================
ConstructBSTfromgivenpreorder
traversal|Set2
Givenpreordertraversalofabinarysearchtree,constructtheBST.
Forexample,ifthegiventraversalis{10,5,1,7,40,50},thentheoutputshouldberootoffollowingtree.
10
/\
540
/\\
1750
WehavediscussedO(n^2)andO(n)recursivesolutionsinthepreviouspost.Followingisastackbased
iterativesolutionthatworksinO(n)time.
1.Createanemptystack.
2.Makethefirstvalueasroot.Pushittothestack.
3.Keeponpoppingwhilethestackisnotemptyandthenextvalueisgreaterthanstackstopvalue.Make
thisvalueastherightchildofthelastpoppednode.Pushthenewnodetothestack.
4.Ifthenextvalueislessthanthestackstopvalue,makethisvalueastheleftchildofthestackstopnode.
Pushthenewnodetothestack.
5.Repeatsteps2and3untilthereareitemsremaininginpre[].
/* A O(n) iterative program for construction of BST from preorder traversal */
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int top;
int capacity;
Node* *array;
} Stack;
// Push root
push( stack, root );
int i;
Node* temp;
// Make this greater value as the right child and push it to the stack
if ( temp != NULL)
{
temp->right = newNode( pre[i] );
push( stack, temp->right );
}
// If the next value is less than the stack's top value, make this value
// as the left child of the stack's top node. Push the new node to stack
else
{
peek( stack )->left = newNode( pre[i] );
push( stack, peek( stack )->left );
}
}
return root;
}
return 0;
}
Output:
157104050
TimeComplexity:O(n).Thecomplexitylooksmorefromfirstlook.Ifwetakeacloserlook,wecanobserve
thateveryitemispushedandpoppedonlyonce.Soatmost2npush/popoperationsareperformedinthe
mainloopsofconstructTree().Therefore,timecomplexityisO(n).
=======================================================================
ConstructFullBinaryTreefrom
givenpreorderandpostorder
traversals
Giventwoarraysthatrepresentpreorderandpostordertraversalsofafullbinarytree,constructthebinary
tree.
AFullBinaryTreeisabinarytreewhereeverynodehaseither0or2children
FollowingareexamplesofFullTrees.
1
/\
23
/\/\
4567
1
/\
23
/\
45
/\
67
1
/\
23
/\/\
4567
/\
89
ItisnotpossibletoconstructageneralBinaryTreefrompreorderandpostordertraversals(Seethis).Butif
knowthattheBinaryTreeisFull,wecanconstructthetreewithoutambiguity.Letusunderstandthiswith
thehelpoffollowingexample.
Letusconsiderthetwogivenarraysaspre[]={1,2,4,8,9,5,3,6,7}andpost[]={8,9,4,5,2,6,7,3,1}
Inpre[],theleftmostelementisrootoftree.Sincethetreeisfullandarraysizeismorethan1.Thevalue
nextto1inpre[],mustbeleftchildofroot.Soweknow1isrootand2isleftchild.Howtofindtheallnodes
inleftsubtree?Weknow2isrootofallnodesinleftsubtree.Allnodesbefore2inpost[]mustbeinleft
subtree.Nowweknow1isroot,elements{8,9,4,5,2}areinleftsubtree,andtheelements{6,7,3}arein
rightsubtree.
1
/\
/\
{8,9,4,5,2}{6,7,3}
Werecursivelyfollowtheaboveapproachandgetthefollowingtree.
1
/\
23
/\/\
4567
/\
89
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
return root;
}
// The main function to construct Full Binary Tree from given preorder and
// postorder traversals. This function mainly uses constructTreeUtil()
struct node *constructTree (int pre[], int post[], int size)
{
int preIndex = 0;
return 0;
}
Output:
Inordertraversaloftheconstructedtree:
849251637
=======================================================================
TwonodesofaBSTareswapped,
correcttheBST
TwoofthenodesofaBinarySearchTree(BST)areswapped.Fix(orcorrect)theBST.
InputTree:
10
/\
58
/\
220
Intheabovetree,nodes20and8mustbeswappedtofixthetree.
Followingistheoutputtree
10
/\
520
/\
28
TheinordertraversalofaBSTproducesasortedarray.Soasimplemethodistostoreinordertraversalof
theinputtreeinanauxiliaryarray.Sorttheauxiliaryarray.Finally,inserttheauxiilaryarrayelementsbackto
theBST,keepingthestructureoftheBSTsame.TimecomplexityofthismethodisO(nLogn)andauxiliary
spaceneededisO(n).
WecansolvethisinO(n)timeandwithasingletraversalofthegivenBST.Sinceinordertraversalof
BSTisalwaysasortedarray,theproblemcanbereducedtoaproblemwheretwoelementsofasorted
arrayareswapped.Therearetwocasesthatweneedtohandle:
1.TheswappednodesarenotadjacentintheinordertraversaloftheBST.
Forexample,Nodes5and25areswappedin{357810152025}.
Theinordertraversalofthegiventreeis325781015205
Ifweobservecarefully,duringinordertraversal,wefindnode7issmallerthanthepreviousvisitednode25.
Heresavethecontextofnode25(previousnode).Again,wefindthatnode5issmallerthantheprevious
node20.Thistime,wesavethecontextofnode5(currentnode).Finallyswapthetwonodesvalues.
2.TheswappednodesareadjacentintheinordertraversalofBST.
Forexample,Nodes7and8areswappedin{357810152025}.
Theinordertraversalofthegiventreeis358710152025
Unlikecase#1,hereonlyonepointexistswhereanodevalueissmallerthanpreviousnodevalue.e.g.
node7issmallerthannode8.
HowtoSolve?Wewillmaintainthreepointers,first,middleandlast.Whenwefindthefirstpointwhere
currentnodevalueissmallerthanpreviousnodevalue,weupdatethefirstwiththepreviousnode&middle
withthecurrentnode.Whenwefindthesecondpointwherecurrentnodevalueissmallerthanprevious
nodevalue,weupdatethelastwiththecurrentnode.Incase#2,wewillneverfindthesecondpoint.So,
lastpointerwillnotbeupdated.Afterprocessing,ifthelastnodevalueisnull,thentwoswappednodesof
BSTareadjacent.
FollowingisCimplementationofthegivencode.
// Two nodes in the BST's swapped, correct the BST.
#include <stdio.h>
#include <stdlib.h>
node->left = NULL;
node->right = NULL;
return(node);
}
// This function does inorder traversal to find out the two swapped nodes.
// It sets three pointers, first, middle and last. If the swapped nodes are
// adjacent to each other, then first and middle contain the resultant nodes
// Else, first and last contain the resultant nodes
void correctBSTUtil( struct node* root, struct node** first,
struct node** middle, struct node** last,
struct node** prev )
{
if( root )
{
// Recur for the left subtree
correctBSTUtil( root->left, first, middle, last, prev );
// A function to fix a given BST where two nodes are swapped. This
// function uses correctBSTUtil() to find out two nodes and swaps the
// nodes to fix the BST
void correctBST( struct node* root )
{
// Initialize pointers needed for correctBSTUtil()
struct node *first, *middle, *last, *prev;
first = middle = last = prev = NULL;
// else nodes have not been swapped, passed tree is really BST.
}
6
/ \
10
/\
/\
3 7 12
= newNode(10);
root->right
= newNode(2);
root->left->left = newNode(1);
root->left->right = newNode(3);
root->right->right = newNode(12);
root->right->left = newNode(7);
correctBST(root);
return 0;
}
Output:
InorderTraversaloftheoriginaltree
110367212
InorderTraversalofthefixedtree
123671012
TimeComplexity:O(n)
=======================================================================
BoundaryTraversalofbinarytree
Givenabinarytree,printboundarynodesofthebinarytreeAntiClockwisestartingfromtheroot.For
example,boundarytraversalofthefollowingtreeis208410142522
Webreaktheproblemin3parts:
1.Printtheleftboundaryintopdownmanner.
2.Printallleafnodesfromlefttoright,whichcanagainbesubdividedintotwosubparts:
..2.1Printallleafnodesofleftsubtreefromlefttoright.
..2.2Printallleafnodesofrightsubtreefromlefttoright.
3.Printtherightboundaryinbottomupmanner.
Weneedtotakecareofonethingthatnodesarenotprintedagain.e.g.Theleftmostnodeisalsotheleaf
nodeofthetree.
Basedontheabovecases,belowistheimplementation:
/* program for boundary traversal of a binary tree */
#include <stdio.h>
#include <stdlib.h>
printLeaves(root->right);
}
}
printLeaves(root->left);
printLeaves(root->right);
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
= newNode(20);
root->left
= newNode(8);
root->left->left
= newNode(4);
root->left->right
= newNode(12);
root->left->right->left
= newNode(10);
root->left->right->right = newNode(14);
root->right
= newNode(22);
root->right->right
= newNode(25);
printBoundary( root );
return 0;
}
Output:
208410142522
TimeComplexity:O(n)wherenisthenumberofnodesinbinarytree.
=======================================================================
CheckwhetheragivenBinaryTree
isCompleteornot
GivenaBinaryTree,writeafunctiontocheckwhetherthegivenBinaryTreeisCompleteBinaryTreeornot.
Acompletebinarytreeisabinarytreeinwhicheverylevel,exceptpossiblythelast,iscompletelyfilled,and
allnodesareasfarleftaspossible.Seefollowingexamples.
ThefollowingtreesareexamplesofCompleteBinaryTrees
1
/\
23
1
/\
23
/
4
1
/\
23
/\/
456
ThefollowingtreesareexamplesofNonCompleteBinaryTrees
1
\
3
1
/\
23
\/\
456
1
/\
23
/\
45
Source:Writeanalgorithmtocheckifatreeiscompletebinarytreeornot
Themethod2oflevelordertraversalpostcanbeeasilymodifiedtocheckwhetheratreeisCompleteor
not.Tounderstandtheapproach,letusfirstdefineatermFullNode.AnodeisFullNodeifbothleftand
rightchildrenarenotempty(ornotNULL).
Theapproachistodoalevelordertraversalstartingfromroot.Inthetraversal,onceanodeisfoundwhich
isNOTaFullNode,allthefollowingnodesmustbeleafnodes.
Also,onemorethingneedstobecheckedtohandlethebelowcase:Ifanodehasemptyleftchild,thenthe
rightchildmustbeempty.
1
/\
23
\
4
ThankstoGudduSharmaforsuggestingthissimpleandefficientapproach.
// A program to check if a given binary tree is complete or not
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX_Q_SIZE 500
return false;
/*UTILITY FUNCTIONS*/
struct node** createQueue(int *front, int *rear)
{
struct node **queue =
(struct node **)malloc(sizeof(struct node*)*MAX_Q_SIZE);
*front = *rear = 0;
return queue;
}
return(node);
}
/\ \
4
56
*/
= newNode(2);
root->right
= newNode(3);
root->left->left
= newNode(4);
root->left->right = newNode(5);
root->right->right = newNode(6);
if ( isCompleteBT(root) == true )
printf ("Complete Binary Tree");
else
printf ("NOT Complete Binary Tree");
return 0;
}
Output:
NOTCompleteBinaryTree
TimeComplexity:O(n)wherenisthenumberofnodesingivenBinaryTree
AuxiliarySpace:O(n)forqueue.
=======================================================================
CheckifeachinternalnodeofaBST
hasexactlyonechild
GivenPreordertraversalofaBST,checkifeachnonleafnodehasonlyonechild.AssumethattheBST
containsuniqueentries.
Examples
Input:pre[]={20,10,11,13,12}
Output:Yes
ThegivearrayrepresentsfollowingBST.InthefollowingBST,everyinternal
nodehasexactly1child.Therefor,theoutputistrue.
20
/
10
\
11
\
13
/
12
InPreordertraversal,descendants(orPreordersuccessors)ofeverynodeappearafterthenode.Inthe
aboveexample,20isthefirstnodeinpreorderandalldescendantsof20appearafterit.Alldescendantsof
20aresmallerthanit.For10,alldescendantsaregreaterthanit.Ingeneral,wecansay,ifallinternalnodes
haveonlyonechildinaBST,thenallthedescendantsofeverynodeareeithersmallerorlargerthanthe
node.Thereasonissimple,sincethetreeisBSTandeverynodehasonlyonechild,alldescendantsofa
nodewilleitherbeonleftsideorrightside,meansalldescendantswilleitherbesmallerorgreater.
Approach1(Naive)
Thisapproachsimplyfollowstheaboveideathatallvaluesonrightsideareeithersmallerorlarger.Usetwo
loops,theouterlooppicksanelementonebyone,startingfromtheleftmostelement.Theinnerloopchecks
ifallelementsontherightsideofthepickedelementareeithersmallerorgreater.Thetimecomplexityof
thismethodwillbeO(n^2).
Approach2
Sinceallthedescendantsofanodemusteitherbelargerorsmallerthanthenode.Wecandofollowingfor
everynodeinaloop.
1.Findthenextpreordersuccessor(ordescendant)ofthenode.
2.Findthelastpreordersuccessor(lastelementinpre[])ofthenode.
3.Ifbothsuccessorsarelessthanthecurrentnode,orbothsuccessorsaregreaterthanthecurrentnode,
thencontinue.Else,returnfalse.
#include <stdio.h>
Yes
Approach3
1.Scanthelasttwonodesofpreorder&markthemasmin&max.
2.Scaneverynodedownthepreorderarray.Eachnodemustbeeithersmallerthantheminnodeorlarger
thanthemaxnode.Updatemin&maxaccordingly.
#include <stdio.h>
max = pre[size-2];
min = pre[size-1];
}
Yes
=======================================================================
Constructaspecialtreefromgiven
preordertraversal
Givenanarraypre[]thatrepresentsPreordertraversalofaspacialbinarytreewhereeverynodehaseither
0or2children.OnemorearraypreLN[]isgivenwhichhasonlytwopossiblevaluesLandN.Thevalue
LinpreLN[]indicatesthatthecorrespondingnodeinBinaryTreeisaleafnodeandvalueNindicatesthat
thecorrespondingnodeisnonleafnode.Writeafunctiontoconstructthetreefromthegiventwoarrays.
Source:AmazonInterviewQuestion
Example:
Input:pre[]={10,30,20,5,15},preLN[]={'N','N','L','L','L'}
Output:Rootoffollowingtree
10
/\
3015
/\
205
Thefirstelementinpre[]willalwaysberoot.Sowecaneasilyfigureoutroot.Ifleftsubtreeisempty,the
rightsubtreemustalsobeemptyandpreLN[]entryforrootmustbeL.Wecansimplycreateanodeand
returnit.Ifleftandrightsubtreesarenotempty,thenrecursivelycallforleftandrightsubtreesandlinkthe
returnednodestoroot.
/* A program to construct Binary Tree from preorder traversal */
#include<stdio.h>
// If this is an internal node, construct left and right subtrees and link the
subtrees
if (preLN[index] == 'N')
{
temp->left = constructTreeUtil(pre, preLN, index_ptr, n);
temp->right = constructTreeUtil(pre, preLN, index_ptr, n);
}
return temp;
}
{
// Initialize index as 0. Value of index is used in recursion to maintain
// the current index in pre[] and preLN[] arrays.
int index = 0;
15
/ \
20
5 */
return 0;
}
Output:
FollowingisInorderTraversaloftheConstructedBinaryTree:
203051015
TimeComplexity:O(n)
=======================================================================
ConstructSpecialBinaryTreefrom
givenInordertraversal
GivenInorderTraversalofaSpecialBinaryTreeinwhichkeyofeverynodeisgreaterthankeysinleftand
rightchildren,constructtheBinaryTreeandreturnroot.
Examples:
Input:inorder[]={5,10,40,30,28}
Output:rootoffollowingtree
40
/\
1030
/\
528
TheideausedinConstructionofTreefromgivenInorderandPreordertraversalscanbeusedhere.Letthe
givenarrayis{1,5,10,40,30,15,28,20}.Themaximumelementingivenarraymustberoot.The
elementsonleftsideofthemaximumelementareinleftsubtreeandelementsonrightsideareinright
subtree.
40
/\
{1,5,10}{30,15,28,20}
Werecursivelyfollowabovestepforleftandrightsubtrees,andfinallygetthefollowingtree.
40
/\
1030
/\
528
//\
11520
Algorithm:buildTree()
1)Findindexofthemaximumelementinarray.ThemaximumelementmustberootofBinaryTree.
2)Createanewtreenoderootwiththedataasthemaximumvaluefoundinstep1.
3)CallbuildTreeforelementsbeforethemaximumelementandmakethebuilttreeasleftsubtreeofroot.
5)CallbuildTreeforelementsafterthemaximumelementandmakethebuilttreeasrightsubtreeofroot.
6)returnroot.
Implementation:FollowingisC/C++implementationoftheabovealgorithm.
/* program to construct tree from inorder traversal */
#include<stdio.h>
#include<stdlib.h>
return root;
}
/* UTILITY FUNCTIONS */
/* Function to find index of the maximum value in arr[start...end] */
int max (int arr[], int strt, int end)
{
int i, max = arr[strt], maxind = strt;
return node;
}
\
30
\
28 */
Inordertraversaloftheconstructedtreeis
510403028
TimeComplexity:O(n^2)
=======================================================================
MergetwoBSTswithlimitedextra
space
GiventwoBinarySearchTrees(BST),printtheelementsofbothBSTsinsortedform.Theexpectedtime
complexityisO(m+n)wheremisthenumberofnodesinfirsttreeandnisthenumberofnodesinsecond
tree.MaximumallowedauxiliaryspaceisO(heightofthefirsttree+heightofthesecondtree).
Examples:
FirstBST
3
/\
15
SecondBST
4
/\
26
Output:123456
FirstBST
8
/\
210
/
1
SecondBST
5
/
3
/
0
Output:01235810
Source:Googleinterviewquestion
Asimilarquestionhasbeendiscussedearlier.Letusfirstdiscussalreadydiscussedmethodsofthe
previouspostwhichwasforBalancedBSTs.Themethod1canbeappliedherealso,butthetime
complexitywillbeO(n^2)inworstcase.Themethod2canalsobeappliedhere,buttheextraspace
requiredwillbeO(n)whichviolatestheconstraintgiveninthisquestion.Method3canbeappliedherebut
thestep3ofmethod3cantbedoneinO(n)foranunbalancedBST.
ThankstoKumarforsuggestingthefollowingsolution.
Theideaistouseiterativeinordertraversal.WeusetwoauxiliarystacksfortwoBSTs.Sinceweneedto
printtheelementsinsortedform,wheneverwegetasmallerelementfromanyofthetrees,weprintit.Ifthe
elementisgreater,thenwepushitbacktostackforthenextiteration.
#include<stdio.h>
#include<stdlib.h>
return t;
}
return 0;
}
//.................... END OF STACK RELATED STUFF....................
{
// s1 is stack to hold nodes of first BST
struct snode *s1 = NULL;
// Run the loop while there are nodes not yet printed.
// The nodes may be in stack(explored, but not printed)
// or may be not yet explored
while (current1 != NULL || !isEmpty(s1) ||
current2 != NULL || !isEmpty(s2))
{
// Following steps follow iterative Inorder Traversal
if (current1 != NULL || current2 != NULL )
{
}
else
{
// If we reach a NULL node and either of the stacks is empty,
// then one tree is exhausted, ptint the other tree
if (isEmpty(s1))
{
while (!isEmpty(s2))
{
current2 = pop (&s2);
current2->left = NULL;
inorder(current2);
}
return ;
}
if (isEmpty(s2))
{
while (!isEmpty(s1))
{
current1 = pop (&s1);
current1->left = NULL;
inorder(current1);
}
return ;
*/
root1 = newNode(3);
root1->left = newNode(1);
root1->right = newNode(5);
*/
root2 = newNode(4);
root2->left = newNode(2);
root2->right = newNode(6);
return 0;
}
TimeComplexity:O(m+n)
AuxiliarySpace:O(heightofthefirsttree+heightofthesecondtree)
=======================================================================
Findthemaximumsumleaftoroot
pathinaBinaryTree
GivenaBinaryTree,findthemaximumsumpathfromaleaftoroot.Forexample,inthefollowingtree,there
arethreeleaftorootpaths8>2>10,4>2>10and7>10.Thesumsofthesethreepathsare16,4and
17respectively.Themaximumofthemis17andthepathformaximumis7>10.
10
/\
27
/\
84
Solution
1)Firstfindtheleafnodethatisonthemaximumsumpath.InthefollowingcodegetTargetLeaf()doesthis
byassigningtheresultto*target_leaf_ref.
2)Oncewehavethetargetleafnode,wecanprintthemaximumsumpathbytraversingthetree.Inthe
followingcode,printPath()doesthis.
ThemainfunctionismaxSumPath()thatusesabovetwofunctionstogetthecompletesolution.
#include<stdio.h>
#include<limits.h>
// A utility function that prints all nodes on the path from root to target_leaf
bool printPath (struct node *root, struct node *target_leaf)
{
// base case
if (root == NULL)
return false;
return false;
}
// This function Sets the target_leaf_ref to refer the leaf node of the maximum
// Update current sum to hold sum of nodes on path from root to this node
curr_sum = curr_sum + node->data;
// If this is a leaf node and path to this node has maximum sum so far,
// then make this node target_leaf
if (node->left == NULL && node->right == NULL)
{
if (curr_sum > *max_sum_ref)
{
*max_sum_ref = curr_sum;
*target_leaf_ref = node;
}
}
// If this is not a leaf node, then recur down to find the target_leaf
getTargetLeaf (node->left, max_sum_ref, curr_sum, target_leaf_ref);
getTargetLeaf (node->right, max_sum_ref, curr_sum, target_leaf_ref);
}
// Returns the maximum sum and prints the nodes on max sum path
int maxSumPath (struct node *node)
{
// base case
if (node == NULL)
return 0;
printf ("Following are the nodes on the maximum sum path \n");
int sum = maxSumPath(root);
printf ("\nSum of the nodes is %d ", sum);
getchar();
return 0;
}
Output:
Followingarethenodesonthemaximumsumpath
710
Sumofthenodesis17
TimeComplexity:TimecomplexityoftheabovesolutionisO(n)asitinvolvestreetraversaltwotimes.
=======================================================================
MergeTwoBalancedBinarySearch
Trees
Youaregiventwobalancedbinarysearchtreese.g.,AVLorRedBlackTree.Writeafunctionthatmerges
thetwogivenbalancedBSTsintoabalancedbinarysearchtree.Lettherebemelementsinfirsttreeandn
elementsintheothertree.YourmergefunctionshouldtakeO(m+n)time.
Inthefollowingsolutions,itisassumedthatsizesoftreesarealsogivenasinput.Ifthesizeisnotgiven,
thenwecangetthesizebytraversingthetree(Seethis).
Method1(Insertelementsoffirsttreetosecond)
TakeallelementsoffirstBSTonebyone,andinsertthemintothesecondBST.Insertinganelementtoa
selfbalancingBSTtakesLogntime(Seethis)wherenissizeoftheBST.Sotimecomplexityofthismethod
isLog(n)+Log(n+1)Log(m+n1).ThevalueofthisexpressionwillbebetweenmLognandmLog(m+n1).
Asanoptimization,wecanpickthesmallertreeasfirsttree.
Method2(MergeInorderTraversals)
1)Doinordertraversaloffirsttreeandstorethetraversalinonetemparrayarr1[].ThissteptakesO(m)
time.
2)Doinordertraversalofsecondtreeandstorethetraversalinanothertemparrayarr2[].Thissteptakes
O(n)time.
3)Thearrayscreatedinstep1and2aresortedarrays.Mergethetwosortedarraysintoonearrayofsizem
+n.ThissteptakesO(m+n)time.
4)Constructabalancedtreefromthemergedarrayusingthetechniquediscussedinthispost.Thisstep
takesO(m+n)time.
TimecomplexityofthismethodisO(m+n)whichisbetterthanmethod1.ThismethodtakesO(m+n)time
eveniftheinputBSTsarenotbalanced.
FollowingisC++implementationofthismethod.
#include <stdio.h>
#include <stdlib.h>
/* A function that constructs Balanced Binary Search Tree from a sorted array
See http://www.geeksforgeeks.org/archives/17138 */
struct node* sortedArrayToBST(int arr[], int start, int end);
/* This function merges two balanced BSTs with roots as root1 and root2.
m and n are the sizes of the trees respectively */
struct node* mergeTrees(struct node *root1, struct node *root2, int m, int n)
{
// Store inorder traversal of first tree in an array arr1[]
int *arr1 = new int[m];
int i = 0;
storeInorder(root1, arr1, &i);
// Construct a tree from the merged array and return root of the tree
return sortedArrayToBST (mergedArr, 0, m+n-1);
}
return(node);
}
int i = 0, j = 0, k = 0;
return mergedArr;
}
// A helper function that stores inorder traversal of a tree rooted with node
inorder[*index_ptr] = node->data;
(*index_ptr)++; // increase index for next entry
/* A function that constructs Balanced Binary Search Tree from a sorted array
See http://www.geeksforgeeks.org/archives/17138 */
struct node* sortedArrayToBST(int arr[], int start, int end)
{
/* Base Case */
if (start > end)
return NULL;
return root;
}
300
/\
20 70
*/
struct node *root1 = newNode(100);
root1->left
= newNode(50);
root1->right
= newNode(300);
root1->left->left
= newNode(20);
root1->left->right = newNode(70);
120
*/
struct node *root2 = newNode(80);
root2->left
= newNode(40);
root2->right
= newNode(120);
getchar();
return 0;
}
Output:
FollowingisInordertraversalofthemergedtree
2040507080100120300
Method3(InPlaceMergeusingDLL)
WecanuseaDoublyLinkedListtomergetreesinplace.Followingarethesteps.
1)ConvertthegiventwoBinarySearchTreesintodoublylinkedlistinplace(Referthispostforthisstep).
2)MergethetwosortedLinkedLists(Referthispostforthisstep).
3)BuildaBalancedBinarySearchTreefromthemergedlistcreatedinstep2.(Referthispostforthisstep)
TimecomplexityofthismethodisalsoO(m+n)andthismethoddoesconversioninplace.
=======================================================================
AVLTree|Set2(Deletion)
WehavediscussedAVLinsertioninthepreviouspost.Inthispost,wewillfollowasimilarapproachfor
deletion.
Stepstofollowfordeletion.
TomakesurethatthegiventreeremainsAVLaftereverydeletion,wemustaugmentthestandardBST
deleteoperationtoperformsomerebalancing.Followingaretwobasicoperationsthatcanbeperformedto
rebalanceaBSTwithoutviolatingtheBSTproperty(keys(left)<key(root)<keys(right)).
1)LeftRotation
2)RightRotation
T1,T2andT3aresubtreesofthetreerootedwithy(onleftside)
orx(onrightside)
yx
/\RightRotation/\
xT3>T1y
/\</\
T1T2LeftRotationT2T3
Keysinbothoftheabovetreesfollowthefollowingorder
keys(T1)<key(x)<keys(T2)<key(y)<keys(T3)
SoBSTpropertyisnotviolatedanywhere.
Letwbethenodetobedeleted
1)PerformstandardBSTdeleteforw.
2)Startingfromw,travelupandfindthefirstunbalancednode.Letzbethefirstunbalancednode,ybethe
largerheightchildofz,andxbethelargerheightchildofy.Notethatthedefinitionsofxandyaredifferent
frominsertionhere.
3)Rebalancethetreebyperformingappropriaterotationsonthesubtreerootedwithz.Therecanbe4
possiblecasesthatneedstobehandledasx,yandzcanbearrangedin4ways.Followingarethepossible
4arrangements:
a)yisleftchildofzandxisleftchildofy(LeftLeftCase)
b)yisleftchildofzandxisrightchildofy(LeftRightCase)
c)yisrightchildofzandxisrightchildofy(RightRightCase)
d)yisrightchildofzandxisleftchildofy(RightLeftCase)
Likeinsertion,followingaretheoperationstobeperformedinabovementioned4cases.Notethat,unlike
insertion,fixingthenodezwontfixthecompleteAVLtree.Afterfixingz,wemayhavetofixancestorsofz
aswell(Seethisvideolectureforproof)
a)LeftLeftCase
T1,T2,T3andT4aresubtrees.
zy
/\/\
yT4RightRotate(z)xz
/\>/\/\
xT3T1T2T3T4
/\
T1T2
b)LeftRightCase
zzx
/\/\/\
yT4LeftRotate(y)xT4RightRotate(z)yz
/\>/\>/\/\
T1xyT3T1T2T3T4
/\/\
T2T3T1T2
c)RightRightCase
zy
/\/\
T1yLeftRotate(z)zx
/\>/\/\
T2xT1T2T3T4
/\
T3T4
d)RightLeftCase
zzx
/\/\/\
T1yRightRotate(y)T1xLeftRotate(z)zx
/\>/\>/\/\
xT4T2yT1T2T3T4
/\/\
T2T3T3T4
Unlikeinsertion,indeletion,afterweperformarotationatz,wemayhavetoperformarotationatancestors
ofz.Thus,wemustcontinuetotracethepathuntilwereachtheroot.
Cimplementation
FollowingistheCimplementationforAVLTreeDeletion.ThefollowingCimplementationusestherecursive
BSTdeleteasbasis.IntherecursiveBSTdelete,afterdeletion,wegetpointerstoallancestorsonebyone
inbottomupmanner.Sowedontneedparentpointertotravelup.Therecursivecodeitselftravelsupand
visitsalltheancestorsofthedeletednode.
1)PerformthenormalBSTdeletion.
2)Thecurrentnodemustbeoneoftheancestorsofthedeletednode.Updatetheheightofthecurrent
node.
3)Getthebalancefactor(leftsubtreeheightrightsubtreeheight)ofthecurrentnode.
4)Ifbalancefactorisgreaterthan1,thenthecurrentnodeisunbalancedandweareeitherinLeftLeftcase
orLeftRightcase.TocheckwhetheritisLeftLeftcaseorLeftRightcase,getthebalancefactorofleft
subtree.Ifbalancefactoroftheleftsubtreeisgreaterthanorequalto0,thenitisLeftLeftcase,elseLeft
Rightcase.
5)Ifbalancefactorislessthan1,thenthecurrentnodeisunbalancedandweareeitherinRightRightcase
orRightLeftcase.TocheckwhetheritisRightRightcaseorRightLeftcase,getthebalancefactorofright
subtree.Ifthebalancefactoroftherightsubtreeissmallerthanorequalto0,thenitisRightRightcase,
elseRightLeftcase.
#include<stdio.h>
#include<stdlib.h>
{
int key;
struct node *left;
struct node *right;
int height;
};
/* Helper function that allocates a new node with the given key and
NULL left and right pointers. */
struct node* newNode(int key)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->key
node->left
= key;
= NULL;
node->right = NULL;
node->height = 1; // new node is initially added at leaf
return(node);
}
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right))+1;
x->height = max(height(x->left), height(x->right))+1;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right))+1;
y->height = max(height(y->left), height(y->right))+1;
/* Given a non-empty binary search tree, return the node with minimum
key value found in that tree. Note that the entire tree does not
need to be searched. */
struct node * minValueNode(struct node* node)
{
struct node* current = node;
return current;
}
if (root == NULL)
return root;
// No child case
if(temp == NULL)
{
temp = root;
root = NULL;
}
else // One child case
*root = *temp; // Copy the contents of the non-empty child
free(temp);
}
else
{
// node with two children: Get the inorder successor (smallest
// in the right subtree)
struct node* temp = minValueNode(root->right);
// STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to check whether
// this node became unbalanced)
int balance = getBalance(root);
return root;
}
11
/ \
-1
2 6
*/
/ \
5
11
/ \
2 6
*/
return 0;
}
Output:
PreordertraversaloftheconstructedAVLtreeis
91015261011
Preordertraversalafterdeletionof10
101952611
TimeComplexity:Therotationoperations(leftandrightrotate)takeconstanttimeasonlyfewpointersare
beingchangedthere.Updatingtheheightandgettingthebalancefactoralsotakeconstanttime.Sothetime
complexityofAVLdeleteremainssameasBSTdeletewhichisO(h)wherehisheightofthetree.Since
AVLtreeisbalanced,theheightisO(Logn).SotimecomplexityofAVLdeleteisO(Logn).
=======================================================================
VerticalSuminagivenBinaryTree
GivenaBinaryTree,findverticalsumofthenodesthatareinsameverticalline.Printallsumsthrough
differentverticallines.
Examples:
1
/\
23
/\/\
4567
Thetreehas5verticallines
VerticalLine1hasonlyonenode4=>verticalsumis4
VerticalLine2:hasonlyonenode2=>verticalsumis2
VerticalLine3:hasthreenodes:1,5,6=>verticalsumis1+5+6=12
VerticalLine4:hasonlyonenode3=>verticalsumis3
VerticalLine5:hasonlyonenode7=>verticalsumis7
Soexpectedoutputis4,2,12,3and7
Solution:
WeneedtochecktheHorizontalDistancesfromrootforallnodes.IftwonodeshavethesameHorizontal
Distance(HD),thentheyareonsameverticalline.TheideaofHDissimple.HDforrootis0,arightedge
(edgeconnectingtorightsubtree)isconsideredas+1horizontaldistanceandaleftedgeisconsideredas
1horizontaldistance.Forexample,intheabovetree,HDforNode4isat2,HDforNode2is1,HDfor5
and6is0andHDfornode7is+2.
WecandoinordertraversalofthegivenBinaryTree.Whiletraversingthetree,wecanrecursivelycalculate
HDs.Weinitiallypassthehorizontaldistanceas0forroot.Forleftsubtree,wepasstheHorizontalDistance
asHorizontaldistanceofrootminus1.Forrightsubtree,wepasstheHorizontalDistanceasHorizontal
Distanceofrootplus1.
FollowingisJavaimplementationforthesame.HashMapisusedtostoretheverticalsumsfordifferent
horizontaldistances.ThankstoNagesforsuggestingthismethod.
import java.util.HashMap;
// data members
private int key;
private TreeNode left;
private TreeNode right;
// Accessor methods
public int key()
{ return key; }
// Constructor
public TreeNode(int key) { this.key = key; left = null; right = null; }
{ this.left = left; }
// Constructors
public Tree() { root = null; }
public Tree(TreeNode n) { root = n; }
// base case
if (root == null) { return; }
// base case
if (root == null) { return; }
/\
4
56
/\
7
*/
TreeNode root = new TreeNode(1);
root.setLeft(new TreeNode(2));
root.setRight(new TreeNode(3));
root.left().setLeft(new TreeNode(4));
root.left().setRight(new TreeNode(5));
root.right().setLeft(new TreeNode(6));
root.right().setRight(new TreeNode(7));
Tree t = new Tree(root);
==================================================================================
AVLTree|Set1(Insertion)
AVLtreeisaselfbalancingBinarySearchTree(BST)wherethedifferencebetweenheightsofleftandright
subtreescannotbemorethanoneforallnodes.
WhyAVLTrees?
MostoftheBSToperations(e.g.,search,max,min,insert,delete..etc)takeO(h)timewherehistheheight
oftheBST.ThecostoftheseoperationsmaybecomeO(n)foraskewedBinarytree.Ifwemakesurethat
heightofthetreeremainsO(Logn)aftereveryinsertionanddeletion,thenwecanguaranteeanupper
boundofO(Logn)foralltheseoperations.TheheightofanAVLtreeisalwaysO(Logn)wherenisthe
numberofnodesinthetree(Seethisvideolectureforproof).
Insertion
TomakesurethatthegiventreeremainsAVLaftereveryinsertion,wemustaugmentthestandardBST
insertoperationtoperformsomerebalancing.Followingaretwobasicoperationsthatcanbeperformedto
rebalanceaBSTwithoutviolatingtheBSTproperty(keys(left)<key(root)<keys(right)).
1)LeftRotation
2)RightRotation
T1,T2andT3aresubtreesofthetreerootedwithy(onleftside)
orx(onrightside)
yx
/\RightRotation/\
xT3>T1y
/\</\
T1T2LeftRotationT2T3
Keysinbothoftheabovetreesfollowthefollowingorder
keys(T1)<key(x)<keys(T2)<key(y)<keys(T3)
SoBSTpropertyisnotviolatedanywhere.
Stepstofollowforinsertion
Letthenewlynsertednodebew
1)PerformstandardBSTinsertforw.
2)Startingfromw,travelupandfindthefirstunbalancednode.Letzbethefirstunbalancednode,ybethe
childofzthatcomesonthepathfromwtozandxbethegrandchildofzthatcomesonthepathfromwto
z.
3)Rebalancethetreebyperformingappropriaterotationsonthesubtreerootedwithz.Therecanbe4
possiblecasesthatneedstobehandledasx,yandzcanbearrangedin4ways.Followingarethepossible
4arrangements:
a)yisleftchildofzandxisleftchildofy(LeftLeftCase)
b)yisleftchildofzandxisrightchildofy(LeftRightCase)
c)yisrightchildofzandxisrightchildofy(RightRightCase)
d)yisrightchildofzandxisleftchildofy(RightLeftCase)
Followingaretheoperationstobeperformedinabovementioned4cases.Inallofthecases,weonlyneed
torebalancethesubtreerootedwithzandthecompletetreebecomesbalancedastheheightofsubtree
(Afterappropriaterotations)rootedwithzbecomessameasitwasbeforeinsertion.(Seethisvideolecture
forproof)
a)LeftLeftCase
T1,T2,T3andT4aresubtrees.
zy
/\/\
yT4RightRotate(z)xz
/\>/\/\
xT3T1T2T3T4
/\
T1T2
b)LeftRightCase
zzx
/\/\/\
yT4LeftRotate(y)xT4RightRotate(z)yz
/\>/\>/\/\
T1xyT3T1T2T3T4
/\/\
T2T3T1T2
c)RightRightCase
zy
/\/\
T1yLeftRotate(z)zx
/\>/\/\
T2xT1T2T3T4
/\
T3T4
d)RightLeftCase
zzx
/\/\/\
T1yRightRotate(y)T1xLeftRotate(z)zy
/\>/\>/\/\
xT4T2yT1T2T3T4
/\/\
T2T3T3T4
Cimplementation
FollowingistheCimplementationforAVLTreeInsertion.ThefollowingCimplementationusestherecursive
BSTinserttoinsertanewnode.IntherecursiveBSTinsert,afterinsertion,wegetpointerstoallancestors
onebyoneinbottomupmanner.Sowedontneedparentpointertotravelup.Therecursivecodeitself
travelsupandvisitsalltheancestorsofthenewlyinsertednode.
1)PerformthenormalBSTinsertion.
2)Thecurrentnodemustbeoneoftheancestorsofthenewlyinsertednode.Updatetheheightofthe
currentnode.
3)Getthebalancefactor(leftsubtreeheightrightsubtreeheight)ofthecurrentnode.
4)Ifbalancefactorisgreaterthan1,thenthecurrentnodeisunbalancedandweareeitherinLeftLeftcase
orleftRightcase.Tocheckwhetheritisleftleftcaseornot,comparethenewlyinsertedkeywiththekeyin
leftsubtreeroot.
5)Ifbalancefactorislessthan1,thenthecurrentnodeisunbalancedandweareeitherinRightRightcase
orRightLeftcase.TocheckwhetheritisRightRightcaseornot,comparethenewlyinsertedkeywiththe
keyinrightsubtreeroot.
#include<stdio.h>
#include<stdlib.h>
return N->height;
}
/* Helper function that allocates a new node with the given key and
NULL left and right pointers. */
struct node* newNode(int key)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->key
node->left
= key;
= NULL;
node->right = NULL;
node->height = 1; // new node is initially added at leaf
return(node);
}
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right))+1;
x->height = max(height(x->left), height(x->right))+1;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right))+1;
y->height = max(height(y->left), height(y->right))+1;
return node;
}
40
/ \\
10 2550
*/
preOrder(root);
return 0;
}
Output:
PreordertraversaloftheconstructedAVLtreeis
302010254050
TimeComplexity:Therotationoperations(leftandrightrotate)takeconstanttimeasonlyfewpointersare
beingchangedthere.Updatingtheheightandgettingthebalancefactoralsotakeconstanttime.Sothetime
complexityofAVLinsertremainssameasBSTinsertwhichisO(h)wherehisheightofthetree.SinceAVL
treeisbalanced,theheightisO(Logn).SotimecomplexityofAVLinsertisO(Logn).
TheAVLtreeandotherselfbalancingsearchtreeslikeRedBlackareusefultogetallbasicoperationsdone
inO(Logn)time.TheAVLtreesaremorebalancedcomparedtoRedBlackTrees,buttheymaycausemore
rotationsduringinsertionanddeletion.Soifyourapplicationinvolvesmanyfrequentinsertionsand
deletions,thenRedBlacktreesshouldbepreferred.Andiftheinsertionsanddeletionsarelessfrequent
andsearchismorefrequentoperation,thenAVLtreeshouldbepreferredoverRedBlackTree.
Followingaresomepreviouspoststhathaveusedselfbalancingsearchtrees.
Medianinastreamofintegers(runningintegers)
Maximumofallsubarraysofsizek
Countsmallerelementsonrightside
=======================================================================
FindthelargestBSTsubtreeina
givenBinaryTree
GivenaBinaryTree,writeafunctionthatreturnsthesizeofthelargestsubtreewhichisalsoaBinary
SearchTree(BST).IfthecompleteBinaryTreeisBST,thenreturnthesizeofwholetree.
Examples:
Input:
5
/\
24
/\
13
Output:3
ThefollowingsubtreeisthemaximumsizeBSTsubtree
2
/\
13
Input:
50
/\
3060
/\/\
5204570
/\
6580
Output:5
ThefollowingsubtreeisthemaximumsizeBSTsubtree
60
/\
4570
/\
6580
Method1(Simplebutinefficient)
Startfromrootanddoaninordertraversalofthetree.ForeachnodeN,checkwhetherthesubtreerooted
withNisBSTornot.IfBST,thenreturnsizeofthesubtreerootedwithN.Else,recurdowntheleftandright
subtreesandreturnthemaximumofvaluesreturnedbyleftandrightsubtrees.
/*
See http://www.geeksforgeeks.org/archives/632 for implementation of size()
Method2(TrickyandEfficient)
Inmethod1,wetraversethetreeintopdownmanneranddoBSTtestforeverynode.Ifwetraversethe
treeinbottomupmanner,thenwecanpassinformationaboutsubtreestotheparent.Thepassed
informationcanbeusedbytheparenttodoBSTtest(forparentnode)onlyinconstanttime(orO(1)time).
AleftsubtreeneedtotelltheparentwhetheritisBSTornotandalsoneedtopassmaximumvalueinit.So
thatwecancomparethemaximumvaluewiththeparentsdatatochecktheBSTproperty.Similarly,the
rightsubtreeneedtopasstheminimumvalueupthetree.Thesubtreesneedtopassthefollowing
informationupthetreeforthefindingthelargestBST.
1)WhetherthesubtreeitselfisBSTornot(Inthefollowingcode,is_bst_refisusedforthispurpose)
2)Ifthesubtreeisleftsubtreeofitsparent,thenmaximumvalueinit.Andifitisrightsubtreethenminimum
valueinit.
3)SizeofthissubtreeifthissubtreeisBST(Inthefollowingcode,returnvalueoflargestBSTtil()isusedfor
thispurpose)
max_refisusedforpassingthemaximumvalueupthetreeandmin_ptrisusedforpassingminimumvalue
upthetree.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
};
return(node);
}
return max_size;
}
/* Base Case */
if (node == NULL)
{
*is_bst_ref = 1; // An empty tree is BST
return 0;
/* Before updating *min_ref, store the min value in left subtree. So that we
have the correct minimum value for this subtree */
min = *min_ref;
// Update min and max values for the parent recursive calls
if (min < *min_ref)
*min_ref = min;
if (node->data < *min_ref) // For leaf nodes
*min_ref = node->data;
if (node->data > *max_ref)
*max_ref = node->data;
/* If both left and right subtrees are BST. And left and right
subtree properties hold for this node, then this tree is BST.
So return the size of this tree */
if(left_flag && right_flag)
{
if (ls + rs + 1 > *max_size_ref)
*max_size_ref = ls + rs + 1;
return ls + rs + 1;
}
else
{
//Since this subtree is not BST, set is_bst flag for parent calls
*is_bst_ref = 0;
return 0;
}
}
10
60
/ \
5
/ \
20
55
/
45 65
70
/ \
80
*/
= newNode(10);
root->right
= newNode(60);
root->left->left = newNode(5);
root->left->right = newNode(20);
root->right->left = newNode(55);
root->right->left->left = newNode(45);
root->right->right = newNode(70);
root->right->right->left = newNode(65);
root->right->right->right = newNode(80);
/ \
65
80
*/
printf(" Size of the largest BST is %d", largestBST(root));
getchar();
return 0;
}
TimeComplexity:O(n)wherenisthenumberofnodesinthegivenBinaryTree.
================================================================
=======
ConvertagiventreetoitsSumTree
GivenaBinaryTreewhereeachnodehaspositiveandnegativevalues.Convertthistoatreewhereeach
nodecontainsthesumoftheleftandrightsubtreesintheoriginaltree.Thevaluesofleafnodesare
changedto0.
Forexample,thefollowingtree
10
/\
26
/\/\
8475
shouldbechangedto
20(42+12+6)
/\
4(84)12(7+5)
/\/\
0000
Solution:
Doatraversalofthegiventree.Inthetraversal,storetheoldvalueofthecurrentnode,recursivelycallfor
leftandrightsubtreesandchangethevalueofcurrentnodeassumofthevaluesreturnedbytherecursive
calls.Finallyreturnthesumofnewvalueandvalue(whichissumofvaluesinthesubtreerootedwiththis
node).
#include<stdio.h>
// Convert a given tree to a tree where every node contains sum of values of
// nodes in left and right subtrees in the original tree
int toSumTree(struct node *node)
{
// Base case
if(node == NULL)
return 0;
// Recursively call for left and right subtrees and store the sum as
// new value of this node
node->data = toSumTree(node->left) + toSumTree(node->right);
// Return the sum of values of nodes in left and right subtrees and
// old_value of this node
return node->data + old_val;
}
temp->right = NULL;
return temp;
}
toSumTree(root);
getchar();
return 0;
}
Output:
InorderTraversaloftheresultanttreeis:
040200120
TimeComplexity:Thesolutioninvolvesasimpletraversalofthegiventree.SothetimecomplexityisO(n)
wherenisthenumberofnodesinthegivenBinaryTree.
=======================================================================
PopulateInorderSuccessorforall
nodes
GivenaBinaryTreewhereeachnodehasfollowingstructure,writeafunctiontopopulatenextpointerforall
nodes.Thenextpointerforeverynodeshouldbesettopointtoinordersuccessor.
struct node
{
int data;
struct node* left;
struct node* right;
struct node* next;
}
Initially,allnextpointershaveNULLvalues.Yourfunctionshouldfillthesenextpointerssothattheypointto
inordersuccessor.
Solution(UseReverseInorderTraversal)
Traversethegiventreeinreverseinordertraversalandkeeptrackofpreviouslyvisitednode.Whenanode
isbeingvisited,assignpreviouslyvisitednodeasnext.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *left;
struct node *right;
struct node *next;
};
if (p)
{
// First set the next pointer in right subtree
populateNext(p->right);
/* UTILITY FUNCTIONS */
/* Helper function that allocates a new node with the
given data and NULL left and right pointers. */
struct node* newnode(int data)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
node->next = NULL;
return(node);
}
8 12
/
3
*/
struct node *root = newnode(10);
root->left
= newnode(8);
root->right
= newnode(12);
root->left->left = newnode(3);
return 0;
}
Wecanavoidtheuseofstaticvariablebypassingreferencetonextasparamater.
// An implementation that doesn't use static variable
populateNextRecur(root, &next);
}
=======================================================================
SortedArraytoBalancedBST
Givenasortedarray.WriteafunctionthatcreatesaBalancedBinarySearchTreeusingarrayelements.
Examples:
Input:Array{1,2,3}
Output:ABalancedBST
2
/\
13
Input:Array{1,2,3,4}
Output:ABalancedBST
3
/\
24
/
1
Algorithm
Inthepreviouspost,wediscussedconstructionofBSTfromsortedLinkedList.Constructingfromsorted
arrayinO(n)timeissimpleraswecangetthemiddleelementinO(1)time.Followingisasimplealgorithm
wherewefirstfindthemiddlenodeoflistandmakeitrootofthetreetobeconstructed.
1)GettheMiddleofthearrayandmakeitroot.
2)Recursivelydosameforlefthalfandrighthalf.
a)Getthemiddleoflefthalfandmakeitleftchildoftheroot
createdinstep1.
b)Getthemiddleofrighthalfandmakeitrightchildofthe
rootcreatedinstep1.
FollowingisCimplementationoftheabovealgorithm.ThemaincodewhichcreatesBalancedBSTis
highlighted.
#include<stdio.h>
#include<stdlib.h>
/* A function that constructs Balanced Binary Search Tree from a sorted array */
struct TNode* sortedArrayToBST(int arr[], int start, int end)
{
/* Base Case */
if (start > end)
return NULL;
return root;
}
return node;
}
return 0;
}
TimeComplexity:O(n)
FollowingistherecurrancerelationforsortedArrayToBST().
T(n)=2T(n/2)+C
T(n)>Timetakenforanarrayofsizen
C>Constant(Findingmiddleofarrayandlinkingroottoleft
andrightsubtreestakeconstanttime)
TheaboverecurrencecanbesolvedusingMasterTheoremasitfallsincase2.
================================================================
=======
Connectnodesatsamelevelusing
constantextraspace
Writeafunctiontoconnectalltheadjacentnodesatthesamelevelinabinarytree.Structureofthegiven
BinaryTreenodeislikefollowing.
struct node {
int data;
struct node* left;
struct node* right;
InputTree
A
/\
BC
/\\
DEF
OutputTree
A>NULL
/\
B>C>NULL
/\\
D>E>F>NULL
Wediscussedtwodifferentapproachestodoitinthepreviouspost.Theauxiliaryspacerequiredinbothof
thoseapproachesisnotconstant.Also,themethod2discussedthereonlyworksforcompleteBinaryTree.
Inthispost,wewillfirstmodifythemethod2tomakeitworkforallkindoftrees.Afterthat,wewillremove
recursionfromthismethodsothattheextraspacebecomesconstant.
ARecursiveSolution
Inthemethod2ofpreviouspost,wetraversedthenodesinpreorderfashion.InsteadoftraversinginPre
Orderfashion(root,left,right),ifwetraversethenextRightnodebeforetheleftandrightchildren(root,
nextRight,left),thenwecanmakesurethatallnodesatlevelihavethenextRightset,beforetheleveli+1
nodes.Letusconsiderthefollowingexample(sameexampleaspreviouspost).Themethod2failsforright
childofnode4.Inthismethod,wemakesurethatallnodesatthe4slevel(level2)havenextRightset,
beforewetrytosetthenextRightof9.SowhenwesetthenextRightof9,wesearchforanonleafnodeon
rightsideofnode4(getNextRight()doesthisforus).
1Level0
/\
23Level1
/\/\
4567Level2
/\/\
891011Level3
// Sets the nextRight of root and calls connectRecur() for other nodes
void connect (struct node *p)
{
// Set the nextRight for root
p->nextRight = NULL;
// Set the next right for rest of the nodes (other than root)
connectRecur(p);
}
/* Set next right of all descendents of p. This function makes sure that
nextRight of nodes ar level i is set before level i+1 nodes. */
void connectRecur(struct node* p)
{
// Base case
if (!p)
return;
else
p->left->nextRight = getNextRight(p);
/* Recursively call for next level nodes. Note that we call only
for left child. The call for left child will call for right child */
connectRecur(p->left);
}
/* If left child is NULL then first node of next level will either be
p->right or getNextRight(p) */
else if (p->right)
{
p->right->nextRight = getNextRight(p);
connectRecur(p->right);
}
else
connectRecur(getNextRight(p));
}
/* This function returns the leftmost child of nodes at the same level as p.
This function is used to getNExt right of p's right child
If right child of p is NULL then this can also be used for the left child */
struct node *getNextRight(struct node *p)
{
struct node *temp = p->nextRight;
// If all the nodes at p's level are leaf nodes then return NULL
return NULL;
}
AnIterativeSolution
Therecursiveapproachdiscussedabovecanbeeasilyconvertedtoiterative.Intheiterativeversion,weuse
nestedloop.Theouterloop,goesthroughallthelevelsandtheinnerloopgoesthroughallthenodesat
everylevel.Thissolutionusesconstantspace.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *left;
struct node *right;
struct node *nextRight;
};
/* This function returns the leftmost child of nodes at the same level as p.
This function is used to getNExt right of p's right child
If right child of is NULL then this can also be sued for the left child */
struct node *getNextRight(struct node *p)
{
struct node *temp = p->nextRight;
// If all the nodes at p's level are leaf nodes then return NULL
return NULL;
}
if (!p)
return;
/* Connect all childrem nodes of p and children nodes of all other nodes
at same level as p */
while (q != NULL)
{
// Set the nextRight pointer for p's left child
if (q->left)
{
// If q has right child, then right child is nextRight of
// p and we also need to set nextRight of right child
if (q->right)
q->left->nextRight = q->right;
else
q->left->nextRight = getNextRight(q);
}
if (q->right)
q->right->nextRight = getNextRight(q);
/* UTILITY FUNCTIONS */
/* Helper function that allocates a new node with the
given data and NULL left and right pointers. */
struct node* newnode(int data)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
node->nextRight = NULL;
return(node);
}
8 2
/
90
*/
struct node *root = newnode(10);
root->left
= newnode(8);
root->right
= newnode(2);
root->left->left = newnode(3);
root->right->right
= newnode(90);
getchar();
return 0;
}
Output:
FollowingarepopulatednextRightpointersinthetree(1isprintedif
thereisnonextRight)
nextRightof10is1
nextRightof8is2
nextRightof2is1
nextRightof3is90
nextRightof90is1
=======================================================================
Connectnodesatsamelevel
Writeafunctiontoconnectalltheadjacentnodesatthesamelevelinabinarytree.Structureofthegiven
BinaryTreenodeislikefollowing.
struct node{
int data;
struct node* left;
struct node* right;
struct node* nextRight;
}
Initially,allthenextRightpointerspointtogarbagevalues.Yourfunctionshouldsetthesepointerstopoint
nextrightforeachnode.
Example
InputTree
A
/\
BC
/\\
DEF
OutputTree
A>NULL
/\
B>C>NULL
/\\
D>E>F>NULL
Method1(ExtendLevelOrderTraversalorBFS)
Considerthemethod2ofLevelOrderTraversal.Themethod2caneasilybeextendedtoconnectnodesof
samelevel.Wecanaugmentqueueentriestocontainlevelofnodesalsowhichis0forroot,1forroots
childrenandsoon.Soaqueuenodewillnowcontainapointertoatreenodeandanintegerlevel.Whenwe
enqueueanode,wemakesurethatcorrectlevelvaluefornodeisbeingsetinqueue.TosetnextRight,for
everynodeN,wedequeuethenextnodefromqueue,ifthelevelnumberofnextnodeissame,wesetthe
nextRightofNasaddressofthedequeuednode,otherwisewesetnextRightofNasNULL.
TimeComplexity:O(n)
Method2(ExtendPreOrderTraversal)
ThisapproachworksonlyforCompleteBinaryTrees.InthismethodwesetnextRightinPreOrderfashion
tomakesurethatthenextRightofparentissetbeforeitschildren.Whenweareatnodep,wesetthe
nextRightofitsleftandrightchildren.Sincethetreeiscompletetree,nextRightofpsleftchild
(p>left>nextRight)willalwaysbepsrightchild,andnextRightofpsrightchild(p>right>nextRight)will
alwaysbeleftchildofpsnextRight(ifpisnottherightmostnodeatitslevel).Ifpistherightmostnode,then
nextRightofpsrightchildwillbeNULL.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *left;
struct node *right;
struct node *nextRight;
};
// Sets the nextRight of root and calls connectRecur() for other nodes
void connect (struct node *p)
{
// Set the nextRight for root
p->nextRight = NULL;
// Set the next right for rest of the nodes (other than root)
connectRecur(p);
}
/* UTILITY FUNCTIONS */
/* Helper function that allocates a new node with the
given data and NULL left and right pointers. */
struct node* newnode(int data)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
node->nextRight = NULL;
return(node);
}
\
2
/
3
*/
struct node *root = newnode(10);
root->left
= newnode(8);
root->right
= newnode(2);
root->left->left = newnode(3);
getchar();
return 0;
}
ThankstoDhanyaforsuggestingthisapproach.
TimeComplexity:O(n)
Whydoesntmethod2workfortreeswhicharenotCompleteBinaryTrees?
Letusconsiderfollowingtreeasanexample.InMethod2,wesetthenextRightpointerinpreorderfashion.
Whenweareatnode4,wesetthenextRightofitschildrenwhichare8and9(thenextRightof4isalready
setasnode5).nextRightof8willsimplybesetas9,butnextRightof9willbesetasNULLwhichis
incorrect.WecantsetthecorrectnextRight,becausewhenwesetnextRightof9,weonlyhavenextRight
ofnode4andancestorsofnode4,wedonthavenextRightofnodesinrightsubtreeofroot.
1
/\
23
/\/\
4567
/\/\
891011
=======================================================================
Trie|(Delete)
Inthepreviouspostontriewehavedescribedhowtoinsertandsearchanodeintrie.Hereisanalgorithm
howtodeleteanodefromtrie.
Duringdeleteoperationwedeletethekeyinbottomupmannerusingrecursion.Thefollowingarepossible
conditionswhendeletingkeyfromtrie,
1.
Keymaynotbethereintrie.Deleteoperationshouldnotmodifytrie.
2.
Keypresentasuniquekey(nopartofkeycontainsanotherkey(prefix),northekeyitselfisprefixof
anotherkeyintrie).Deleteallthenodes.
3.
Keyisprefixkeyofanotherlongkeyintrie.Unmarktheleafnode.
4.
Keypresentintrie,havingatleastoneotherkeyasprefixkey.Deletenodesfromendofkeyuntil
firstleafnodeoflongestprefixkey.
Thehighlightedcodepresentsalgorithmtoimplementaboveconditions.(Onemaybeindilemmahowa
pointerpassedtodeletehelperisreflectingchangesfromdeleteHelpertodeleteKey.Notethatweare
holdingtrieasanADTintrie_tnode,whichispassedbyreferenceorpointer).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FREE(p) \
free(p); \
p = NULL;
// forward declration
typedef struct trie_node trie_node_t;
// trie node
struct trie_node
{
int value; // non zero if leaf
trie_node_t *children[ALPHABET_SIZE];
};
// trie ADT
typedef struct trie trie_t;
struct trie
{
trie_node_t *root;
int count;
};
trie_node_t *getNode(void)
{
trie_node_t *pNode = NULL;
if( pNode )
{
int i;
pNode->value
= 0;
return pNode;
}
pTrie->count++;
pCrawl = pTrie->root;
if( pCrawl->children[index] )
{
// Skip current node
pCrawl = pCrawl->children[index];
}
else
{
// Add new node
pCrawl->children[index] = getNode();
pCrawl = pCrawl->children[index];
}
}
pCrawl = pTrie->root;
if( !pCrawl->children[index] )
{
return 0;
}
pCrawl = pCrawl->children[index];
}
return 1;
}
return false;
}
}
else // Recursive case
{
int index = INDEX(key[level]);
return false;
}
int main()
{
char keys[][8] = {"she", "sells", "sea", "shore", "the", "by", "sheer"};
trie_t trie;
initialize(&trie);
deleteKey(&trie, keys[0]);
return 0;
}
=======================================================================
Trie|(InsertandSearch)
Trieisanefficientinformationretrievaldatastructure.Usingtrie,searchcomplexitiescanbebroughtto
optimallimit(keylength).Ifwestorekeysinbinarysearchtree,awellbalancedBSTwillneedtime
proportionaltoM*logN,whereMismaximumstringlengthandNisnumberofkeysintree.Usingtrie,we
cansearchthekeyinO(M)time.Howeverthepenaltyisontriestoragerequirements.
Everynodeoftrieconsistsofmultiplebranches.Eachbranchrepresentsapossiblecharacterofkeys.We
needtomarkthelastnodeofeverykeyasleafnode.Atrienodefieldvaluewillbeusedtodistinguishthe
nodeasleafnode(thereareotherusesofthevaluefield).AsimplestructuretorepresentnodesofEnglish
alphabetcanbeasfollowing,
structtrie_node
{
intvalue/*Usedtomarkleafnodes*/
trie_node_t*children[ALPHABET_SIZE]
}
Insertingakeyintotrieissimpleapproach.Everycharacterofinputkeyisinsertedasanindividualtrie
node.Notethatthechildrenisanarrayofpointerstonextleveltrienodes.Thekeycharacteractsasan
indexintothearraychildren.Iftheinputkeyisneworanextensionofexistingkey,weneedtoconstruct
nonexistingnodesofthekey,andmarkleafnode.Iftheinputkeyisprefixofexistingkeyintrie,wesimply
markthelastnodeofkeyasleaf.Thekeylengthdeterminestriedepth.
Searchingforakeyissimilartoinsertoperation,howeverweonlycomparethecharactersandmovedown.
Thesearchcanterminateduetoendofstringorlackofkeyintrie.Intheformercase,ifthevaluefieldof
lastnodeisnonzerothenthekeyexistsintrie.Inthesecondcase,thesearchterminateswithoutexamining
allthecharactersofkey,sincethekeyisnotpresentintrie.
Thefollowingpictureexplainsconstructionoftrieusingkeysgivenintheexamplebelow,
root
/\\
tab
|||
hny
||\|
esye
/||
irw
|||
ree
|
r
Inthepicture,everycharacterisoftypetrie_node_t.Forexample,therootisoftypetrie_node_t,andits
childrena,bandtarefilled,allothernodesofrootwillbeNULL.Similarly,aatthenextlevelishavingonly
onechild(n),allotherchildrenareNULL.Theleafnodesareinblue.
InsertandsearchcostsO(key_length),howeverthememoryrequirementsoftrieisO(ALPHABET_SIZE*
key_length*N)whereNisnumberofkeysintrie.Thereareefficientrepresentationoftrienodes(e.g.
compressedtrie,ternarysearchtree,etc.)tominimizememoryrequirementsoftrie.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// trie node
typedef struct trie_node trie_node_t;
struct trie_node
{
int value;
trie_node_t *children[ALPHABET_SIZE];
};
// trie ADT
typedef struct trie trie_t;
struct trie
{
trie_node_t *root;
int count;
};
if( pNode )
{
int i;
pNode->value = 0;
return pNode;
}
{
pTrie->root = getNode();
pTrie->count = 0;
}
pTrie->count++;
pCrawl = pTrie->root;
pCrawl = pCrawl->children[index];
}
int index;
trie_node_t *pCrawl;
pCrawl = pTrie->root;
if( !pCrawl->children[index] )
{
return 0;
}
pCrawl = pCrawl->children[index];
}
// Driver
int main()
{
// Input keys (use only 'a' through 'z' and lower case)
char keys[][8] = {"the", "a", "there", "answer", "any", "by", "bye", "their"};
trie_t trie;
initialize(&trie);
// Construct trie
for(int i = 0; i < ARRAY_SIZE(keys); i++)
{
insert(&trie, keys[i]);
}
return 0;
}
=======================================================================
Checkifabinarytreeissubtreeof
anotherbinarytree|Set1
Giventwobinarytrees,checkifthefirsttreeissubtreeofthesecondone.AsubtreeofatreeTisatreeS
consistingofanodeinTandallofitsdescendantsinT.Thesubtreecorrespondingtotherootnodeisthe
entiretreethesubtreecorrespondingtoanyothernodeiscalledapropersubtree.
Forexample,inthefollowingcase,treeSisasubtreeoftreeT.
TreeS
10
/\
46
\
30
TreeT
26
/\
103
/\\
463
\
30
Solution:TraversethetreeTinpreorderfashion.Foreveryvisitednodeinthetraversal,seeifthesubtree
rootedwiththisnodeisidenticaltoS.
FollowingisCimplementationforthis.
#include <stdio.h>
#include <stdlib.h>
/* A binary tree node has data, left child and right child */
struct node
{
int data;
struct node* left;
struct node* right;
};
/* Check if the data of both roots is same and data of left and right
subtrees are also same */
return (root1->data == root2->data
&&
if (S == NULL)
return true;
if (T == NULL)
return false;
/* Helper function that allocates a new node with the given data
and NULL left and right pointers. */
struct node* newNode(int data)
{
struct node* node =
(struct node*)malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
10 3
/
\
30
*/
struct node *T
= newNode(26);
T->right
= newNode(3);
T->right->right
= newNode(3);
T->left
= newNode(10);
T->left->left
= newNode(4);
T->left->left->right = newNode(30);
T->left->right
= newNode(6);
\
6
\
30
*/
struct node *S = newNode(10);
S->right
= newNode(6);
S->left
= newNode(4);
S->left->right = newNode(30);
if (isSubtree(T, S))
printf("Tree S is subtree of tree T");
else
printf("Tree S is not a subtree of tree T");
getchar();
return 0;
}
Output:
TreeSissubtreeoftreeT
TimeComplexity:TimeworstcasecomplexityofabovesolutionisO(mn)wheremandnarenumberof
nodesingiventwotrees.
WecansolvetheaboveprobleminO(n)time.PleasereferCheckifabinarytreeissubtreeofanother
binarytree|Set2forO(n)solution.
=======================================================================
DecisionTreesFake(Counterfeit)
CoinPuzzle(12CoinPuzzle)
Letussolvetheclassicfakecoinpuzzleusingdecisiontrees.Therearethetwodifferentvariantsofthe
puzzlegivenbelow.Iamprovidingdescriptionofboththepuzzlesbelow,trytosolveonyourown,assume
N=8.
Easy:GivenatwopanfairbalanceandNidenticallylookingcoins,outofwhichonlyonecoinislighter(or
heavier).Tofigureouttheoddcoin,howmanyminimumnumberofweighingarerequiredintheworst
case?
Difficult:GivenatwopanfairbalanceandNidenticallylookingcoinsoutofwhichonlyonecoinmaybe
defective.Howcanwetracewhichcoin,ifany,isoddoneandalsodeterminewhetheritislighterorheavier
inminimumnumberoftrialsintheworstcase?
Letusstartwithrelativelysimpleexamples.Afterreadingeveryproblemtrytosolveonyourown.
Problem1:(Easy)
Given5coinsoutofwhichonecoinislighter.Intheworstcase,howmanyminimumnumberofweighing
arerequiredtofigureouttheoddcoin?
Namethecoinsas1,2,3,4and5.Weknowthatonecoinislighter.Consideringbestoutcomeofbalance,
wecangroupthecoinsintwodifferentways,[(1,2),(3,4)and(5)],or[(12),(34)and(5)].Wecaneasilyrule
outgroupslike[(123)and(45)],aswewillgetobviousanswer.Anyothercombinationwillfallintooneof
thesetwogroups,like[(2)(45)and(13)],etc.
Considerthefirstgroup,pairs(1,2)and(3,4).Wecancheck(1,2),iftheyareequalwegoaheadwith(3,
4).Weneedtwoweighinginworstcase.Thesameanalogycanbeappliedwhenthecoininheavier.
Withthesecondgroup,weigh(12)and(34).Iftheybalance(5)isdefectiveone,otherwisepickthelighter
pair,andweneedonemoreweighingtofindoddone.
Boththecombinationsneedtwoweighingincaseof5coinswithpriorinformationofonecoinislighter.
Analysis:Ingeneral,ifweknowthatthecoinisheavyorlight,wecantracethecoininlog3(N)trials
(roundedtonextinteger).Ifwerepresenttheoutcomeofbalanceasternarytree,everyleafrepresentan
outcome.SinceanycoinamongNcoinscanbedefective,weneedtogeta3arytreehavingminimumofN
leaves.A3arytreeatkthlevelwillhave3kleavesandhenceweneed3k>=N.
Inotherwords,inktrialswecanexamineupto3kcoins,ifweknowwhetherthedefectivecoinisheavieror
lighter.Giventhatacoinisheavier,verifythat3trialsaresufficienttofindtheoddcoinamong12coins,
because32<12<33.
Problem2:(Difficult)
Wearegiven4coins,outofwhichonlyonecoinmaybedefective.Wedontknow,whetherallcoinsare
genuineoranydefectiveoneispresent.Howmanynumberofweighingarerequiredinworstcasetofigure
outtheoddcoin,ifpresent?Wealsoneedtotellwhetheritisheavierorlighter.
Fromtheaboveanalysiswemaythinkthatk=2trialsaresufficient,sinceatwolevel3arytreeyields9
leaveswhichisgreaterthanN=4(readtheproblemonceagain).Notethatitisimpossibletosolveabove4
coinsproblemintwoweighing.Thedecisiontreeconfirmsthefact(trytodraw).
Wecangroupthecoinsintwodifferentways,[(12,34)]or[(1,2)and(3,4)].Letusconsiderthecombination
(12,34),thecorrespondingdecisiontreeisgivenbelow.Blueleavesarevalidoutcomes,andredleavesare
impossiblecases.Wearrivedatimpossiblecasesduetotheassumptionsmadeearlieronthepath.
Theoutcomecanbe(12)<(34)i.e.wegoontoleftsubtreeor(12)>(34)i.e.wegoontorightsubtree.
Theleftsubtreeispossibleintwoways,
A)Either1or2canbelighterOR
B)Either3or4canbeheavier.
Furtherontheleftsubtree,assecondtrial,weweigh(1,2)or(3,4).Letusconsider(3,4)astheanalogyfor
(1,2)issimilar.Theoutcomeofsecondtrailcanbethreeways
A)(3)<(4)yielding4asdefectiveheaviercoin,OR
B)(3)>(4)yielding3asdefectiveheaviercoinOR
C)(3)=(4),yieldingambiguity.Hereweneedonemoreweighingtocheckagenuinecoinagainst1
or2.InthefigureItook(3,2)where3isconfirmedasgenuine.Wecanget(3)>(2)inwhich2is
lighter,or(3)=(2)inwhich1islighter.Notethatitimpossibletoget(3)<(2),itcontradictsour
assumptionleanedtoleftside.
Similarlywecananalyzetherightsubtree.Weneedtwomoreweighingsonrightsubtreeaswell.
Overallweneed3weighingstotracetheoddcoin.Notethatweareunabletoutilizetwooutcomesof3ary
trees.Also,thetreeisnotfulltree,middlebranchterminatedafterfirstweighing.Infact,wecanget27
leavesof3levelfull3arytree,butonlywegot11leavesincludingimpossiblecases.
Analysis:GivenNcoins,allmaybegenuineoronlyonecoinisdefective.Weneedadecisiontreewith
atleast(2N+1)leavescorrespondtotheoutputs.BecausetherecanbeNleavestobelighter,orNleaves
tobeheavieroronegenuinecase,ontotal(2N+1)leaves.
Asexplainedearlierternarytreeatlevelk,canhaveutmost3kleavesandweneedatreewithleavesof3k>
(2N+1).
Inotherwords,weneedatleastk>log3(2N+1)weighingtofindthedefectiveone.
Observetheabovefigurethatnotallthebranchesaregeneratingleaves,i.e.wearemissingvalidoutputs
undersomebranchesthatleadingtomorenumberoftrials.Whenpossible,weshouldgroupthecoinsin
suchawaythateverybranchisgoingtoyieldvalidoutput(insimpletermsgeneratefull3arytree).Problem
4describesthisapproachof12coins.
Problem3:(Specialcaseoftwopanbalance)
Wearegiven5coins,agroupof4coinsoutofwhichonecoinisdefective(wedontknowwhetheritis
heavierorlighter),andonecoinisgenuine.Howmanyweighingarerequiredinworstcasetofigureoutthe
oddcoinwhetheritisheavierorlighter?
Labelthecoinsas1,2,3,4andG(genuine).Wenowhavesomeinformationoncoinpurity.Weneedto
makeusethatinthegroupings.
Wecanbestgroupthemas[(G1,23)and(4)].Anyothergroupcantgeneratefull3arytree,tryyourself.
Thefollowingdiagramexplainstheprocedure.
Themiddlecase(G1)=(23)isselfexplanatory,i.e.1,2,3aregenuineand4thcoincanbefiguredout
lighterorheavierinonemoretrial.
Theleftsideoftreecorrespondstothecase(G1)<(23).Thisispossibleintwoways,either1shouldbe
lighteroreitherof(2,3)shouldbeheavier.Theformerinstanceisobviouswhennextweighing(2,3)is
balanced,yielding1aslighter.Thelaterinstancecouldbe(2)<(3)yielding3asheavieror(2)>(3)yielding
2asheavier.Theleafnodesonleftbrancharenamedtoreflecttheseoutcomes.
Therightsideoftreecorrespondstothecase(G1)>(23).Thisispossibleintwoways,either1isheavieror
eitherof(2,3)shouldbelighter.Theformerinstanceisobviouswhenthenextweighing(2,3)isbalanced,
yielding1asheavier.Thelatercasecouldbe(2)<(3)yielding2aslightercoin,or(2)>(3)yielding3as
lighter.
Intheaboveproblem,underanypossibilityweneedonlytwoweighing.Weareabletousealloutcomesof
twolevelfull3arytree.Westartedwith(N+1)=5coinswhereN=4,weendupwith(2N+1)=9leaves.
Infactweshouldhave11outcomessincewestaredwith5coins,whereareother2outcomes?
Thesetwooutcomescanbedeclaredattherootoftreeitself(priortofirstweighing),canyoufigure
thesetwooutcomes?
Ifweobservethefigure,afterthefirstweighingtheproblemreducedtoweknowthreecoins,eitheronecan
belighter(heavier)oroneamongothertwocanbeheavier(lighter).Thiscanbesolvedinoneweighing
(readProblem1).
Analysis:Given(N+1)coins,oneisgenuineandtherestNcanbegenuineoronlyonecoinisdefective.
Therequireddecisiontreeshouldresultinminimumof(2N+1)leaves.Sincethetotalpossibleoutcomes
are(2(N+1)+1),numberofweighing(trials)aregivenbytheheightofternarytree,k>=log3[2(N+1)+1].
Notetheequalitysign.
RearrangingkandN,wecanweighmaximumofN<=(3k3)/2coinsinktrials.
Problem4:(Theclassic12coinpuzzle)
Youaregiventwopanfairbalance.Youhave12identicallylookingcoinsoutofwhichonecoinmaybe
lighterorheavier.Howcanyoufindoddcoin,ifany,inminimumtrials,alsodeterminewhetherdefective
coinislighterorheavier,intheworstcase?
Howdoyouwanttogroupthem?Bisetortriset?Clearlywecandiscardtheoptionofdividingintotwo
equalgroups.Itcantleadtobesttree.Fromtheabovetwoexamples,wecanensurethatthedecisiontree
canbeusedinoptimalwayifwecanrevealatleasetonegenuinecoin.Remembertogroupcoinssuchthat
thefirstweighingrevealsatleastonegenuinecoin.
Letusnamethecoinsas1,2,8,A,B,CandD.Wecancombinethecoinsinto3groups,namely(1234),
(5678)and(ABCD).Weigh(1234)and(5678).Youareencouragedtodrawdecisiontreewhilereadingthe
procedure.Theoutcomecanbethreeways,
1.
(1234)=(5678),bothgroupsareequal.Defectivecoinmaybein(ABCD)group.
2.
(1234)<(5678),i.e.firstgroupislessinweightthansecondgroup.
3.
(1234)>(5678),i.e.firstgroupismoreinweightthansecondgroup.
Theoutput(1)canbesolvedintwomoreweighingasspecialcaseoftwopanbalancegiveninProblem3.
Weknowthatgroups(1234)and(5678)aregenuineanddefectivecoinmaybein(ABCD).Pickone
genuinecoinfromanyofweighedgroups,andproceedwith(ABCD)asexplainedinProblem3.
Outcomes(2)and(3)arespecial.Inboththecases,weknowthat(ABCD)isgenuine.Andalso,weknowa
setofcoinsbeinglighterandasetofcoinsbeingheavier.Weneedtoshuffletheweighedtwogroupsin
suchawaythatweendupwithsmallerheightdecisiontree.
Considerthesecondoutcomewhere(1234)<(5678).Itispossiblewhenanycoinamong(1,2,3,4)is
lighteroranycoinamong(5,6,7,8)isheavier.Werevealedlighterorheavierpossibilityafterfirst
weighing.IfweproceedasinProblem1,wewillnotgeneratebestdecisiontree.Letusshufflecoinsas
(1235)and(4BCD)asnewgroups(therearedifferentshufflespossible,theyalsoleadtominimum
weighing,canyoutry?).Ifweweighthesetwogroupsagaintheoutcomecanbethreeways,i)(1235)<
(4BCD)yieldingoneamong1,2,3islighterwhichissimilartoProblem1explainedabove,weneedone
moreweighing,ii)(1235)=(4BCD)yieldingoneamong6,7,8isheavierwhichissimilartoProblem1
explainedabove,weneedonemoreweighingiii)(1235)>(4BCD)yieldingeither5asheaviercoinor4as
lightercoin,attheexpenseofonemoreweighing.
Similarwaywecanalsosolvetherightsubtree(thirdoutcomewhere(1234)>(5678))intwomoreweighing.
Weareabletosolvethe12coinpuzzlein3weighingintheworstcase.
FewInterestingPuzzles:
1.
SolveProblem4withN=8andN=13,Howmanyminimumtrialsarerequiredineachcase?
2.
Givenafunctionintweigh(A[],B[])whereAandBarearrays(neednotbeequalsize).Thefunction
returns1,0or1.Itreturns0ifsumofallelementsinAandBareequal,1ifA<Band1ifA>B.
Givenanarrayof12elements,allelementsareequalexceptone.Theoddelementcanbeasthat
ofothers,smallerorgreaterthanothers.Writeaprogramtofindtheoddelement(ifany)using
weigh()minimumnumberoftimes.
3.
Youmighthaveseen3panbalanceinsciencelabsduringschooldays.Givena3panbalance(4
outcomes)andNcoins,howmanyminimumtrialsareneededtofigureoutoddcoin?
=======================================================================
CheckifagivenBinaryTreeis
SumTree
WriteafunctionthatreturnstrueifthegivenBinaryTreeisSumTreeelsefalse.ASumTreeisaBinaryTree
wherethevalueofanodeisequaltosumofthenodespresentinitsleftsubtreeandrightsubtree.An
emptytreeisSumTreeandsumofanemptytreecanbeconsideredas0.Aleafnodeisalsoconsideredas
SumTree.
FollowingisanexampleofSumTree.
26
/\
103
/\\
463
Method1(Simple)
Getthesumofnodesinleftsubtreeandrightsubtree.Checkifthesumcalculatedisequaltorootsdata.
Also,recursivelycheckiftheleftandrightsubtreesareSumTrees.
#include <stdio.h>
#include <stdlib.h>
/* A binary tree node has data, left child and right child */
struct node
{
int data;
struct node* left;
struct node* right;
};
if(root == NULL)
return 0;
return sum(root->left) + root->data + sum(root->right);
}
return 0;
}
/*
Helper function that allocates a new node
with the given data and NULL left and right
pointers.
*/
struct node* newNode(int data)
{
struct node* node =
(struct node*)malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
= newNode(10);
root->right
= newNode(3);
root->left->left
= newNode(4);
root->left->right = newNode(6);
root->right->right = newNode(3);
if(isSumTree(root))
printf("The given tree is a SumTree ");
else
printf("The given tree is not a SumTree ");
getchar();
return 0;
}
TimeComplexity:O(n^2)inworstcase.Worstcaseoccursforaskewedtree.
Method2(Tricky)
TheMethod1usessum()togetthesumofnodesinleftandrightsubtrees.Themethod2usesfollowing
rulestogetthesumdirectly.
1)Ifthenodeisaleafnodethensumofsubtreerootedwiththisnodeisequaltovalueofthisnode.
2)Ifthenodeisnotaleafnodethensumofsubtreerootedwiththisnodeistwicethevalueofthisnode
(AssumingthatthetreerootedwiththisnodeisSumTree).
#include <stdio.h>
#include <stdlib.h>
/* A binary tree node has data, left child and right child */
struct node
{
int data;
struct node* left;
struct node* right;
};
ls = 2*(node->left->data);
return 0;
}
= newNode(10);
root->right
= newNode(3);
root->left->left
= newNode(4);
root->left->right = newNode(6);
root->right->right = newNode(3);
if(isSumTree(root))
printf("The given tree is a SumTree ");
else
printf("The given tree is not a SumTree ");
getchar();
return 0;
}
TimeComplexity:O(n)
WriteafunctionthatreturnstrueifthegivenBinaryTreeisSumTreeelsefalse.ASumTreeisaBinaryTree
wherethevalueofanodeisequaltosumofthenodespresentinitsleftsubtreeandrightsubtree.An
emptytreeisSumTreeandsumofanemptytreecanbeconsideredas0.Aleafnodeisalsoconsideredas
SumTree.
FollowingisanexampleofSumTree.
26
/\
103
/\\
463
Method1(Simple)
Getthesumofnodesinleftsubtreeandrightsubtree.Checkifthesumcalculatedisequaltorootsdata.
Also,recursivelycheckiftheleftandrightsubtreesareSumTrees.
#include <stdio.h>
#include <stdlib.h>
/* A binary tree node has data, left child and right child */
struct node
{
int data;
struct node* left;
struct node* right;
};
return 0;
}
/*
Helper function that allocates a new node
= newNode(10);
root->right
= newNode(3);
root->left->left
= newNode(4);
root->left->right = newNode(6);
root->right->right = newNode(3);
if(isSumTree(root))
printf("The given tree is a SumTree ");
else
printf("The given tree is not a SumTree ");
getchar();
return 0;
}
TimeComplexity:O(n^2)inworstcase.Worstcaseoccursforaskewedtree.
Method2(Tricky)
TheMethod1usessum()togetthesumofnodesinleftandrightsubtrees.Themethod2usesfollowing
rulestogetthesumdirectly.
1)Ifthenodeisaleafnodethensumofsubtreerootedwiththisnodeisequaltovalueofthisnode.
2)Ifthenodeisnotaleafnodethensumofsubtreerootedwiththisnodeistwicethevalueofthisnode
(AssumingthatthetreerootedwiththisnodeisSumTree).
#include <stdio.h>
#include <stdlib.h>
/* A binary tree node has data, left child and right child */
struct node
{
int data;
struct node* left;
struct node* right;
};
ls = 0;
else if(isLeaf(node->left))
ls = node->left->data;
else
ls = 2*(node->left->data);
return 0;
}
int main()
{
struct node *root = newNode(26);
root->left
= newNode(10);
root->right
= newNode(3);
root->left->left
= newNode(4);
root->left->right = newNode(6);
root->right->right = newNode(3);
if(isSumTree(root))
printf("The given tree is a SumTree ");
else
printf("The given tree is not a SumTree ");
getchar();
return 0;
}
TimeComplexity:O(n)
================================================================
=======
TournamentTree(WinnerTree)and
BinaryHeap
GivenateamofNplayers.Howmanyminimumgamesarerequiredtofindsecondbestplayer?
Wecanuseadversaryargumentsbasedontournamenttree(BinaryHeap).
Tournamenttreeisaformofmin(max)heapwhichisacompletebinarytree.Everyexternalnode
representsaplayerandinternalnoderepresentswinner.Inatournamenttreeeveryinternalnodecontains
winnerandeveryleafnodecontainsoneplayer.
TherewillbeN1internalnodesinabinarytreewithNleaf(external)nodes.Fordetailsseethispost(put
n=2inequationgiveninthepost).
ItisobviousthattoselectthebestplayeramongNplayers,(N1)playerstobeeliminated,i.e.weneed
minimumof(N1)games(comparisons).Mathematicallywecanproveit.InabinarytreeI=E1,whereI
isnumberofinternalnodesandEisnumberofexternalnodes.Itmeanstofindmaximumorminimum
elementofanarray,weneedN1(internalnodes)comparisons.
SecondBestPlayer
Theinformationexploredduringbestplayerselectioncanbeusedtominimizethenumberofcomparisons
intracingthenextbestplayers.Forexample,wecanpicksecondbestplayerin(N+log2N2)
comparisons.Fordetailsreadthiscomment.
Thefollowingdiagramdisplaysatournamenttree(winnertree)asamaxheap.Notethattheconceptof
losertreeisdifferent.
Theabovetreecontains4leafnodesthatrepresentplayersandhave3levels0,1and2.Initially2games
areconductedatlevel2,onebetween5and3andanotheronebetween7and8.Inthenextmove,one
moregameisconductedbetween5and8toconcludethefinalwinner.Overallweneed3comparisons.For
secondbestplayerweneedtotracethecandidatesparticipatedwithfinalwinner,thatleadsto7assecond
best.
MedianofSortedArrays
Tournamenttreecaneffectivelybeusedtofindmedianofsortedarrays.Assume,givenMsortedarraysof
equalsizeL(forsimplicity).Wecanattachallthesesortedarraystothetournamenttree,onearrayperleaf.
WeneedatreeofheightCEIL(log2M)tohaveatleastMexternalnodes.
Consideranexample.Given3(M=3)sortedintegerarraysofmaximumsize5elements.
{2,5,7,11,15}Array1
{1,3,4}Array2
{6,8,12,13,14}Array3
Whatshouldbetheheightoftournamenttree?Weneedtoconstructatournamenttreeofheightlog23.=
1.585=2roundedtonextinteger.Abinarytreeofheight2willhave4leavestowhichwecanattachthe
arraysasshowninthebelowfigure.
Afterthefirsttournament,thetreeappearsasbelow,
WecanobservethatthewinnerisfromArray2.HencethenextelementfromArray2willdiveinandgames
willbeplayedalongthewinnerpathofprevioustournament.
Notethatinfinityisusedassentinelelement.Basedondatabeingholdinnodeswecanselectthesentinel
character.Forexampleweusuallystorethepointersinnodesratherthankeys,soNULLcanserveas
sentinel.Ifanyofthearrayexhaustswewillfillthecorrespondingleafandupcominginternalnodeswith
sentinel.
Afterthesecondtournament,thetreeappearsasbelow,
ThenextwinnerisfromArray1,sonextelementofArray1arraywhichis5willdiveintothenextround,and
nexttournamentplayedalongthepathof2.
Thetournamentscanbecontinuedtillwegetmedianelementwhichis(5+3+5)/2=7thelement.Notethat
thereareevenbetteralgorithmsforfindingmedianofunionofsortedarrays,fordetailsseetherelatedlinks
givenbelow.
IngeneralwithMsortedlistsofsizeL1,L2LmrequirestimecomplexityofO((L1+L2++Lm)*logM)to
mergeallthearrays,andO(m*logM)timetofindmedian,wheremismedianposition.
Selectsmallestonemillionelementsfromonebillionunsortedelements:
Asasimplesolution,wecansortthebillionnumbersandselectfirstonemillion.
Onalimitedmemorysystemsortingbillionelementsandpickingthefirstonemillionseemstobe
impractical.Wecanusetournamenttreeapproach.Atanytimeonlyelementsoftreetobeinmemory.
Splitthelargearray(perhapsstoredondisk)intosmallersizearraysofsizeonemillioneach(oreven
smallerthatcanbesortedbythemachine).Sortthese1000smallsizearraysandstorethemondiskas
individualfiles.Constructatournamenttreewhichcanhaveatleast1000leafnodes(treetobeofheight10
since29<1000<210,iftheindividualfilesizeisevensmallerwewillneedmoreleafnodes).Everyleafnode
willhaveanenginethatpicksnextelementfromthesortedfilestoredondisk.Wecanplaythetournament
treegametoextractfirstonemillionelements.
Totalcost=sorting1000listsofonemillioneach+treeconstruction+tournaments
Implementation
Weneedtobuildthetree(heap)inbottomupmanner.Alltheleafnodesfilledfirst.Startattheleftextreme
oftreeandfillalongthebreadth(i.e.from2k1to2k1wherekisdepthoftree)andplaythegame.After
practicingwithfewexamplesitwillbeeasytowritecode.Wewillhavecodeinanupcomingarticle.
================================================================
=======
PrintBSTkeysinthegivenrange
Giventwovaluesk1andk2(wherek1<k2)andarootpointertoaBinarySearchTree.Printallthekeysof
treeinrangek1tok2.i.e.printallxsuchthatk1<=x<=k2andxisakeyofgivenBST.Printallthekeysin
increasingorder.
Forexample,ifk1=10andk2=22,thenyourfunctionshouldprint12,20and22.
Thankstobhaskerforsuggestingthefollowingsolution.
Algorithm:
1)Ifvalueofrootskeyisgreaterthank1,thenrecursivelycallinleftsubtree.
2)Ifvalueofrootskeyisinrange,thenprinttherootskey.
3)Ifvalueofrootskeyissmallerthank2,thenrecursivelycallinrightsubtree.
Implementation:
#include<stdio.h>
/* The functions prints all the keys which in the given range [k1..k2].
The function assumes than k1 < k2 */
void Print(struct node *root, int k1, int k2)
{
/* base case */
if ( NULL == root )
return;
/* Since the desired o/p is sorted, recurse for left subtree first
If root->data is greater than k1, then only we can get o/p keys
in left subtree */
if ( k1 < root->data )
Print(root->left, k1, k2);
/* If root->data is smaller than k2, then only we can get o/p keys
in right subtree */
if ( k2 > root->data )
Print(root->right, k1, k2);
}
return temp;
}
getchar();
return 0;
}
Output:
122022
TimeComplexity:O(n)wherenisthetotalnumberofkeysintree.
=======================================================================
PrintAncestorsofagivennodein
BinaryTree
GivenaBinaryTreeandakey,writeafunctionthatprintsalltheancestorsofthekeyinthegivenbinary
tree.
Forexample,ifthegiventreeisfollowingBinaryTreeandkeyis7,thenyourfunctionshouldprint4,2and
1.
1
/\
23
/\
45
/
7
ThankstoMike,Sambasivaandwgpshashankfortheircontribution.
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
if (root->data == target)
return true;
return true;
}
return(node);
}
2 3
/ \
4
/
7
*/
struct node *root = newnode(1);
root->left
= newnode(2);
root->right
= newnode(3);
root->left->left = newnode(4);
root->left->right = newnode(5);
root->left->left->left = newnode(7);
printAncestors(root, 7);
getchar();
return 0;
}
Output:
421
TimeComplexity:O(n)wherenisthenumberofnodesinthegivenBinaryTree.
=======================================================================
GetLevelofanodeinaBinaryTree
GivenaBinaryTreeandakey,writeafunctionthatreturnslevelofthekey.
Forexample,considerthefollowingtree.Iftheinputkeyis3,thenyourfunctionshouldreturn1.Iftheinput
keyis4,thenyourfunctionshouldreturn3.Andforkeywhichisnotpresentinkey,thenyourfunction
shouldreturn0.
Thankstoprandeeyforsuggestingthefollowingsolution.
Theideaistostartfromtherootandlevelas1.Ifthekeymatcheswithrootsdata,returnlevel.Else
recursivelycallforleftandrightsubtreeswithlevelaslevel+1.
#include<stdio.h>
{
int data;
struct node *left;
struct node *right;
};
if (node->data == data)
return level;
return temp;
}
getchar();
return 0;
}
Output:
Levelof1is3
Levelof2is2
Levelof3is1
Levelof4is3
Levelof5is2
TimeComplexity:O(n)wherenisthenumberofnodesinthegivenBinaryTree.
================================================================
=======
FindkthsmallestelementinBST
(OrderStatisticsinBST)
GivenrootofbinarysearchtreeandKasinput,findKthsmallestelementinBST.
Forexample,inthefollowingBST,ifk=3,thenoutputshouldbe10,andifk=5,thenoutputshouldbe14.
Method1:UsingInorderTraversal.
InordertraversalofBSTretrieveselementsoftreeinthesortedorder.Theinordertraversalusesstackto
storetobeexplorednodesoftree(threadedtreeavoidsstackandrecursionfortraversal,seethispost).The
ideaistokeeptrackofpoppedelementswhichparticipateintheorderstatics.Hypotheticalalgorithmis
providedbelow,
Timecomplexity:O(n)wherenistotalnodesintree..
Algorithm:
/*initialization*/
pCrawl=root
setinitialstackelementasNULL(sentinal)
/*traverseuptoleftextreme*/
while(pCrawlisvalid)
stack.push(pCrawl)
pCrawl=pCrawl.left
/*processothernodes*/
while(pCrawl=stack.pop()isvalid)
stopifsufficientnumberofelementsarepopped.
if(pCrawl.rightisvalid)
pCrawl=pCrawl.right
while(pCrawlisvalid)
stack.push(pCrawl)
pCrawl=pCrawl.left
Implementation:
#include <stdio.h>
#include <stdlib.h>
/* same alias */
typedef struct node_t node_t;
node_t* left;
node_t* right;
};
struct stack_t
{
node_t* base[ARRAY_SIZE(ele) + 1];
int
stackIndex;
};
return ret;
}
/* Iterative insertion
Recursion is least preferred unless we gain something
*/
node_t *insert_node(node_t *root, node_t* node)
{
/* A crawling pointer */
node_t *pTraverse = root;
return root;
}
/* initialize */
new_node->data
= keys[iterator];
new_node->left
= NULL;
new_node->right = NULL;
return root;
}
{
/* each pop operation emits one element
in the order
*/
if( !--k )
{
/* loop testing */
st->stackIndex = 0;
break;
}
int k = 5;
if( kNode )
{
printf("kth smallest elment for k = %d is %d", k, kNode->data);
}
else
{
printf("There is no such element");
}
getchar();
return 0;
}
Method2:AugmentedTreeDataStructure.
Theideaistomaintainrankofeachnode.Wecankeeptrackofelementsinasubtreeofanynodewhile
buildingthetree.SinceweneedKthsmallestelement,wecanmaintainnumberofelementsofleftsubtree
ineverynode.
AssumethattherootishavingNnodesinitsleftsubtree.IfK=N+1,rootisKthnode.IfK<N,wewill
continueoursearch(recursion)fortheKthsmallestelementintheleftsubtreeofroot.IfK>N+1,we
continueoursearchintherightsubtreeforthe(KN1)thsmallestelement.Notethatweneedthecount
ofelementsinleftsubtreeonly.
Timecomplexity:O(n)wherenistotalnodesintree.
Algorithm:
start:
ifK=root.leftElement+1
rootnodeistheKthnode.
gotostop
elseifK>root.leftElements
K=K(root.leftElements+1)
root=root.right
gotostart
else
root=root.left
gotosrart
stop:
Implementation:
#include <stdio.h>
#include <stdlib.h>
node_t* left;
node_t* right;
};
/* Iterative insertion
Recursion is least preferred unless we gain something
*/
node_t *insert_node(node_t *root, node_t* node)
{
/* A crawling pointer */
node_t *pTraverse = root;
node_t *currentParent = root;
return root;
}
int iterator;
node_t *new_node = NULL;
/* initialize */
new_node->data
= keys[iterator];
new_node->lCount = 0;
new_node->left
= NULL;
new_node->right = NULL;
return root;
}
if( root )
{
/* A crawling pointer */
node_t *pTraverse = root;
/* Go to k-th smallest */
while(pTraverse)
{
if( (pTraverse->lCount + 1) == k )
{
ret = pTraverse->data;
break;
}
return ret;
}
getchar();
return 0;
}
=======================================================================
InorderSuccessorinBinarySearch
Tree
InBinaryTree,InordersuccessorofanodeisthenextnodeinInordertraversaloftheBinaryTree.Inorder
SuccessorisNULLforthelastnodeinInoordertraversal.
InBinarySearchTree,InorderSuccessorofaninputnodecanalsobedefinedasthenodewiththesmallest
keygreaterthanthekeyofinputnode.So,itissometimesimportanttofindnextnodeinsortedorder.
Intheabovediagram,inordersuccessorof8is10,inordersuccessorof10is12andinordersuccessorof
14is20.
Method1(UsesParentPointer)
Inthismethod,weassumethateverynodehasparentpointer.
TheAlgorithmisdividedintotwocasesonthebasisofrightsubtreeoftheinputnodebeingemptyornot.
Input:node,root//nodeisthenodewhoseInordersuccessorisneeded.
output:succ//succisInordersuccessorofnode.
1)IfrightsubtreeofnodeisnotNULL,thensuccliesinrightsubtree.Dofollowing.
Gotorightsubtreeandreturnthenodewithminimumkeyvalueinrightsubtree.
2)IfrightsbtreeofnodeisNULL,thensuccisoneoftheancestors.Dofollowing.
Travelupusingtheparentpointeruntilyouseeanodewhichisleftchildofitsparent.Theparentofsucha
nodeisthesucc.
Implementation
NotethatthefunctiontofindInOrderSuccessorishighlighted(withgraybackground)inbelowcode.
#include <stdio.h>
#include <stdlib.h>
value found in that tree. Note that the entire tree does not need
to be searched. */
struct node * minValue(struct node* node) {
struct node* current = node;
/* Helper function that allocates a new node with the given data and
NULL left and right pointers. */
struct node* newNode(int data)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->data
= data;
node->left
= NULL;
node->right = NULL;
node->parent = NULL;
return(node);
}
/* Give a binary search tree and a number, inserts a new node with
the given number in the correct place in the tree. Returns the new
root pointer which the caller should then use (the standard trick to
avoid using reference parameters). */
struct node* insert(struct node* node, int data)
{
/* 1. If the tree is empty, return a new,
single node */
if (node == NULL)
return(newNode(data));
else
{
struct node *temp;
getchar();
return 0;
}
Outputoftheaboveprogram:
InorderSuccessorof14is20
TimeComplexity:O(h)wherehisheightoftree.
Method2(Searchfromroot)
ParentpointerisNOTneededinthisalgorithm.TheAlgorithmisdividedintotwocasesonthebasisofright
subtreeoftheinputnodebeingemptyornot.
Input:node,root//nodeisthenodewhoseInordersuccessorisneeded.
output:succ//succisInordersuccessorofnode.
1)IfrightsubtreeofnodeisnotNULL,thensuccliesinrightsubtree.Dofollowing.
Gotorightsubtreeandreturnthenodewithminimumkeyvalueinrightsubtree.
2)IfrightsbtreeofnodeisNULL,thenstartfromrootandussearchliketechnique.Dofollowing.
Traveldownthetree,ifanodesdataisgreaterthanrootsdatathengorightside,otherwisegotoleftside.
struct node * inOrderSuccessor(struct node *root, struct node *n)
{
// step 1 of the above algorithm
if( n->right != NULL )
return minValue(n->right);
// Start from root and search for successor down the tree
while (root != NULL)
{
if (n->data < root->data)
{
succ = root;
root = root->left;
}
else if (n->data > root->data)
root = root->right;
else
break;
}
return succ;
}
TimeComplexity:O(h)wherehisheightoftree.
=======================================================================
Applicationsoftreedatastructure
DifficultyLevel:Rookie
WhyTree?
UnlikeArrayandLinkedList,whicharelineardatastructures,treeishierarchical(ornonlinear)data
structure.
1)
Onereasontousetreesmightbebecauseyouwanttostoreinformationthatnaturallyformsa
hierarchy.Forexample,thefilesystemonacomputer:
filesystem
/<root
/\
...home
/\
ugradcourse
//|\
...cs101cs112cs113
2)
Ifweorganizekeysinformofatree(withsomeorderinge.g.,BST),wecansearchforagivenkey
inmoderatetime(quickerthanLinkedListandslowerthanarrays).SelfbalancingsearchtreeslikeAVLand
RedBlacktreesguaranteeanupperboundofO(Logn)forsearch.
3)
Wecaninsert/deletekeysinmoderatetime(quickerthanArraysandslowerthanUnorderedLinked
Lists).SelfbalancingsearchtreeslikeAVLandRedBlacktreesguaranteeanupperboundofO(Logn)for
insertion/deletion.
4)
LikeLinkedListsandunlikeArrays,Pointerimplementationoftreesdonthaveanupperlimiton
numberofnodesasnodesarelinkedusingpointers.
AsperWikipedia,followingarethecommonusesoftree.
1.
Manipulatehierarchicaldata.
2.
Makeinformationeasytosearch(seetreetraversal).
3.
Manipulatesortedlistsofdata.
4.
Asaworkflowforcompositingdigitalimagesforvisualeffects.
5.
Routeralgorithms
=======================================================================
Sortedorderprintingofagiven
arraythatrepresentsaBST
GivenanarraythatstoresacompleteBinarySearchTree,writeafunctionthatefficientlyprintsthegiven
arrayinascendingorder.
Forexample,givenanarray[4,2,5,1,3],thefunctionshouldprint1,2,3,4,5
Solution:
InordertraversalofBSTprintsitinascendingorder.Theonlytrickistomodifyrecursiontermination
conditioninstandardInorderTreeTraversal.
Implementation:
#include<stdio.h>
// print root
printf("%d ", arr[start]);
int main()
{
int arr[] = {4, 2, 5, 1, 3};
int arr_size = sizeof(arr)/sizeof(int);
printSorted(arr, 0, arr_size-1);
getchar();
return 0;
}
TimeComplexity:O(n)
=======================================================================
Printnodesatkdistancefromroot
Givenarootofatree,andanintegerk.Printallthenodeswhichareatkdistancefromroot.
Forexample,inthebelowtree,4,5&8areatdistance2fromroot.
1
/\
23
/\/
458
Theproblemcanbesolvedusingrecursion.Thankstoeldhoforsuggestingthesolution.
#include <stdio.h>
#include <stdlib.h>
node->right = NULL;
return(node);
}
/ \
4 5 8
*/
struct node *root = newNode(1);
root->left
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(8);
printKDistant(root, 2);
getchar();
return 0;
}
Theaboveprogramprints4,5and8.
TimeComplexity:O(n)wherenisnumberofnodesinthegivenbinarytree.
=======================================================================
FoldableBinaryTrees
Question:Givenabinarytree,findoutifthetreecanbefoldedornot.
Atreecanbefoldedifleftandrightsubtreesofthetreearestructurewisemirrorimageofeachother.An
emptytreeisconsideredasfoldable.
Considerthebelowtrees:
(a)and(b)canbefolded.
(c)and(d)cannotbefolded.
(a)
10
/\
715
\/
911
(b)
10
/\
715
/\
911
(c)
10
/\
715
//
511
(d)
10
/\
715
/\/
91012
Method1(ChangeLeftsubtreetoitsMirrorandcompareitwithRightsubtree)
Algorithm:isFoldable(root)
1)Iftreeisempty,thenreturntrue.
2)Converttheleftsubtreetoitsmirrorimage
mirror(root>left)/*Seethispost*/
3)Checkifthestructureofleftsubtreeandrightsubtreeissame
andstoretheresult.
res=isStructSame(root>left,root>right)/*isStructSame()
recursivelycomparesstructuresoftwosubtreesandreturns
trueifstructuresaresame*/
4)Revertthechangesmadeinstep(2)togettheoriginaltree.
mirror(root>left)
5)Returnresultresstoredinstep2.
Thankstoajaymforsuggestingthisapproach.
#include<stdio.h>
#include<stdlib.h>
/* base case */
if(root == NULL)
return true;
return res;
}
return false;
}
/* UTILITY FUNCTIONS */
/* Change a tree so that the roles of the left and
right pointers are swapped at every node.
See http://geeksforgeeks.org/?p=662 for details */
void mirror(struct node* node)
{
if (node==NULL)
return;
else
{
struct node* temp;
/* do the subtrees */
mirror(node->left);
mirror(node->right);
= node->left;
node->left = node->right;
node->right = temp;
}
}
return(node);
}
4 5
*/
struct node *root = newNode(1);
root->left
= newNode(2);
root->right
= newNode(3);
root->right->left = newNode(4);
root->left->right = newNode(5);
if(isFoldable(root) == 1)
{ printf("\n tree is foldable"); }
else
{ printf("\n tree is not foldable"); }
getchar();
return 0;
}
Timecomplexity:O(n)
Method2(CheckifLeftandRightsubtreesareMirror)
Therearemainlytwofunctions:
//Checksiftreecanbefoldedornot
IsFoldable(root)
1)Iftreeisemptythenreturntrue
2)Elsecheckifleftandrightsubtreesarestructurewisemirrorsof
eachother.UseutilityfunctionIsFoldableUtil(root>left,
root>right)forthis.
//Checksifn1andn2aremirrorofeachother.
IsFoldableUtil(n1,n2)
1)Ifbothtreesareemptythenreturntrue.
2)Ifoneofthemisemptyandotherisnotthenreturnfalse.
3)Returntrueiffollowingconditionsaremet
a)n1>leftismirrorofn2>right
b)n1>rightismirrorofn2>left
#include<stdio.h>
#include<stdlib.h>
/*UTILITY FUNCTIONS */
/* Helper function that allocates a new node with the
given data and NULL left and right pointers. */
struct node* newNode(int data)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
1
/
4 5
*/
struct node *root = newNode(1);
root->left
= newNode(2);
root->right
= newNode(3);
root->left->right = newNode(4);
root->right->left = newNode(5);
if(IsFoldable(root) == true)
{ printf("\n tree is foldable"); }
else
{ printf("\n tree is not foldable"); }
getchar();
return 0;
}
================================================================
=======
TotalnumberofpossibleBinary
SearchTreeswithnkeys
TotalnumberofpossibleBinarySearchTreeswithndifferentkeys=CatalannumberCn=(2n)!/(n+1)!*n!
Seereferencesforproofandexamples.
References:
http://en.wikipedia.org/wiki/Catalan_number
=======================================================================
Maximumwidthofabinarytree
Givenabinarytree,writeafunctiontogetthemaximumwidthofthegiventree.Widthofatreeismaximum
ofwidthsofalllevels.
Letusconsiderthebelowexampletree.
1
/\
23
/\\
458
/\
67
Fortheabovetree,
widthoflevel1is1,
widthoflevel2is2,
widthoflevel3is3
widthoflevel4is2.
Sothemaximumwidthofthetreeis3.
Method1(UsingLevelOrderTraversal)
Thismethodmainlyinvolvestwofunctions.Oneistocountnodesatagivenlevel(getWidth),andotheristo
getthemaximumwidthofthetree(getMaxWidth).getMaxWidth()makesuseofgetWidth()togetthewidthof
alllevelsstartingfromroot.
/*Functiontoprintlevelordertraversaloftree*/
getMaxWidth(tree)
maxWdth=0
fori=1toheight(tree)
width=getWidth(tree,i)
if(width>maxWdth)
maxWdth=width
returnwidth
/*Functiontogetwidthofagivenlevel*/
getWidth(tree,level)
iftreeisNULLthenreturn0
iflevelis1,thenreturn1
elseiflevelgreaterthan1,then
returngetWidth(tree>left,level1)+
getWidth(tree>right,level1)
#include <stdio.h>
#include <stdlib.h>
/*Function protoypes*/
int getWidth(struct node* root, int level);
int height(struct node* node);
struct node* newNode(int data);
maxWidth = width;
}
return maxWidth;
}
if(root == NULL)
return 0;
if(level == 1)
return 1;
/* UTILITY FUNCTIONS */
/* Compute the "height" of a tree -- the number of
nodes along the longest path from the root node
down to the farthest leaf node.*/
int height(struct node* node)
{
if (node==NULL)
return 0;
else
{
/* compute the height of each subtree */
int lHeight = height(node->left);
int rHeight = height(node->right);
/* use the larger one */
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->right = newNode(8);
root->right->right->left = newNode(6);
root->right->right->right = newNode(7);
/*
Constructed bunary tree is:
1
/ \
2
/ \
8
/ \
6
*/
printf("Maximum width is %d \n", getMaxWidth(root));
getchar();
return 0;
}
TimeComplexity:O(n^2)intheworstcase.
WecanuseQueuebasedlevelordertraversaltooptimizethetimecomplexityofthismethod.TheQueue
basedlevelordertraversalwilltakeO(n)timeinworstcase.ThankstoNitish,DivyaCandtech.login.id2for
suggestingthisoptimization.Seetheircommentsforimplementationusingqueuebasedtraversal.
Method2(UsingPreorderTraversal)
Inthismethodwecreateatemporaryarraycount[]ofsizeequaltotheheightoftree.Weinitializeallvalues
incountas0.Wetraversethetreeusingpreordertraversalandfilltheentriesincountsothatthecount
arraycontainscountofnodesateachlevelinBinaryTree.
#include <stdio.h>
#include <stdlib.h>
int level = 0;
/* UTILITY FUNCTIONS */
/* Compute the "height" of a tree -- the number of
nodes along the longest path from the root node
down to the farthest leaf node.*/
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->right = newNode(8);
root->right->right->left = newNode(6);
root->right->right->right = newNode(7);
/*
Constructed bunary tree is:
1
/ \
2
/ \
8
/ \
6
*/
printf("Maximum width is %d \n", getMaxWidth(root));
getchar();
return 0;
}
TimeComplexity:O(n)
=======================================================================
DoubleTree
WriteaprogramthatconvertsagiventreetoitsDoubletree.TocreateDoubletreeofthegiventree,create
anewduplicateforeachnode,andinserttheduplicateastheleftchildoftheoriginalnode.
Sothetree
2
/\
13
ischangedto
2
/\
23
//
13
/
1
Andthetree
1
/\
23
/\
45
ischangedto
1
/\
13
//
23
/\
25
//
45
/
4
Algorithm:
Recursivelyconvertthetreetodoubletreeinpostorderfashion.Foreachnode,firstconverttheleftsubtree
ofthenode,thenrightsubtree,finallycreateaduplicatenodeofthenodeandfixtheleftchildofthenode
andleftchildofleftchild.
Implementation:
#include <stdio.h>
#include <stdlib.h>
if (node==NULL) return;
/* do the subtrees */
doubleTree(node->left);
doubleTree(node->right);
return(node);
}
\
3
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
doubleTree(root);
getchar();
return 0;
}
TimeComplexity:O(n)wherenisthenumberofnodesinthetree.
=======================================================================
Givenabinarytree,printall
roottoleafpaths
Forthebelowexampletree,allroottoleafpathsare:
10>8>3
10>8>5
10>2>2
Algorithm:
Useapatharraypath[]tostorecurrentroottoleafpath.Traversefromroottoallleavesintopdownfashion.
Whiletraversing,storedataofallnodesincurrentpathinarraypath[].Whenwereachaleafnode,printthe
patharray.
#include<stdio.h>
#include<stdlib.h>
/* UTILITY FUNCTIONS */
/* Utility that prints out an array on a line. */
void printArray(int ints[], int len)
{
int i;
for (i=0; i<len; i++)
{
printf("%d ", ints[i]);
}
printf("\n");
return(node);
}
/ \
3 5 2
*/
struct node *root = newnode(10);
root->left
= newnode(8);
root->right
= newnode(2);
root->left->left = newnode(3);
root->left->right = newnode(5);
root->right->left = newnode(2);
printPaths(root);
getchar();
return 0;
}
TimeComplexity:O(n)
=======================================================================
ConstructTreefromgivenInorder
andPreordertraversals
Letusconsiderthebelowtraversals:
Inordersequence:DBEAFC
Preordersequence:ABDECF
InaPreordersequence,leftmostelementistherootofthetree.SoweknowAisrootforgivensequences.
BysearchingAinInordersequence,wecanfindoutallelementsonleftsideofAareinleftsubtreeand
elementsonrightareinrightsubtree.Soweknowbelowstructurenow.
A
/\
/\
DBEFC
Werecursivelyfollowabovestepsandgetthefollowingtree.
A
/\
/\
BC
/\/
/\/
DEF
Algorithm:buildTree()
1)PickanelementfromPreorder.IncrementaPreorderIndexVariable(preIndexinbelowcode)topicknext
elementinnextrecursivecall.
2)CreateanewtreenodetNodewiththedataaspickedelement.
3)FindthepickedelementsindexinInorder.LettheindexbeinIndex.
4)CallbuildTreeforelementsbeforeinIndexandmakethebuilttreeasleftsubtreeoftNode.
5)CallbuildTreeforelementsafterinIndexandmakethebuilttreeasrightsubtreeoftNode.
6)returntNode.
ThankstoRohiniandTusharforsuggestingthecode.
/* program to construct tree using inorder and preorder traversals */
#include<stdio.h>
#include<stdlib.h>
return tNode;
}
/* UTILITY FUNCTIONS */
/* Function to find index of value in arr[start...end]
The function assumes that value is present in in[] */
int search(char arr[], int strt, int end, char value)
{
int i;
for(i = strt; i <= end; i++)
{
if(arr[i] == value)
return i;
}
}
return(node);
}
=======================================================================
Roottoleafpathsumequaltoa
givennumber
Givenabinarytreeandanumber,returntrueifthetreehasaroottoleafpathsuchthataddingupallthe
valuesalongthepathequalsthegivennumber.Returnfalseifnosuchpathcanbefound.
Forexample,intheabovetreeroottoleafpathsexistwithfollowingsums.
21>1083
23>1085
14>1022
Sothereturnedvalueshouldbetrueonlyfornumbers21,23and14.Foranyothernumber,returnedvalue
shouldbefalse.
Algorithm:
Recursivelycheckifleftorrightchildhaspathsumequalto(numbervalueatcurrentnode)
Implementation:
#include<stdio.h>
#include<stdlib.h>
#define bool int
/*
Given a tree and a sum, return true if there is a path from the root
down to a leaf, such that adding up all the values along the path
equals the given sum.
Strategy: subtract the node value from the sum when recurring down,
and check to see if the sum is 0 when you run out of tree.
*/
bool hasPathSum(struct node* node, int sum)
{
/* return true if we run out of tree and sum==0 */
if (node == NULL)
{
return (sum == 0);
}
else
{
bool ans = 0;
if(node->left)
ans = ans || hasPathSum(node->left, subSum);
if(node->right)
ans = ans || hasPathSum(node->right, subSum);
return ans;
}
/* UTILITY FUNCTIONS */
/* Helper function that allocates a new node with the
given data and NULL left and right pointers. */
struct node* newnode(int data)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
/ \
3 5 2
*/
struct node *root = newnode(10);
root->left
= newnode(8);
root->right
= newnode(2);
root->left->left = newnode(3);
root->left->right = newnode(5);
root->right->left = newnode(2);
if(hasPathSum(root, sum))
getchar();
return 0;
}
TimeComplexity:O(n)
References:
=======================================================================
InorderTreeTraversalwithout
recursionandwithoutstack!
UsingMorrisTraversal,wecantraversethetreewithoutusingstackandrecursion.TheideaofMorris
TraversalisbasedonThreadedBinaryTree.Inthistraversal,wefirstcreatelinkstoInordersuccessorand
printthedatausingtheselinks,andfinallyrevertthechangestorestoreoriginaltree.
1.Initializecurrentasroot
2.WhilecurrentisnotNULL
Ifcurrentdoesnothaveleftchild
a)Printcurrentsdata
b)Gototheright,i.e.,current=current>right
Else
a)Makecurrentasrightchildoftherightmostnodeincurrent'sleftsubtree
b)Gotothisleftchild,i.e.,current=current>left
Althoughthetreeismodifiedthroughthetraversal,itisrevertedbacktoitsoriginalshapeafterthe
completion.UnlikeStackbasedtraversal,noextraspaceisrequiredforthistraversal.
#include<stdio.h>
#include<stdlib.h>
int data;
struct tNode* left;
struct tNode* right;
};
if(root == NULL)
return;
current = root;
while(current != NULL)
{
if(current->left == NULL)
{
printf(" %d ", current->data);
current = current->right;
}
else
{
/* Find the inorder predecessor of current */
pre = current->left;
while(pre->right != NULL && pre->right != current)
pre = pre->right;
/* UTILITY FUNCTIONS */
/* Helper function that allocates a new tNode with the
given data and NULL left and right pointers. */
struct tNode* newtNode(int data)
{
struct tNode* tNode = (struct tNode*)
malloc(sizeof(struct tNode));
tNode->data = data;
tNode->left = NULL;
tNode->right = NULL;
return(tNode);
}
\
3
/ \
4 5
*/
struct tNode *root = newtNode(1);
root->left
= newtNode(2);
root->right
= newtNode(3);
root->left->left = newtNode(4);
root->left->right = newtNode(5);
MorrisTraversal(root);
getchar();
return 0;
}
================================================================
=======
InorderTreeTraversalwithout
Recursion
UsingStackistheobviouswaytotraversetreewithoutrecursion.Belowisanalgorithmfortraversingbinary
treeusingstack.Seethisforstepwisestepexecutionofthealgorithm.
1)CreateanemptystackS.
2)Initializecurrentnodeasroot
3)PushthecurrentnodetoSandsetcurrent=current>leftuntilcurrentisNULL
4)IfcurrentisNULLandstackisnotemptythen
a)Popthetopitemfromstack.
b)Printthepoppeditem,setcurrent=popped_item>right
c)Gotostep3.
5)IfcurrentisNULLandstackisemptythenwearedone.
Letusconsiderthebelowtreeforexample
1
/\
23
/\
45
Step1Createsanemptystack:S=NULL
Step2setscurrentasaddressofroot:current>1
Step3Pushesthecurrentnodeandsetcurrent=current>leftuntilcurrentisNULL
current>1
push1:StackS>1
current>2
push2:StackS>2,1
current>4
push4:StackS>4,2,1
current=NULL
Step4popsfromS
a)Pop4:StackS>2,1
b)print"4"
c)current=NULL/*rightof4*/andgotostep3
SincecurrentisNULLstep3doesn'tdoanything.
Step4popsagain.
a)Pop2:StackS>1
b)print"2"
c)current>5/*rightof2*/andgotostep3
Step3pushes5tostackandmakescurrentNULL
StackS>5,1
current=NULL
Step4popsfromS
a)Pop5:StackS>1
b)print"5"
c)current=NULL/*rightof5*/andgotostep3
SincecurrentisNULLstep3doesn'tdoanything
Step4popsagain.
a)Pop1:StackS>NULL
b)print"1"
c)current>3/*rightof5*/
Step3pushes3tostackandmakescurrentNULL
StackS>3
current=NULL
Step4popsfromS
a)Pop3:StackS>NULL
b)print"3"
c)current=NULL/*rightof3*/
TraversalisdonenowasstackSisemptyandcurrentisNULL.
Implementation:
#include<stdio.h>
#include<stdlib.h>
#define bool int
while (!done)
{
/* Reach the left most tNode of the current tNode */
if(current != NULL)
{
/* place pointer to a tree node on the stack before traversing
the node's left subtree */
push(&s, current);
current = current->left;
}
else
done = 1;
}
} /* end of while */
}
/* UTILITY FUNCTIONS */
/* Function to push an item to sNode*/
void push(struct sNode** top_ref, struct tNode *t)
{
/* allocate tNode */
struct sNode* new_tNode =
(struct sNode*) malloc(sizeof(struct sNode));
if(new_tNode == NULL)
{
printf("Stack Overflow \n");
getchar();
exit(0);
}
return(tNode);
}
int main()
{
\
3
/ \
4 5
*/
struct tNode *root = newtNode(1);
root->left
= newtNode(2);
root->right
= newtNode(3);
root->left->left = newtNode(4);
root->left->right = newtNode(5);
inOrder(root);
getchar();
return 0;
}
TimeComplexity:O(n)
=======================================================================
Howtodetermineifabinarytreeis
heightbalanced?
Atreewherenoleafismuchfartherawayfromtherootthananyotherleaf.Differentbalancingschemes
allowdifferentdefinitionsofmuchfartheranddifferentamountsofworktokeepthembalanced.
Consideraheightbalancingschemewherefollowingconditionsshouldbecheckedtodetermineifabinary
treeisbalanced.
Anemptytreeisheightbalanced.AnonemptybinarytreeTisbalancedif:
1)LeftsubtreeofTisbalanced
2)RightsubtreeofTisbalanced
3)Thedifferencebetweenheightsofleftsubtreeandrightsubtreeisnotmorethan1.
TheaboveheightbalancingschemeisusedinAVLtrees.Thediagrambelowshowstwotrees,oneofthem
isheightbalancedandotherisnot.Thesecondtreeisnotheightbalancedbecauseheightofleftsubtreeis
2morethanheightofrightsubtree.
Tocheckifatreeisheightbalanced,gettheheightofleftandrightsubtrees.Returntrueifdifference
betweenheightsisnotmorethan1andleftandrightsubtreesarebalanced,otherwisereturnfalse.
/* program to check if a tree is height-balanced or not */
#include<stdio.h>
#include<stdlib.h>
#define bool int
{
int lh; /* for height of left subtree */
int rh; /* for height of right subtree */
return(node);
}
int main()
{
struct node *root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->left->left->left = newNode(8);
if(isBalanced(root))
printf("Tree is balanced");
else
printf("Tree is not balanced");
getchar();
return 0;
}
TimeComplexity:O(n^2)Worstcaseoccursincaseofskewedtree.
Optimizedimplementation:Aboveimplementationcanbeoptimizedbycalculatingtheheightinthesame
recursionratherthancallingaheight()functionseparately.ThankstoAmarforsuggestingthisoptimized
version.ThisoptimizationreducestimecomplexitytoO(n).
/* program to check if a tree is height-balanced or not */
#include<stdio.h>
#include<stdlib.h>
#define bool int
if(root == NULL)
{
*height = 0;
return 1;
return(node);
}
int main()
{
int height = 0;
\
3
/ \ /
4
5 6
/
7
*/
struct node *root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->left->left->left = newNode(7);
if(isBalanced(root, &height))
printf("Tree is balanced");
else
printf("Tree is not balanced");
getchar();
return 0;
}
TimeComplexity:O(n)
=======================================================================
DiameterofaBinaryTree
Thediameterofatree(sometimescalledthewidth)isthenumberofnodesonthelongestpathbetweentwo
leavesinthetree.Thediagrambelowshowstwotreeseachwithdiameternine,theleavesthatformthe
endsofalongestpathareshaded(notethatthereismorethanonepathineachtreeoflengthnine,butno
pathlongerthanninenodes).
ThediameterofatreeTisthelargestofthefollowingquantities:
*thediameterofTsleftsubtree
*thediameterofTsrightsubtree
*thelongestpathbetweenleavesthatgoesthroughtherootofT(thiscanbecomputedfromtheheightsof
thesubtreesofT)
Implementation:
#include <stdio.h>
#include <stdlib.h>
return(node);
}
\
3
4 5
*/
struct node *root = newNode(1);
root->left
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
getchar();
return 0;
}
TimeComplexity:O(n^2)
Optimizedimplementation:Theaboveimplementationcanbeoptimizedbycalculatingtheheightinthe
samerecursionratherthancallingaheight()separately.ThankstoAmarforsuggestingthisoptimized
version.ThisoptimizationreducestimecomplexitytoO(n).
/*The second parameter is to store the height of tree.
Initially, we need to pass a pointer to a location with value
as 0. So, function should be used as follows:
int height = 0;
struct node *root = SomeFunctionToMakeTree();
int diameter = diameterOpt(root, &height); */
int diameterOpt(struct node *root, int* height)
{
/* lh --> Height of left subtree
rh --> Height of right subtree */
int lh = 0, rh = 0;
if(root == NULL)
{
*height = 0;
return 0; /* diameter is also 0 */
}
================================================================
=======
ConvertanarbitraryBinaryTreeto
atreethatholdsChildrenSum
Property
Question:Givenanarbitrarybinarytree,convertittoabinarytreethatholdsChildrenSumProperty.You
canonlyincrementdatavaluesinanynode(Youcannotchangestructureoftreeandcannotdecrement
valueofanynode).
Forexample,thebelowtreedoesntholdthechildrensumproperty,convertittoatreethatholdsthe
property.
50
/\
/\
72
/\/\
/\/\
35130
Algorithm:
Traversegiventreeinpostordertoconvertit,i.e.,firstchangeleftandrightchildrentoholdthechildrensum
propertythenchangetheparentnode.
Letdifferencebetweennodesdataandchildrensumbediff.
diff=nodeschildrensumnodesdata
Ifdiffis0thennothingneedstobedone.
Ifdiff>0(nodesdataissmallerthannodeschildrensum)incrementthenodesdatabydiff.
Ifdiff<0(nodesdataisgreaterthanthenode'schildrensum)thenincrementonechildsdata.Wecan
choosetoincrementeitherleftorrightchildiftheybotharenotNULL.Letusalwaysfirstincrementtheleft
child.Incrementingachildchangesthesubtreeschildrensumpropertysoweneedtochangeleftsubtree
also.Sowerecursivelyincrementtheleftchild.Ifleftchildisemptythenwerecursivelycallincrement()for
rightchild.
Letusrunthealgorithmforthegivenexample.
Firstconverttheleftsubtree(increment7to8).
50
/\
/\
82
/\/\
/\/\
35130
Thenconverttherightsubtree(increment2to31)
50
/\
/\
831
/\/\
/\/\
35130
Nowconverttheroot,wehavetoincrementleftsubtreeforconvertingtheroot.
50
/\
/\
1931
/\/\
/\/\
145130
Pleasenotethelaststepwehaveincremented8to19,andtofixthesubtreewehaveincremented3to
14.
Implementation:
/* Program to convert an aribitary binary tree to
a tree that holds children sum property */
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node* left;
struct node* right;
};
= newNode(7);
root->right
= newNode(2);
root->left->left = newNode(3);
root->left->right = newNode(5);
root->right->left = newNode(1);
root->right->right = newNode(30);
convertTree(root);
getchar();
return 0;
}
TimeComplexity:O(n^2),Worstcasecomplexityisforaskewedtreesuchthatnodesareindecreasing
orderfromroottoleaf.
=======================================================================
CheckforChildrenSumPropertyin
aBinaryTree.
Givenabinarytree,writeafunctionthatreturnstrueifthetreesatisfiesbelowproperty.
Foreverynode,datavaluemustbeequaltosumofdatavaluesinleftandrightchildren.Considerdata
valueas0forNULLchildren.Belowtreeisanexample
Algorithm:
Traversethegivenbinarytree.Foreachnodecheck(recursively)ifthenodeandbothitschildrensatisfythe
ChildrenSumProperty,ifsothenreturntrueelsereturnfalse.
Implementation:
/* Program to check children sum property */
#include <stdio.h>
#include <stdlib.h>
/* A binary tree node has data, left child and right child */
struct node
{
int data;
struct node* left;
struct node* right;
};
/*
Helper function that allocates a new node
= newNode(8);
root->right
= newNode(2);
root->left->left
= newNode(3);
root->left->right = newNode(5);
root->right->right = newNode(2);
if(isSumProperty(root))
printf("The given tree satisfies the children sum property ");
else
printf("The given tree does not satisfy the children sum property ");
getchar();
return 0;
}
TimeComplexity:O(n),wearedoingacompletetraversalofthetree.
=======================================================================
Levelordertraversalinspiralform
Writeafunctiontoprintspiralordertraversalofatree.Forbelowtree,functionshouldprint1,2,3,4,5,6,7.
Method1(Recursive)
Thisproblemcanbeeseenasanextensionofthelevelordertraversalpost.
Toprintthenodesinspiralorder,nodesatdifferentlevelsshouldbeprintedinalternatingorder.An
additionalBooleanvariableltrisusedtochangeprintingorderoflevels.Ifltris1thenprintGivenLevel()
printsnodesfromlefttorightelsefromrighttoleft.Valueofltrisflippedineachiterationtochangethe
order.
Functiontoprintlevelordertraversaloftree
printSpiral(tree)
boolltr=0
ford=1toheight(tree)
printGivenLevel(tree,d,ltr)
ltr~=ltr/*flipltr*/
Functiontoprintallnodesatagivenlevel
printGivenLevel(tree,level,ltr)
iftreeisNULLthenreturn
iflevelis1,then
print(tree>data)
elseiflevelgreaterthan1,then
if(ltr)
printGivenLevel(tree>left,level1,ltr)
printGivenLevel(tree>right,level1,ltr)
else
printGivenLevel(tree>right,level1,ltr)
printGivenLevel(tree>left,level1,ltr)
FollowingisCimplementationofabovealgorithm.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
/* Function protoypes */
void printGivenLevel(struct node* root, int level, int ltr);
int height(struct node* node);
struct node* newNode(int data);
}
}
return(node);
}
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(7);
root->left->right = newNode(6);
root->right->left = newNode(5);
root->right->right = newNode(4);
printf("Spiral Order traversal of binary tree is \n");
printSpiral(root);
return 0;
}
Output:
SpiralOrdertraversalofbinarytreeis
1234567
TimeComplexity:WorstcasetimecomplexityoftheabovemethodisO(n^2).Worstcaseoccursincaseof
skewedtrees.
Method2(Iterative)
WecanprintspiralordertraversalinO(n)timeandO(n)extraspace.Theideaistousetwostacks.Wecan
useonestackforprintingfromlefttorightandotherstackforprintingfromrighttoleft.Ineveryiteration,we
havenodesofonelevelinoneofthestacks.Weprintthenodes,andpushnodesofnextlevelinother
stack.
// C++ implementation of a O(n) time method for spiral order traversal
#include <iostream>
#include <stack>
using namespace std;
// NULL check
node->left = NULL;
node->right = NULL;
return(node);
}
int main()
{
struct node *root = newNode(1);
root->left
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(7);
root->left->right = newNode(6);
root->right->left = newNode(5);
root->right->right = newNode(4);
cout << "Spiral Order traversal of binary tree is \n";
printSpiral(root);
return 0;
}
Output:
SpiralOrdertraversalofbinarytreeis
1234567
=======================================================================
Aprogramtocheckifabinarytree
isBSTornot
Abinarysearchtree(BST)isanodebasedbinarytreedatastructurewhichhasthefollowingproperties.
Theleftsubtreeofanodecontainsonlynodeswithkeyslessthanthenodeskey.
Therightsubtreeofanodecontainsonlynodeswithkeysgreaterthanthenodeskey.
Boththeleftandrightsubtreesmustalsobebinarysearchtrees.
Fromtheabovepropertiesitnaturallyfollowsthat:
Eachnode(iteminthetree)hasadistinctkey.
METHOD1(SimplebutWrong)
Followingisasimpleprogram.Foreachnode,checkifleftnodeofitissmallerthanthenodeandrightnode
ofitisgreaterthanthenode.
int isBST(struct node* node)
{
if (node == NULL)
return 1;
METHOD2(Correctbutnotefficient)
Foreachnode,checkifmaxvalueinleftsubtreeissmallerthanthenodeandminvalueinrightsubtree
greaterthanthenode.
/* Returns true if a binary tree is a binary search tree */
int isBST(struct node* node)
{
if (node == NULL)
return(true);
return(true);
}
ItisassumedthatyouhavehelperfunctionsminValue()andmaxValue()thatreturntheminormaxintvalue
fromanonemptytree
METHOD3(CorrectandEfficient)
Method2aboverunsslowlysinceittraversesoversomepartsofthetreemanytimes.Abettersolution
looksateachnodeonlyonce.ThetrickistowriteautilityhelperfunctionisBSTUtil(structnode*node,int
min,intmax)thattraversesdownthetreekeepingtrackofthenarrowingminandmaxallowedvaluesasit
goes,lookingateachnodeonlyonce.TheinitialvaluesforminandmaxshouldbeINT_MINandINT_MAX
theynarrowfromthere.
/*Returnstrueifthegiventreeisabinarysearchtree
(efficientversion).*/
intisBST(structnode*node)
{
return(isBSTUtil(node,INT_MIN,INT_MAX))
}
/*ReturnstrueifthegiventreeisaBSTandits
valuesare>=minand<=max.*/
intisBSTUtil(structnode*node,intmin,intmax)
Implementation:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
node->right = NULL;
return(node);
}
= newNode(2);
root->right
= newNode(5);
root->left->left = newNode(1);
root->left->right = newNode(3);
if(isBST(root))
printf("Is BST");
else
printf("Not a BST");
getchar();
return 0;
}
TimeComplexity:O(n)
AuxiliarySpace:O(1)ifFunctionCallStacksizeisnotconsidered,otherwiseO(n)
METHOD4(UsingInOrderTraversal)
ThankstoLJW489forsuggestingthismethod.
1)DoInOrderTraversalofthegiventreeandstoretheresultinatemparray.
3)Checkifthetemparrayissortedinascendingorder,ifitis,thenthetreeisBST.
TimeComplexity:O(n)
WecanavoidtheuseofAuxiliaryArray.WhiledoingInOrdertraversal,wecankeeptrackofpreviously
visitednode.Ifthevalueofthecurrentlyvisitednodeislessthanthepreviousvalue,thentreeisnotBST.
Thankstoygosforthisspaceoptimization.
bool isBST(struct node* root)
{
static struct node *prev = NULL;
// traverse the tree in inorder fashion and keep track of prev node
if (root)
{
if (!isBST(root->left))
return false;
prev = root;
return isBST(root->right);
}
return true;
}
Theuseofstaticvariablecanalsobeavoidedbyusingreferencetoprevnodeasaparameter(Similarto
thispost).
=======================================================================
Programtocountleafnodesina
binarytree
AnodeisaleafnodeifbothleftandrightchildnodesofitareNULL.
Hereisanalgorithmtogettheleafnodecount.
getLeafCount(node)
1)IfnodeisNULLthenreturn0.
2)ElseIfleftandrightchildnodesareNULLreturn1.
3)Elserecursivelycalculateleafcountofthetreeusingbelowformula.
Leafcountofatree=Leafcountofleftsubtree+
Leafcountofrightsubtree
ExampleTree
Leafcountfortheabovetreeis3.
Implementation:
#include <stdio.h>
#include <stdlib.h>
return(node);
}
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
getchar();
return 0;
}
Time&SpaceComplexities:Sincethisprogramissimilartotraversaloftree,timeandspacecomplexities
willbesameasTreetraversal(PleaseseeourTreeTraversalpostfordetails)
=======================================================================
LevelOrderTreeTraversal
Levelordertraversalofatreeisbreadthfirsttraversalforthetree.
ExampleTree
Levelordertraversaloftheabovetreeis12345
METHOD1(Usefunctiontoprintagivenlevel)
Algorithm:
Therearebasicallytwofunctionsinthismethod.Oneistoprintallnodesatagivenlevel(printGivenLevel),
andotheristoprintlevelordertraversalofthetree(printLevelorder).printLevelordermakesuseof
printGivenLeveltoprintnodesatalllevelsonebyonestartingfromroot.
/*Functiontoprintlevelordertraversaloftree*/
printLevelorder(tree)
ford=1toheight(tree)
printGivenLevel(tree,d)
/*Functiontoprintallnodesatagivenlevel*/
printGivenLevel(tree,level)
iftreeisNULLthenreturn
iflevelis1,then
print(tree>data)
elseiflevelgreaterthan1,then
printGivenLevel(tree>left,level1)
printGivenLevel(tree>right,level1)
Implementation:
#include <stdio.h>
#include <stdlib.h>
/*Function protoypes*/
void printGivenLevel(struct node* root, int level);
int height(struct node* node);
struct node* newNode(int data);
}
}
return(node);
}
int main()
{
struct node *root = newNode(1);
root->left
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
getchar();
return 0;
}
TimeComplexity:O(n^2)inworstcase.Foraskewedtree,printGivenLevel()takesO(n)timewherenisthe
numberofnodesintheskewedtree.SotimecomplexityofprintLevelOrder()isO(n)+O(n1)+O(n2)+..+
O(1)whichisO(n^2).
METHOD2(UseQueue)
Algorithm:
Foreachnode,firstthenodeisvisitedandthenitschildnodesareputinaFIFOqueue.
printLevelorder(tree)
1)Createanemptyqueueq
2)temp_node=root/*startfromroot*/
3)Loopwhiletemp_nodeisnotNULL
a)printtemp_node>data.
b)Enqueuetemp_nodeschildren(firstleftthenrightchildren)toq
c)Dequeueanodefromqandassignitsvaluetotemp_node
Implementation:
Hereisasimpleimplementationoftheabovealgorithm.Queueisimplementedusinganarraywith
maximumsizeof500.Wecanimplementqueueaslinkedlistalso.
#include <stdio.h>
#include <stdlib.h>
#define MAX_Q_SIZE 500
/* frunction prototypes */
struct node** createQueue(int *, int *);
void enQueue(struct node **, int *, struct node *);
struct node *deQueue(struct node **, int *);
while(temp_node)
{
printf("%d ", temp_node->data);
/*UTILITY FUNCTIONS*/
struct node** createQueue(int *front, int *rear)
{
struct node **queue =
(struct node **)malloc(sizeof(struct node*)*MAX_Q_SIZE);
*front = *rear = 0;
return queue;
}
return(node);
}
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
getchar();
return 0;
}
TimeComplexity:O(n)wherenisnumberofnodesinthebinarytree
================================================================
=======
Findthenodewithminimumvalue
inaBinarySearchTree
Thisisquitesimple.JusttraversethenodefromroottoleftrecursivelyuntilleftisNULL.Thenodewhose
leftisNULListhenodewithminimumvalue.
Fortheabovetree,westartwith20,thenwemoveleft8,wekeeponmovingtoleftuntilweseeNULL.
Sinceleftof4isNULL,4isthenodewithminimumvalue.
#include <stdio.h>
#include<stdlib.h>
return(node);
}
=======================================================================
TheGreatTreeListRecursion
Problem.
Question:
WritearecursivefunctiontreeToList(Noderoot)thattakesanorderedbinarytreeandrearrangesthe
internalpointerstomakeacirculardoublylinkedlistoutofthetreenodes.Thepreviouspointersshouldbe
storedinthesmallfieldandthenextpointersshouldbestoredinthelargefield.Thelistshouldbe
arrangedsothatthenodesareinincreasingorder.Returntheheadpointertothenewlist.
Thisisverywellexplainedandimplementedathttp://cslibrary.stanford.edu/109/TreeListRecursion.html
=======================================================================
LowestCommonAncestorinaBinarySearchTree
GivenvaluesoftwonodesinaBinarySearchTree,writeacprogramtofindtheLowestCommonAncestor
(LCA).Youmayassumethatboththevaluesexistinthetree.
Thefunctionprototypeshouldbeasfollows:
structnode*lca(node*root,intn1,intn2)
n1andn2aretwogivenvaluesinthetreewithgivenroot.
Forexample,considertheBSTindiagram,LCAof10and14is12andLCAof8and14is8.
FollowingisdefinitionofLCAfromWikipedia:
LetTbearootedtree.Thelowestcommonancestorbetweentwonodesn1andn2isdefinedasthelowest
nodeinTthathasbothn1andn2asdescendants(whereweallowanodetobeadescendantofitself).
TheLCAofn1andn2inTisthesharedancestorofn1andn2thatislocatedfarthestfromtheroot.
Computationoflowestcommonancestorsmaybeuseful,forinstance,aspartofaprocedurefor
determiningthedistancebetweenpairsofnodesinatree:thedistancefromn1ton2canbecomputedas
thedistancefromtherootton1,plusthedistancefromtherootton2,minustwicethedistancefromtheroot
totheirlowestcommonancestor.(SourceWiki)
Solutions:
IfwearegivenaBSTwhereeverynodehasparentpointer,thenLCAcanbeeasilydeterminedby
traversingupusingparentpointerandprintingthefirstintersectingnode.
WecansolvethisproblemusingBSTproperties.WecanrecursivelytraversetheBSTfromroot.Themain
ideaofthesolutionis,whiletraversingfromtoptobottom,thefirstnodenweencounterwithvaluebetween
n1andn2,i.e.,n1<n<n2orsameasoneofthen1orn2,isLCAofn1andn2(assumingthatn1<n2).So
justrecursivelytraversetheBSTin,ifnode'svalueisgreaterthanbothn1andn2thenourLCAliesinleft
sideofthenode,ifit'sissmallerthanbothn1andn2,thenLCAliesonrightside.OtherwiserootisLCA
(assumingthatbothn1andn2arepresentinBST)
// A recursive C program to find LCA of two nodes n1 and n2.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node* left, *right;
};
/* Function to find LCA of n1 and n2. The function assumes that both
n1 and n2 are present in BST */
struct node *lca(struct node* root, int n1, int n2)
{
if (root == NULL) return NULL;
// If both n1 and n2 are smaller than root, then LCA lies in left
if (root->data > n1 && root->data > n2)
return lca(root->left, n1, n2);
// If both n1 and n2 are greater than root, then LCA lies in right
if (root->data < n1 && root->data < n2)
return lca(root->right, n1, n2);
return root;
}
/* Helper function that allocates a new node with the given data.*/
struct node* newNode(int data)
{
struct node* node = (struct node*)malloc(sizeof(struct node));
node->data = data;
node->left = node->right = NULL;
return(node);
= newNode(20);
root->left
= newNode(8);
root->right
= newNode(22);
root->left->left
= newNode(4);
root->left->right
= newNode(12);
root->left->right->left = newNode(10);
root->left->right->right = newNode(14);
n1 = 14, n2 = 8;
t = lca(root, n1, n2);
printf("LCA of %d and %d is %d \n", n1, n2, t->data);
n1 = 10, n2 = 22;
t = lca(root, n1, n2);
printf("LCA of %d and %d is %d \n", n1, n2, t->data);
getchar();
return 0;
}
Output:
LCAof10and14is12
LCAof14and8is8
LCAof10and22is20
TimecomplexityofabovesolutionisO(h)wherehisheightoftree.Also,theabovesolutionrequiresO(h)
extraspaceinfunctioncallstackforrecursivefunctioncalls.Wecanavoidextraspaceusingiterative
solution.
/* Function to find LCA of n1 and n2. The function assumes that both
n1 and n2 are present in BST */
struct node *lca(struct node* root, int n1, int n2)
{
while (root != NULL)
{
// If both n1 and n2 are smaller than root, then LCA lies in left
if (root->data > n1 && root->data > n2)
root = root->left;
// If both n1 and n2 are greater than root, then LCA lies in right
else if (root->data < n1 && root->data < n2)
root = root->right;
else break;
}
return root;
}
Seethisforcompleteprogram.
YoumayliketoseeLowestCommonAncestorinaBinaryTreealso.
Exercise
Theabovefunctionsassumethatn1andn2bothareinBST.Ifn1andn2arenotpresent,thentheymay
returnincorrectresult.ExtendtheabovesolutionstoreturnNULLifn1orn2orbothnotpresentinBST.
=======================================================================
Givenabinarytree,printoutallof
itsroottoleafpathsoneperline.
Hereisthesolution.
Algorithm:
initialize:pathlen=0,path[1000]
/*1000issomemaxlimitforpaths,itcanchange*/
/*printPathsRecurtraversesnodesoftreeinpreorder*/
printPathsRecur(tree,path[],pathlen)
1)IfnodeisnotNULLthen
a)pushdatatopatharray:
path[pathlen]=node>data.
b)incrementpathlen
pathlen++
2)Ifnodeisaleafnodethenprintthepatharray.
3)Else
a)CallprintPathsRecurforleftsubtree
printPathsRecur(node>left,path,pathLen)
b)CallprintPathsRecurforrightsubtree.
printPathsRecur(node>right,path,pathLen)
Example:
ExampleTree
Outputfortheaboveexamplewillbe
124
125
13
Implementation:
/*program to print all of its root-to-leaf paths for a tree*/
#include <stdio.h>
#include <stdlib.h>
}
else
{
/* otherwise try both subtrees */
printPathsRecur(node->left, path, pathLen);
printPathsRecur(node->right, path, pathLen);
}
}
return(node);
}
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
getchar();
return 0;
}
=======================================================================
Ifyouaregiventwotraversal
sequences,canyouconstructthe
binarytree?
Itdependsonwhattraversalsaregiven.IfoneofthetraversalmethodsisInorderthenthetreecanbe
constructed,otherwisenot.
Therefore,followingcombinationcanuniquelyidentifyatree.
InorderandPreorder.
InorderandPostorder.
InorderandLevelorder.
Andfollowingdonot.
PostorderandPreorder.
PreorderandLevelorder.
PostorderandLevelorder.
Forexample,Preorder,LevelorderandPostordertraversalsaresameforthetreesgiveninabovediagram.
PreorderTraversal=AB
PostorderTraversal=BA
LevelOrderTraversal=AB
So,evenifthreeofthem(Pre,PostandLevel)aregiven,thetreecannotbeconstructed.
=======================================================================
WriteanEfficientCFunctionto
ConvertaBinaryTreeintoits
MirrorTree
MirrorofaTree:MirrorofaBinaryTreeTisanotherBinaryTreeM(T)withleftandrightchildrenofall
nonleafnodesinterchanged.
Treesinthebelowfigurearemirrorofeachother
AlgorithmMirror(tree):
(1)CallMirrorforleftsubtreei.e.,Mirror(leftsubtree)
(2)CallMirrorforrightsubtreei.e.,Mirror(leftsubtree)
(3)Swapleftandrightsubtrees.
temp=leftsubtree
leftsubtree=rightsubtree
rightsubtree=temp
Program:
#include<stdio.h>
#include<stdlib.h>
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
So the tree...
4
/\
2
/\
1
is changed to...
4
/\
5
2
/\
3
*/
void mirror(struct node* node)
{
if (node==NULL)
return;
else
{
struct node* temp;
/* do the subtrees */
mirror(node->left);
mirror(node->right);
= node->left;
node->left = node->right;
node->right = temp;
}
}
inOrder(node->left);
printf("%d ", node->data);
inOrder(node->right);
}
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
getchar();
return 0;
}
Time&SpaceComplexities:Thisprogramissimilartotraversaloftreespaceandtimecomplexitieswillbe
sameasTreetraversal(PleaseseeourTreeTraversalpostfordetails)
=======================================================================
WriteaCprogramtoDeleteaTree.
Todeleteatreewemusttraverseallthenodesofthetreeanddeletethemonebyone.Sowhichtraversal
weshoulduseInorderorPreorderorPostorder.AnswerissimplePostorder,becausebeforedeleting
theparentnodeweshoulddeleteitschildrennodesfirst
Wecandeletetreewithothertraversalsalsowithextraspacecomplexitybutwhyshouldwegoforother
traversalsifwehavePostorderavailablewhichdoestheworkwithoutstoringanythinginsametime
complexity.
Forthefollowingtreenodesaredeletedinorder4,5,2,3,1
ExampleTree
Program
#include<stdio.h>
#include<stdlib.h>
int data;
struct node* left;
struct node* right;
};
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
= newNode(2);
root->right
= newNode(3);
root->left->left
= newNode(4);
root->left->right
= newNode(5);
deleteTree(root);
root = NULL;
getchar();
return 0;
}
TheabovedeleteTree()functiondeletesthetree,butdoesntchangeroottoNULLwhichmaycause
problemsiftheuserofdeleteTree()doesntchangeroottoNULLandtirestoaccessvaluesusingroot
pointer.WecanmodifythedeleteTree()functiontotakereferencetotherootnodesothatthisproblem
doesntoccur.Seethefollowingcode.
#include<stdio.h>
#include<stdlib.h>
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
= newNode(2);
root->right
= newNode(3);
root->left->left
= newNode(4);
root->left->right
= newNode(5);
deleteTree(&root);
printf("\n Tree deleted ");
getchar();
return 0;
}
TimeComplexity:O(n)
SpaceComplexity:IfwedontconsidersizeofstackforfunctioncallsthenO(1)otherwiseO(n)
=======================================================================
WriteaCProgramtoFindthe
MaximumDepthorHeightofaTree
Maximumdepthorheightofthebelowtreeis3.
ExampleTree
Recursivelycalculateheightofleftandrightsubtreesofanodeandassignheighttothenodeasmaxofthe
heightsoftwochildrenplus1.Seebelowpseudocodeandprogramfordetails.
Algorithm:
maxDepth()
1.Iftreeisemptythenreturn0
2.Else
(a)Getthemaxdepthofleftsubtreerecursivelyi.e.,
callmaxDepth(tree>leftsubtree)
(a)Getthemaxdepthofrightsubtreerecursivelyi.e.,
callmaxDepth(tree>rightsubtree)
(c)Getthemaxofmaxdepthsofleftandright
subtreesandadd1toitforthecurrentnode.
max_depth=max(maxdeptofleftsubtree,
maxdepthofrightsubtree)
+1
(d)Returnmax_depth
SeethebelowdiagramformoreclarityaboutexecutionoftherecursivefunctionmaxDepth()for
aboveexampletree.
maxDepth('1')=max(maxDepth('2'),maxDepth('3'))+1
=2+1
/\
/\
/\
/\
/\
maxDepth('1')maxDepth('3')=1
=max(maxDepth('4'),maxDepth('5'))+1
=1+1=2
/\
/\
/\
/\
/\
maxDepth('4')=1maxDepth('5')=1
Implementation:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node* left;
struct node* right;
};
return(node);
}
int main()
{
struct node *root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
getchar();
return 0;
}
TimeComplexity:O(n)(PleaseseeourpostTreeTraversalfordetails)
=======================================================================
WriteCCodetoDetermineifTwo
TreesareIdentical
Twotreesareidenticalwhentheyhavesamedataandarrangementofdataisalsosame.
Toidentifyiftwotreesareidentical,weneedtotraversebothtreessimultaneously,andwhiletraversingwe
needtocomparedataandchildrenofthetrees.
Algorithm:
sameTree(tree1,tree2)
1.Ifbothtreesareemptythenreturn1.
2.ElseIfbothtreesarenonempty
(a)Checkdataoftherootnodes(tree1>data==tree2>data)
(b)Checkleftsubtreesrecursivelyi.e.,callsameTree(
tree1>left_subtree,tree2>left_subtree)
(c)Checkrightsubtreesrecursivelyi.e.,callsameTree(
tree1>right_subtree,tree2>right_subtree)
(d)Ifa,bandcaretruethenreturn1.
3Elsereturn0(oneisemptyandotherisnot)
#include <stdio.h>
#include <stdlib.h>
return(node);
}
root2->left = newNode(2);
root2->right = newNode(3);
root2->left->left = newNode(4);
root2->left->right = newNode(5);
if(identicalTrees(root1, root2))
printf("Both tree are identical.");
else
printf("Trees are not identical.");
getchar();
return 0;
}
TimeComplexity:
ComplexityoftheidenticalTree()willbeaccordingtothetreewithlessernumberofnodes.Letnumberof
nodesintwotreesbemandnthencomplexityofsameTree()isO(m)wherem<n.
=======================================================================
WriteaCprogramtoCalculateSize
ofatree
Sizeofatreeisthenumberofelementspresentinthetree.Sizeofthebelowtreeis5.
ExampleTree
Size()functionrecursivelycalculatesthesizeofatree.Itworksasfollows:
Sizeofatree=Sizeofleftsubtree+1+Sizeofrightsubtree
Algorithm:
size(tree)
1.Iftreeisemptythenreturn0
2.Else
(a)Getthesizeofleftsubtreerecursivelyi.e.,call
size(tree>leftsubtree)
(a)Getthesizeofrightsubtreerecursivelyi.e.,call
size(tree>rightsubtree)
(c)Calculatesizeofthetreeasfollowing:
tree_size=size(leftsubtree)+size(right
subtree)+1
(d)Returntree_size
#include <stdio.h>
#include <stdlib.h>
return(node);
}
= newNode(2);
root->right
= newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
=======================================================================
TreeTraversals
Unlikelineardatastructures(Array,LinkedList,Queues,Stacks,etc)whichhaveonlyonelogicalwayto
traversethem,treescanbetraversedindifferentways.Followingarethegenerallyusedwaysfortraversing
trees.
ExampleTree
DepthFirstTraversals:
(a)Inorder
(b)Preorder
(c)Postorder
BreadthFirstorLevelOrderTraversal
PleaseseethispostforBreadthFirstTraversal.
InorderTraversal:
AlgorithmInorder(tree)
1.Traversetheleftsubtree,i.e.,callInorder(leftsubtree)
2.Visittheroot.
3.Traversetherightsubtree,i.e.,callInorder(rightsubtree)
UsesofInorder
Incaseofbinarysearchtrees(BST),Inordertraversalgivesnodesinnondecreasingorder.Togetnodesof
BSTinnonincreasingorder,avariationofInordertraversalwhereInorderitraversalsreversed,canbe
used.
Example:Inordertraversalfortheabovegivenfigureis42513.
PreorderTraversal:
AlgorithmPreorder(tree)
1.Visittheroot.
2.Traversetheleftsubtree,i.e.,callPreorder(leftsubtree)
3.Traversetherightsubtree,i.e.,callPreorder(rightsubtree)
UsesofPreorder
Preordertraversalisusedtocreateacopyofthetree.Preordertraversalisalsousedtogetprefix
expressiononofanexpressiontree.Pleaseseehttp://en.wikipedia.org/wiki/Polish_notationtoknowwhy
prefixexpressionsareuseful.
Example:Preordertraversalfortheabovegivenfigureis12453.
PostorderTraversal:
AlgorithmPostorder(tree)
1.Traversetheleftsubtree,i.e.,callPostorder(leftsubtree)
2.Traversetherightsubtree,i.e.,callPostorder(rightsubtree)
3.Visittheroot.
UsesofPostorder
Postordertraversalisusedtodeletethetree.Pleaseseethequestionfordeletionoftreefordetails.
Postordertraversalisalsousefultogetthepostfixexpressionofanexpressiontree.Pleasesee
http://en.wikipedia.org/wiki/Reverse_Polish_notationtofortheusageofpostfixexpression.
Example:Postordertraversalfortheabovegivenfigureis45231.
#include <stdio.h>
#include <stdlib.h>
return(node);
}
printPostorder(node->left);
= newNode(2);
root->right
= newNode(3);
root->left->left
= newNode(4);
root->left->right
= newNode(5);
getchar();
return 0;
}
TimeComplexity:O(n)
Letusproveit:
ComplexityfunctionT(n)forallproblemwheretreetraversalisinvolvedcanbedefinedas:
T(n)=T(k)+T(nk1)+c
Wherekisthenumberofnodesononesideofrootandnk1ontheotherside.
Letsdoanalysisofboundaryconditions
Case1:Skewedtree(Oneofthesubtreesisemptyandothersubtreeisnonempty)
kis0inthiscase.
T(n)=T(0)+T(n1)+c
T(n)=2T(0)+T(n2)+2c
T(n)=3T(0)+T(n3)+3c
T(n)=4T(0)+T(n4)+4c
.
T(n)=(n1)T(0)+T(1)+(n1)c
T(n)=nT(0)+(n)c
ValueofT(0)willbesomeconstantsayd.(traversingaemptytreewilltakesomeconstantstime)
T(n)=n(c+d)
T(n)=()(n)(Thetaofn)
Case2:Bothleftandrightsubtreeshaveequalnumberofnodes.
T(n)=2T(|_n/2_|)+c
Thisrecursivefunctionisinthestandardform(T(n)=aT(n/b)+()(n))formaster
methodhttp://en.wikipedia.org/wiki/Master_theorem.Ifwesolveitbymastermethodweget()(n)
AuxiliarySpace:IfwedontconsidersizeofstackforfunctioncallsthenO(1)otherwiseO(n).
=======================================================================
InorderSuccessorinBinarySearch
Tree
InBinaryTree,InordersuccessorofanodeisthenextnodeinInordertraversaloftheBinaryTree.Inorder
SuccessorisNULLforthelastnodeinInoordertraversal.
InBinarySearchTree,InorderSuccessorofaninputnodecanalsobedefinedasthenodewiththesmallest
keygreaterthanthekeyofinputnode.So,itissometimesimportanttofindnextnodeinsortedorder.
Intheabovediagram,inordersuccessorof8is10,inordersuccessorof10is12andinordersuccessorof
14is20.
Method1(UsesParentPointer)
Inthismethod,weassumethateverynodehasparentpointer.
TheAlgorithmisdividedintotwocasesonthebasisofrightsubtreeoftheinputnodebeingemptyornot.
Input:node,root//nodeisthenodewhoseInordersuccessorisneeded.
output:succ//succisInordersuccessorofnode.
1)IfrightsubtreeofnodeisnotNULL,thensuccliesinrightsubtree.Dofollowing.
Gotorightsubtreeandreturnthenodewithminimumkeyvalueinrightsubtree.
2)IfrightsbtreeofnodeisNULL,thensuccisoneoftheancestors.Dofollowing.
Travelupusingtheparentpointeruntilyouseeanodewhichisleftchildofitsparent.Theparentofsucha
nodeisthesucc.
Implementation
NotethatthefunctiontofindInOrderSuccessorishighlighted(withgraybackground)inbelowcode.
#include <stdio.h>
#include <stdlib.h>
/* Helper function that allocates a new node with the given data and
NULL left and right pointers. */
struct node* newNode(int data)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->data
= data;
node->left
= NULL;
node->right = NULL;
node->parent = NULL;
return(node);
}
/* Give a binary search tree and a number, inserts a new node with
the given number in the correct place in the tree. Returns the new
root pointer which the caller should then use (the standard trick to
avoid using reference parameters). */
struct node* insert(struct node* node, int data)
{
/* 1. If the tree is empty, return a new,
single node */
if (node == NULL)
return(newNode(data));
else
{
struct node *temp;
getchar();
return 0;
}
Outputoftheaboveprogram:
InorderSuccessorof14is20
TimeComplexity:O(h)wherehisheightoftree.
Method2(Searchfromroot)
ParentpointerisNOTneededinthisalgorithm.TheAlgorithmisdividedintotwocasesonthebasisofright
subtreeoftheinputnodebeingemptyornot.
Input:node,root//nodeisthenodewhoseInordersuccessorisneeded.
output:succ//succisInordersuccessorofnode.
1)IfrightsubtreeofnodeisnotNULL,thensuccliesinrightsubtree.Dofollowing.
Gotorightsubtreeandreturnthenodewithminimumkeyvalueinrightsubtree.
2)IfrightsbtreeofnodeisNULL,thenstartfromrootandussearchliketechnique.Dofollowing.
Traveldownthetree,ifanodesdataisgreaterthanrootsdatathengorightside,otherwisegotoleftside.
struct node * inOrderSuccessor(struct node *root, struct node *n)
{
// step 1 of the above algorithm
if( n->right != NULL )
return minValue(n->right);
// Start from root and search for successor down the tree
while (root != NULL)
{
if (n->data < root->data)
{
succ = root;
root = root->left;
}
else if (n->data > root->data)
root = root->right;
else
break;
}
return succ;
}
TimeComplexity:O(h)wherehisheightoftree.
=======================================================================
BinaryTreetoBinarySearchTree
Conversion
GivenaBinaryTree,convertittoaBinarySearchTree.Theconversionmustbedoneinsuchawaythat
keepstheoriginalstructureofBinaryTree.
Examples.
Example1
Input:
10
/\
27
/\
84
Output:
8
/\
410
/\
27
Example2
Input:
10
/\
3015
/\
205
Output:
15
/\
1020
/\
530
Solution
Followingisa3stepsolutionforconvertingBinarytreetoBinarySearchTree.
1)Createatemparrayarr[]thatstoresinordertraversalofthetree.ThissteptakesO(n)time.
2)Sortthetemparrayarr[].Timecomplexityofthisstepdependsuponthesortingalgorithm.Inthefollowing
implementation,QuickSortisusedwhichtakes(n^2)time.ThiscanbedoneinO(nLogn)timeusingHeap
SortorMergeSort.
3)Againdoinordertraversaloftreeandcopyarrayelementstotreenodesonebyone.ThissteptakesO(n)
time.
FollowingisCimplementationoftheaboveapproach.Themainfunctiontoconvertishighlightedinthe
followingcode.
/* A program to convert Binary Tree to Binary Search Tree */
#include<stdio.h>
#include<stdlib.h>
// Create a temp array arr[] and store inorder traversal of tree in arr[]
int *arr = new int[n];
int i = 0;
storeInorder (root, arr, &i);
15
20
*/
root = newNode(10);
root->left = newNode(30);
root->right = newNode(15);
root->left->left = newNode(20);
root->right->right = newNode(5);
return 0;
}
Output:
FollowingisInorderTraversaloftheconvertedBST:
510152030
WewillbecoveringanothermethodforthisproblemwhichconvertsthetreeusingO(heightoftree)extra
space.
=======================================================================
Aprogramtocheckifabinarytree
isBSTornot
Abinarysearchtree(BST)isanodebasedbinarytreedatastructurewhichhasthefollowingproperties.
Theleftsubtreeofanodecontainsonlynodeswithkeyslessthanthenodeskey.
Therightsubtreeofanodecontainsonlynodeswithkeysgreaterthanthenodeskey.
Boththeleftandrightsubtreesmustalsobebinarysearchtrees.
Fromtheabovepropertiesitnaturallyfollowsthat:
Eachnode(iteminthetree)hasadistinctkey.
METHOD1(SimplebutWrong)
Followingisasimpleprogram.Foreachnode,checkifleftnodeofitissmallerthanthenodeandrightnode
ofitisgreaterthanthenode.
int isBST(struct node* node)
{
if (node == NULL)
return 1;
METHOD2(Correctbutnotefficient)
Foreachnode,checkifmaxvalueinleftsubtreeissmallerthanthenodeandminvalueinrightsubtree
greaterthanthenode.
/* Returns true if a binary tree is a binary search tree */
int isBST(struct node* node)
{
if (node == NULL)
return(true);
METHOD3(CorrectandEfficient)
Method2aboverunsslowlysinceittraversesoversomepartsofthetreemanytimes.Abettersolution
looksateachnodeonlyonce.ThetrickistowriteautilityhelperfunctionisBSTUtil(structnode*node,int
min,intmax)thattraversesdownthetreekeepingtrackofthenarrowingminandmaxallowedvaluesasit
goes,lookingateachnodeonlyonce.TheinitialvaluesforminandmaxshouldbeINT_MINandINT_MAX
theynarrowfromthere.
/*Returnstrueifthegiventreeisabinarysearchtree
(efficientversion).*/
intisBST(structnode*node)
{
return(isBSTUtil(node,INT_MIN,INT_MAX))
}
/*ReturnstrueifthegiventreeisaBSTandits
valuesare>=minand<=max.*/
intisBSTUtil(structnode*node,intmin,intmax)
Implementation:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
return(node);
}
= newNode(2);
root->right
= newNode(5);
root->left->left = newNode(1);
root->left->right = newNode(3);
if(isBST(root))
printf("Is BST");
else
printf("Not a BST");
getchar();
return 0;
}
TimeComplexity:O(n)
AuxiliarySpace:O(1)ifFunctionCallStacksizeisnotconsidered,otherwiseO(n)
METHOD4(UsingInOrderTraversal)
ThankstoLJW489forsuggestingthismethod.
1)DoInOrderTraversalofthegiventreeandstoretheresultinatemparray.
3)Checkifthetemparrayissortedinascendingorder,ifitis,thenthetreeisBST.
TimeComplexity:O(n)
WecanavoidtheuseofAuxiliaryArray.WhiledoingInOrdertraversal,wecankeeptrackofpreviously
visitednode.Ifthevalueofthecurrentlyvisitednodeislessthanthepreviousvalue,thentreeisnotBST.
Thankstoygosforthisspaceoptimization.
bool isBST(struct node* root)
{
static struct node *prev = NULL;
// traverse the tree in inorder fashion and keep track of prev node
if (root)
{
if (!isBST(root->left))
return false;
prev = root;
return isBST(root->right);
return true;
}
=======================================================================
LowestCommonAncestorina
BinarySearchTree.
GivenvaluesoftwonodesinaBinarySearchTree,writeacprogramtofindtheLowestCommonAncestor
(LCA).Youmayassumethatboththevaluesexistinthetree.
Thefunctionprototypeshouldbeasfollows:
structnode*lca(node*root,intn1,intn2)
n1andn2aretwogivenvaluesinthetreewithgivenroot.
Forexample,considertheBSTindiagram,LCAof10and14is12andLCAof8and14is8.
FollowingisdefinitionofLCAfromWikipedia:
LetTbearootedtree.Thelowestcommonancestorbetweentwonodesn1andn2isdefinedasthelowest
nodeinTthathasbothn1andn2asdescendants(whereweallowanodetobeadescendantofitself).
TheLCAofn1andn2inTisthesharedancestorofn1andn2thatislocatedfarthestfromtheroot.
Computationoflowestcommonancestorsmaybeuseful,forinstance,aspartofaprocedurefor
determiningthedistancebetweenpairsofnodesinatree:thedistancefromn1ton2canbecomputedas
thedistancefromtherootton1,plusthedistancefromtherootton2,minustwicethedistancefromtheroot
totheirlowestcommonancestor.(SourceWiki)
Solutions:
IfwearegivenaBSTwhereeverynodehasparentpointer,thenLCAcanbeeasilydeterminedby
traversingupusingparentpointerandprintingthefirstintersectingnode.
WecansolvethisproblemusingBSTproperties.WecanrecursivelytraversetheBSTfromroot.Themain
ideaofthesolutionis,whiletraversingfromtoptobottom,thefirstnodenweencounterwithvaluebetween
n1andn2,i.e.,n1<n<n2orsameasoneofthen1orn2,isLCAofn1andn2(assumingthatn1<n2).So
justrecursivelytraversetheBSTin,ifnode'svalueisgreaterthanbothn1andn2thenourLCAliesinleft
sideofthenode,ifit'sissmallerthanbothn1andn2,thenLCAliesonrightside.OtherwiserootisLCA
(assumingthatbothn1andn2arepresentinBST)
// A recursive C program to find LCA of two nodes n1 and n2.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node* left, *right;
};
/* Function to find LCA of n1 and n2. The function assumes that both
n1 and n2 are present in BST */
struct node *lca(struct node* root, int n1, int n2)
{
if (root == NULL) return NULL;
// If both n1 and n2 are smaller than root, then LCA lies in left
if (root->data > n1 && root->data > n2)
return lca(root->left, n1, n2);
// If both n1 and n2 are greater than root, then LCA lies in right
if (root->data < n1 && root->data < n2)
return lca(root->right, n1, n2);
return root;
}
/* Helper function that allocates a new node with the given data.*/
= newNode(20);
root->left
= newNode(8);
root->right
= newNode(22);
root->left->left
= newNode(4);
root->left->right
= newNode(12);
root->left->right->left = newNode(10);
root->left->right->right = newNode(14);
n1 = 14, n2 = 8;
t = lca(root, n1, n2);
printf("LCA of %d and %d is %d \n", n1, n2, t->data);
n1 = 10, n2 = 22;
t = lca(root, n1, n2);
printf("LCA of %d and %d is %d \n", n1, n2, t->data);
getchar();
return 0;
}
Output:
LCAof10and14is12
LCAof14and8is8
LCAof10and22is20
TimecomplexityofabovesolutionisO(h)wherehisheightoftree.Also,theabovesolutionrequiresO(h)
extraspaceinfunctioncallstackforrecursivefunctioncalls.Wecanavoidextraspaceusingiterative
solution.
/* Function to find LCA of n1 and n2. The function assumes that both
n1 and n2 are present in BST */
struct node *lca(struct node* root, int n1, int n2)
{
while (root != NULL)
{
// If both n1 and n2 are smaller than root, then LCA lies in left
if (root->data > n1 && root->data > n2)
root = root->left;
// If both n1 and n2 are greater than root, then LCA lies in right
else if (root->data < n1 && root->data < n2)
root = root->right;
else break;
}
return root;
}
=======================================================================
MergeTwoBalancedBinarySearch
Trees
Youaregiventwobalancedbinarysearchtreese.g.,AVLorRedBlackTree.Writeafunctionthatmerges
thetwogivenbalancedBSTsintoabalancedbinarysearchtree.Lettherebemelementsinfirsttreeandn
elementsintheothertree.YourmergefunctionshouldtakeO(m+n)time.
Inthefollowingsolutions,itisassumedthatsizesoftreesarealsogivenasinput.Ifthesizeisnotgiven,
thenwecangetthesizebytraversingthetree(Seethis).
Method1(Insertelementsoffirsttreetosecond)
TakeallelementsoffirstBSTonebyone,andinsertthemintothesecondBST.Insertinganelementtoa
selfbalancingBSTtakesLogntime(Seethis)wherenissizeoftheBST.Sotimecomplexityofthismethod
isLog(n)+Log(n+1)Log(m+n1).ThevalueofthisexpressionwillbebetweenmLognandmLog(m+n1).
Asanoptimization,wecanpickthesmallertreeasfirsttree.
Method2(MergeInorderTraversals)
1)Doinordertraversaloffirsttreeandstorethetraversalinonetemparrayarr1[].ThissteptakesO(m)
time.
2)Doinordertraversalofsecondtreeandstorethetraversalinanothertemparrayarr2[].Thissteptakes
O(n)time.
3)Thearrayscreatedinstep1and2aresortedarrays.Mergethetwosortedarraysintoonearrayofsizem
+n.ThissteptakesO(m+n)time.
4)Constructabalancedtreefromthemergedarrayusingthetechniquediscussedinthispost.Thisstep
takesO(m+n)time.
TimecomplexityofthismethodisO(m+n)whichisbetterthanmethod1.ThismethodtakesO(m+n)time
eveniftheinputBSTsarenotbalanced.
FollowingisC++implementationofthismethod.
#include <stdio.h>
#include <stdlib.h>
/* A function that constructs Balanced Binary Search Tree from a sorted array
See http://www.geeksforgeeks.org/archives/17138 */
/* This function merges two balanced BSTs with roots as root1 and root2.
m and n are the sizes of the trees respectively */
struct node* mergeTrees(struct node *root1, struct node *root2, int m, int n)
{
// Store inorder traversal of first tree in an array arr1[]
int *arr1 = new int[m];
int i = 0;
storeInorder(root1, arr1, &i);
// Construct a tree from the merged array and return root of the tree
return sortedArrayToBST (mergedArr, 0, m+n-1);
}
return(node);
}
return mergedArr;
}
// A helper function that stores inorder traversal of a tree rooted with node
void storeInorder(struct node* node, int inorder[], int *index_ptr)
{
if (node == NULL)
return;
inorder[*index_ptr] = node->data;
(*index_ptr)++; // increase index for next entry
/* A function that constructs Balanced Binary Search Tree from a sorted array
See http://www.geeksforgeeks.org/archives/17138 */
struct node* sortedArrayToBST(int arr[], int start, int end)
{
/* Base Case */
if (start > end)
return NULL;
return root;
}
300
/\
20 70
*/
struct node *root1 = newNode(100);
root1->left
= newNode(50);
root1->right
= newNode(300);
root1->left->left
= newNode(20);
root1->left->right = newNode(70);
80
/ \
40
120
*/
struct node *root2 = newNode(80);
root2->left
= newNode(40);
root2->right
= newNode(120);
getchar();
return 0;
}
Output:
FollowingisInordertraversalofthemergedtree
2040507080100120300
Method3(InPlaceMergeusingDLL)
WecanuseaDoublyLinkedListtomergetreesinplace.Followingarethesteps.
1)ConvertthegiventwoBinarySearchTreesintodoublylinkedlistinplace(Referthispostforthisstep).
2)MergethetwosortedLinkedLists(Referthispostforthisstep).
3)BuildaBalancedBinarySearchTreefromthemergedlistcreatedinstep2.(Referthispostforthisstep)
TimecomplexityofthismethodisalsoO(m+n)andthismethoddoesconversioninplace.
=======================================================================
Findthenodewithminimumvalue
inaBinarySearchTree
Thisisquitesimple.JusttraversethenodefromroottoleftrecursivelyuntilleftisNULL.Thenodewhose
leftisNULListhenodewithminimumvalue.
Fortheabovetree,westartwith20,thenwemoveleft8,wekeeponmovingtoleftuntilweseeNULL.
Sinceleftof4isNULL,4isthenodewithminimumvalue.
#include <stdio.h>
#include<stdlib.h>
pointers. */
struct node* newNode(int data)
{
struct node* node = (struct node*)
malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return(node);
}
=======================================================================
DynamicProgramming|Set24
(OptimalBinarySearchTree)
Givenasortedarraykeys[0..n1]ofsearchkeysandanarrayfreq[0..n1]offrequencycounts,wherefreq[i]
isthenumberofsearchestokeys[i].Constructabinarysearchtreeofallkeyssuchthatthetotalcostofall
thesearchesisassmallaspossible.
LetusfirstdefinethecostofaBST.ThecostofaBSTnodeislevelofthatnodemultipliedbyitsfrequency.
Levelofrootis1.
Example1
Input:keys[]={10,12},freq[]={34,50}
TherecanbefollowingtwopossibleBSTs
1012
\/
1210
III
Frequencyofsearchesof10and12are34and50respectively.
ThecostoftreeIis34*1+50*2=134
ThecostoftreeIIis50*1+34*2=118
Example2
Input:keys[]={10,12,20},freq[]={34,8,50}
TherecanbefollowingpossibleBSTs
1012201020
\/\/\/
121020122010
\//\
20101212
IIIIIIIVV
AmongallpossibleBSTs,costofthefifthBSTisminimum.
CostofthefifthBSTis1*50+2*34+3*8=142
1)OptimalSubstructure:
Theoptimalcostforfreq[i..j]canberecursivelycalculatedusingfollowingformula.
WeneedtocalculateoptCost(0,n1)tofindtheresult.
Theideaofaboveformulaissimple,weonebyonetryallnodesasroot(rvariesfromitojinsecondterm).
Whenwemakerthnodeasroot,werecursivelycalculateoptimalcostfromitor1andr+1toj.
Weaddsumoffrequenciesfromitoj(seefirsttermintheaboveformula),thisisaddedbecauseevery
searchwillgothroughrootandonecomparisonwillbedoneforeverysearch.
2)OverlappingSubproblems
Followingisrecursiveimplementationthatsimplyfollowstherecursivestructurementionedabove.
// A naive recursive implementation of optimal binary search tree problem
#include <stdio.h>
#include <limits.h>
return 0;
if (j == i)
return freq[i];
// One by one consider all elements as root and recursively find cost
// of the BST, compare the cost with min and update min if needed
for (int r = i; r <= j; ++r)
{
int cost = optCost(freq, i, r-1) + optCost(freq, r+1, j);
// The main function that calculates minimum cost of a Binary Search Tree.
// It mainly uses optCost() to find the optimal cost.
int optimalSearchTree(int keys[], int freq[], int n)
{
// Here array keys[] is assumed to be sorted in increasing order.
// If keys[] is not sorted, then add code to sort keys, and rearrange
// freq[] accordingly.
return optCost(freq, 0, n-1);
}
CostofOptimalBSTis142
Timecomplexityoftheabovenaiverecursiveapproachisexponential.Itshouldbenotedthattheabove
functioncomputesthesamesubproblemsagainandagain.Wecanseemanysubproblemsbeingrepeated
inthefollowingrecursiontreeforfreq[1..4].
Sincesamesuproblemsarecalledagain,thisproblemhasOverlappingSubprolemsproperty.Sooptimal
BSTproblemhasbothproperties(seethisandthis)ofadynamicprogrammingproblem.Likeothertypical
DynamicProgramming(DP)problems,recomputationsofsamesubproblemscanbeavoidedbyconstructing
atemporaryarraycost[][]inbottomupmanner.
DynamicProgrammingSolution
FollowingisC/C++implementationforoptimalBSTproblemusingDynamicProgramming.Weusean
auxiliaryarraycost[n][n]tostorethesolutionsofsubproblems.cost[0][n1]willholdthefinalresult.The
challengeinimplementationis,alldiagonalvaluesmustbefilledfirst,thenthevalueswhichlieontheline
justabovethediagonal.Inotherwords,wemustfirstfillallcost[i][i]values,thenallcost[i][i+1]values,then
allcost[i][i+2]values.Sohowtofillthe2Darrayinsuchmanner>Theideausedintheimplementationis
sameasMatrixChainMultiplicationproblem,weuseavariableLforchainlengthandincrementL,oneby
one.WecalculatecolumnnumberjusingthevaluesofiandL.
// Dynamic Programming code for Optimal Binary Search Tree Problem
#include <stdio.h>
#include <limits.h>
{
/* Create an auxiliary 2D matrix to store results of subproblems */
int cost[n][n];
CostofOptimalBSTis142
Notes
1)ThetimecomplexityoftheabovesolutionisO(n^4).ThetimecomplexitycanbeeasilyreducedtoO(n^3)
byprecalculatingsumoffrequenciesinsteadofcallingsum()againandagain.
2)Intheabovesolutions,wehavecomputedoptimalcostonly.Thesolutionscanbeeasilymodifiedtostore
thestructureofBSTsalso.Wecancreateanotherauxiliaryarrayofsizentostorethestructureoftree.All
weneedtodois,storethechosenrintheinnermostloop.
=======================================================================