0% found this document useful (0 votes)
16 views209 pages

8 Dsa

Uploaded by

teeyanshshukla
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views209 pages

8 Dsa

Uploaded by

teeyanshshukla
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 209

❖ Definition

Outline
❖ Tree Terminology
❖ Binary Trees
❖ Types of Binary Trees
❖ Some Q & A
❖ Expression Trees
❖ Tree Traversal
❖ Construction of Binary Tree
❖ Construction of Expression Trees and its Evaluation
❖ MCQs and Assignments
❖ Binary Search Trees (BST)
❖ Creation, Insertion & Deletion Operations on BSTs
❖ Height Balanced Trees (AVL Trees) (Insertion & Deletion)
❖ B-Trees and B+ Trees (Insertion & Deletion)
❖ Heap Trees (Max Heap & Min Heap)
❖ Assignments and Doubt Clearance
Why Study Trees???
They give the hierarchical relationship between
different elements.

Good example of recursive data structures


Methods are recursive algorithms

For language processing (human or computer).


Eg: Parse trees

For knowledge representation and modeling of


the “real world” relations.
E.g. family trees; the Linnaean taxonomy
(kingdom, phylum, …, species); etc.
Trees
Why should you care?

Trees are used to organize data in


many software applications, including:

Databases (B-TREES)
Data Compression (Huffman Trees)
Bitcoin (Merkle Trees)
Medical Diagnosis (Decision Trees)
Trees
A Tree is a special linked list-based data structure
that has many uses in Computer Science:

A Decision Tree
AAn A Does
Binary
FamilytheTree
Search Tree
• To organize hierarchical data Expression Tree
patient
• To make information easily have a+fever?
“marty”
“carey”
searchable yes no
• To simplify the evaluation of Does he/she Does he/she
mathematical expressions have “harry”
spots
* on
“leon”
his/her face?
have +
a sore
“andrea”
“rich”
throat?
• To make decisions
yes
“sheila”
“alan”
He has 32 …
“simon”
“jacob” -42 “milton”
17 “martha”
“nancy” “zai”
4
COOTIES!
NULL NULL
NULL NULL NULL
NULL NULL NULL NULL
NULL NULL
NULL NULL NULL NULL
NULL
A Real World Tree

A Tree Data Structure


Data Organized in a Tree Structure
InfoTech

Sales Manufacturing R&D

US International Laptops Desktops

Europe Asia Canada


Root

A General Tree

T1 T2 T3 T4
…… Tn

Sub Trees
❖ A tree structure means that the data are organized so that
items of information are related by branches.

❖ It is used to represent hierarchical relationship existing among


several data items.
ROOT Example
T2 T3
InfoTech Subtree Subtree
T1
Subtree

Sales Manufacturing R&D

US International Laptops Desktops

Europe Asia Canada


What is a Tree???

A tree is a non-linear data structure made up of nodes or


vertices and edges without having any cycle.

The tree with no nodes is called the null or


empty tree.

A tree that is not empty consists of a root node and


potentially many levels of additional nodes that form a
hierarchy.
Definition:

A tree is a finite set of one or more data items (nodes) such


that
• There is a specially designated node called the root node,
• The remaining nodes are partitioned into n>=0 disjoint set
T1,…,Tn, where each of these sets is a tree. T1,…,Tn are
called the subtrees of the root.
Basic Tree Facts
1. Trees are made of nodes
(just like linked list nodes). root ptr
2. Every tree has a "root" pointer. Empty tree NULL
3. The top node of a tree
is called its But
"root" node.
instead of just one next 5
Root node
4. Every node may have
pointer, zeronode can have
a tree
two or more
or more “children” next pointers!
nodes.
5. A node with 0 children is
called a “leaf” node. 2 children -33 1 child 17
NULL
6. A struct
tree with no nodes is
node
The{ tree’s
called anroot
“empty tree.”
pointer is likevalue;
int a linked// some value
list’s head
nodepointer! 0
*left, *right;Leaf node
children 53 91 -115
}; NULL NULL NULL NULL NULL NULL

node *rootPtr;
Tree Nodes Can Have Many Children
A tree node can have more than just two children:
struct node
{
int value; // node data

node *pChild1, *pChild2, *pChild3, …;


}; root ptr

struct node
{
int value; // node data 3
node *pChildren[26]; NULL
};

7 4 15
NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
Familiarity with Tree Terms
B,C,D,E,F and G are children of A
A is the root
G is parent of N
and child of A

B,C,D,E,F,G are siblings

M is child of F and
grandchild of A
A is an ancestor of P
P is a descendant of A

B,C,H,I,P,Q,K,L,M,N are leaves K,L,M are siblings


I and J are siblings
P and Q are siblings
TREE TERMINOLOGY
• Node: Each data item in a tree is a called a node. It specifies the
data information and links to other data items.
• Root: It is a specially designated data item in a tree. It is the first in
the hierarchical arrangement of data items.
• Subtree: Tree consisting of a node and its descendants.
• Degree: The number of immediate nodes (subtrees) attached to a
node.
• Degree of a tree: The maximum degree of node in a tree.
• Terminal/ Leaf node(s): A node with degree zero.
• Non-terminal/ Interior node(s): Nodes with at least degree one.
• Child node: The immediate successor of a node.
• Parent node: The immediate predecessor of a node.
• Ancestors: Parent, grandparent, great-grandparent, etc.
• Descendants: Child, grandchild, great-grandchild, etc.
Contd…
• Siblings: Nodes having the same parent node.
• Edge: A line connecting two nodes (parent and child nodes).
• Path: A sequence of consecutive edges from the source node to the
destination node.
• Height of a node: The height of a node ni is the length of the
longest path from ni to a leaf node.
• Depth of a node: The depth of a node ni is the length of the longest
path from root to ni.
• Forest: A forest is a set of n ≥ 0 disjoint trees.
Height of root = Height of tree = Depth of tree

Height of leaf node = 0

Depth of root node = 0


LEVEL
0

Degree of tree = 6 3

Degree(A)= 6, Degree(F)= 3, Degree(L)= 0


Root is always at Level 0
Height(J)= 1, Height(E)= 2, Height(K)= 0
Siblings are placed in
Depth(M)= 2, Depth(G)= 1, Depth(P)= 3
the same level
Height of tree = Depth of tree = 3
Lets Answer These!!!
A

B C

D E F

G H

Who isisthe parent ofofE???


Who the sibling H???
WhatWhat
is theisdegree of the tree???
What is the depth of theF???
the height of tree??? G
0
B
32
Binary Tree They are also
known as 2-way
• A binary tree is a tree where each node has trees
no more than two children.
• That is, a node in a binary tree can have a maximum of two
child nodes.

A A A A A

B B B C B C

D E F
LEVEL

A 0
Degree of Binary Tree <= 2

B C 1

D E F G 2

H I J K 3

L M N 4
Binary Trees
A binary tree is a special form of tree. In a binary tree,
every node has at most two children nodes:
A left child and a right child.

struct BTNODE // binary tree node


{ A Binary Tree
string value; // node data
“carey”
BTNODE *pLeft, *pRight;
};
“leon” “andrea”

“sheila” “simon” “martha” “milton”


NULL NULL NULL NULL NULL NULL NULL NULL
Properties of A Binary Tree
The maximum number of nodes on level i of a
binary tree is 2i-1, i 1.

The maximum number of nodes in a binary tree of


k levels is 2k-1, k1.

For any nonempty binary tree, T, if n0 is the


number of leaf nodes and n2 is the
number of nodes of degree 2, then n0 = n2 + 1.
Operations on Binary Trees
The following are common operations that we might
perform on a Binary Tree:

• enumerating all the items


• searching for an item
• adding a new item at a certain position on the tree
• deleting an item
• deleting the entire tree (destruction)
• removing a whole section of a tree (called pruning)
• adding a whole section to a tree (called grafting)
Strictly (or Full) Binary Trees
• If every non-terminal node in a binary tree consists of non-empty
left- and right subtrees, then such a tree is called a strictly binary
tree.

Each node in the tree has either no children or exactly two child nodes.

Example: A

B C Also known
as
D E Full Binary
Tree

F G
Complete Binary Trees
• A Complete Binary Tree is a binary tree in which every level, except
possibly the last, is completely filled, and all nodes are as far left as
possible.

Complete Binary Tree Perfect Binary Tree

Almost Complete
Binary Tree

A Perfect Binary Tree is a binary tree where every level is


completely filled.

An Almost Complete Binary Tree is a binary tree where all


levels are filled expect the last level and the nodes in the
last level are as far left as possible. It is also known as
nearly complete binary tree.
LEVEL
Example:
A 0

B C 1

D E F G 2

H I J K L M N O 3

A perfect binary tree is both full and complete


but not vice-versa
LEVEL
Example:
A 0

B C 1

D E F G 2

H I J K L M N O 3

Still…An
An almost Almost
NOTbinary
complete Complete
tree is not
An Almost Complete
always a full
Binary
binary tree
Tree
An Almost Binary
Complete TreeBinary Tree
A complete binary tree with n
vertices and height H satisfies:
• 2H ≤ n < 2H + 1
• H ≤ log n < H + 1
• H = floor(log n)
Skewed Binary Trees
A A

B B

C
C

D D

A Binary Tree in A Binary Tree in


which each node has which each node has
only a left subtree only a right subtree
Some Logics !!!

What is the max number nodes


2l
at some level l in a binary tree?

What is the total number of nodes N


of a Complete binary tree with height h? 2h+1 -1
What is the height h
of a Complete binary tree with N
nodes?
2h+1 -1=N
→2h+1 =N +1
→h+1=log(N + 1)
→ O(log N)
Memory Representations of Binary Tree

Two ways of Representation

Array Representation Link-List Representation

Array Representation is static in nature


Link-List Representation is dynamic in nature
Array Representation of Binary Tree
If a complete binary with n nodes is represented sequentially,
then for any node with index i, 0  i  n-1, we have,
parent(i) is at (i-1)/2 if i  0.
If i = 0, then i is at the root and has no parent.

LeftChild(i) is at 2i+1 if 2i+1  n.


If 2i +1  n, then i has no left child.

RightChild(i) is at 2i+2 if 2i+2  n. A 0


If 2i+2  n, then i has no right child.
[0] [1] [2] [3] [4] [5] [6]
B 1 C 2
A B C — D — E

Level 0 D E
Level 1 Level 2
3 4 5 6
Example
[0] A
A
[1] B
0
[2] ---
B [3] C
1 [4] ---
Array Representation
C [5] ---
3 [6] ---
[7] D
D
[8] ---
7

Waste Spaces: in the worst case, a skewed tree of k levels


requires 2k-1 spaces. Of these, only k spaces will be
occupied
Array Implementation
Array Implementation

#include<bits/stdc++.h>
using namespace std;
char tree[10];
int root(char key) {
if (tree[0] != '\0')
cout << "Tree already had root";
else
tree[0] = key;
return 0;
}
Array Implementation

int set_left(char key, int parent) {


if (tree[parent] == '\0')
cout << "\n Can't set child at "
<< (parent * 2) + 1
<< " , no parent found";
else
tree[(parent * 2) + 1] = key;
return 0;
}
Array Implementation

int set_right(char key, int parent) {


if (tree[parent] == '\0')
cout << "\nCan't set child at "
<< (parent * 2) + 2
<< " , no parent found";
else
tree[(parent * 2) + 2] = key;
return 0;
}
Array Implementation

int print_tree() {
cout << "\n";
for (int i = 0; i < 10; i++) {
if (tree[i] != '\0')
cout << tree[i];
else
cout << "-";
}
return 0;
}
Array Implementation
// Driver Code
int main() {
root('A');
set_left('B',0);
set_right('C', 0);
set_left('D', 1);
set_right('E', 1);
set_right('F', 2);
print_tree();
return 0;
}
Link List Representation of Binary Tree
❖ Here a single tree node consist of three fields such as,
❖ Data: It holds the value of the node
❖ Left child: It is a link field which contains the address of its left child
❖ Right child: It contains the address of its right child

LeftChild Data RightChild

struct treenode
Structure of the Node {
char data ;
struct treenode *lchild ;
struct treenode *rchild ;
};
A 0 Example The field value is
NULL when child
node is absent
B 1 C 2

Link List Representation


D E
3 4 5 6

NULL B NULL C

NULL D NULL NULL E NULL


struct BTNODE // node
{
A Simple Tree
int value; // data
BTNODE *left, *right; Example
};
OS – can Asyou
temp 1200
1100 lists, we use
with linked
main() reserve 12 bytes dynamic
pRoot 1000 memory to
{
OS – can youforallocate our nodes.
of memory
BTNODE *temp, *pRoot;
reserve me?
12 bytes
pRoot = new BTNODE; 1000
of
pRoot->value = 5; memory for value 5
me? left right
temp = new BTNODE;
temp->value = 7; OS – can you 1200 1100

reserve 12 bytes
temp->left = NULL;
temp->right = NULL;
of memory
pRoot->left = temp;
temp-> for
value 7
1200
me? left right temp-> value -3 1100
temp = new BTNODE;
temp->value = -3; NULL NULL Sure, here’s a
left right
temp->left = NULL; chunk ofNULLmemory
NULL
temp->right = NULL; at address 1200.
1100.
1000.
pRoot->right = temp; And of course, later we’d have
// etc…
to delete our tree’s nodes.
Expression Trees
Expression Tree is a binary tree associated with an arithmetic expression,
here
• internal nodes are operators
• external nodes are operands

Example: Arithmetic expression tree for the expression


(2  (a - 1) + (3  b))

 

2 − 3 b

a 1
Maximum Depth of Binary Tree
Follow the steps below to solve the problem:
1. If the tree is empty then return 0.
2. Otherwise, do the following
• Get the max depth of the left subtree recursively i.e.
call maxDepth( node->left).
• Get the max depth of the right subtree recursively i.e.
call maxDepth( node->right).
• Get the max of max depths of left and right subtrees and add
1 to it for the current node.
• maxDepth = max(maxDepth of left subtree, max depth of right
subtree) + 1.
3. Return maxDepth.
Implementation
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* left; int maxDepth(struct Node* node) {
struct Node* right; }; if (node == NULL)
return 0;

// compute the depth of left and right subtrees


int lDepth = maxDepth(node->left);
int rDepth = maxDepth(node->right);

return (lDepth > rDepth ? lDepth : rDepth) + 1;


}
Implementation

Struct node* createnode(int val) {


struct node* node = (struct node*)malloc(sizeof(struct node));
Node->data = val;
Node->left = NULL;
Node->right = NULL;
Return node;
}
Implementation
int main() {
// Representation of the input tree:
// 1
// /\
// 2 3
// / \
// 4 5
struct Node* root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
printf("%d\n", maxDepth(root));
return 0; Output: “3”
}
Traversing Binary Trees
Traversing a binary tree is a way of visiting each
node exactly ones in a systematic manner
There are three standard ways of traversing a binary tree T with
a root R. They are as follows:

Preorder Traversal

Inorder Traversal

Postorder Traversal
Recursive Traversal Algorithms
Preorder Traversal
Preorder(T)
Step 1: Process the root node (say R) → Visit
Step 2: Traverse the left subtree in Preorder
Step 3: Traverse the right subtree in Preorder
Example: A Preorder Sequence:
A B D E HC F G I
B C

D E F G

H I
The Pre-order Traversal cur a
“a” root
Output:
cur b
“b” “c”
NULL NULL

cur NULL cur d


“d” “e”
Our base NULLcase
NULL checks
NULL NULLto

see if cur points at an


void PreOrder(Node *cur) empty sub-tree.
void
{ PreOrder(Node *cur)
void
{ PreOrder(Node *cur) //Then
Otherwise we “process”
if (cur == NULL)
Once we
if empty,
If
cur’s usethere’s
return…
so,
entire recursion
left to to
nothing
subtree
{ PreOrder(Node
void if (cur ==
return;NULL)*cur) // if the
empty, value
return… in the current
{ if (cur == NULL)
return; has
// if process
been
empty, cur’s entire
process
processed,
return… and we’re
weleft done!
then
cout << cur->value; // Process the node…
current node.
main()
return;
if (cur == NULL) // if subtree
empty, return…(a simplifying step).
cout <<
return; cur->value; // process
Process the its
current entire
node. right
{
coutPreOrder(cur->left);
<< cur->value; // Process
// Process nodes innode.
the current left sub-tree.Node *root;
subtree!
PreOrder(cur->left);
PreOrder(cur-> right);////Process
cout << cur->value; Processnodes
nodesininleft
// Process the current node. sub-tree.
right sub-tree.
PreOrder(cur->left);
}PreOrder(cur-> right);////Process
Processnodes
nodesinin
left sub-tree.
right sub-tree. …
}PreOrder(cur-> right);////Process
PreOrder(cur->left); Processnodes
nodesininleft
right sub-tree.
sub-tree.
} PreOrder(cur-> right); // Process nodes in right sub-tree. PreOrder(root);
} }
The Pre-order Traversal cur “a” root
Output:
a b d cur “b” “c”
cur
NULL NULL
NULL
cur “d” “e”
NULL NULL NULL NULL

void PreOrder(Node *cur)


void PreOrder(Node *cur)
{
void
{ PreOrder(Node *cur)
if (cur == NULL) // if empty, return…
{ PreOrder(Node
void if (cur == NULL) *cur) // if empty, return…
return;
{ if (cur == NULL)
return; // if empty, return… main()
return;
if (cur == NULL)
cout << cur->value; // if//empty,
Process return…
the current node. {
cout <<
return; cur->value; // Process the current node.
coutPreOrder(cur->left);
<< cur->value; // Process the current
// Process left sub-tree.Node *root;
nodes innode.
coutPreOrder(cur->left);
<< cur->value; right); // Process
// Process the nodes
current in node.
left sub-tree.
PreOrder(cur-> // Process nodes in right sub-tree.
PreOrder(cur->left); // Process nodes in
PreOrder(cur-> right); // Process nodes in right left sub-tree.
sub-tree. …
}
}PreOrder(cur-> right);////Process
PreOrder(cur->left); Processnodes
nodesininleft
right sub-tree.
sub-tree.
} PreOrder(cur-> right); // Process nodes in right sub-tree. PreOrder(root);
} }
The Pre-order Traversal cur “a” root
Output:
a b d cur “b” “c”
NULL NULL

cur “d” “e”


NULL NULL NULL NULL

void PreOrder(Node *cur)


void
{ PreOrder(Node *cur)
{ PreOrder(Node
void if (cur == NULL) *cur) // if empty, return…
{ if (cur == NULL)
return; // if empty, return… main()
return;
if (cur == NULL) // if empty, return…
cout << cur->value; // Process the current node. {
return;
cout << cur->value; // Process the current node. Node *root;
coutPreOrder(cur->left);
<< cur->value; // Process
// Process the nodes
current in node.
left sub-tree.
PreOrder(cur->left);
PreOrder(cur-> right);////Process
Processnodes
nodesininleft sub-tree.
right sub-tree. …
}PreOrder(cur-> right);////Process
PreOrder(cur->left); Processnodes
nodesininleft
right sub-tree.
sub-tree.
} PreOrder(cur-> right); // Process nodes in right sub-tree. PreOrder(root);
} }
The Pre-order Traversal cur “a” root
Output:
a b d cur “b” “c”
NULL NULL

“d” e
“e” cur
NULL NULL NULL NULL

void PreOrder(Node *cur)


void
{ PreOrder(Node *cur)
{ PreOrder(Node
void if (cur == NULL) *cur) // if empty, return…
{ if (curreturn;
== NULL) // if empty, return… main()
return;
if (cur == NULL) // if empty, return…
cout << cur->value; // Process the current node. {
return;
cout << cur->value; // Process the current node. Node *root;
coutPreOrder(cur->left);
<< cur->value; // Process
// Process nodes innode.
the current left sub-tree.
PreOrder(cur->left);
PreOrder(cur-> right);//// Process nodes
Process in in
nodes left sub-tree.
right sub-tree.…
}PreOrder(cur-> right);////Process
PreOrder(cur->left); Processnodes
nodesininleft
right sub-tree.
sub-tree.
} PreOrder(cur-> right); // Process nodes in right sub-tree. PreOrder(root);
} }
The Pre-order Traversal cur “a” root
Output:
a b d e cur “b” “c”
NULL NULL

“d” “e”
NULL NULL NULL NULL

void PreOrder(Node *cur)


{ PreOrder(Node *cur)
void
{ if (cur == NULL) // if empty, return… main()
return;
if (cur == NULL) // if empty, return… {
return;
cout << cur->value; // Process the current node. Node *root;
cout << cur->value; // Process the current node.
PreOrder(cur->left); // Process nodes in left sub-tree. …
PreOrder(cur-> right);////Process
PreOrder(cur->left); Processnodes
nodesininleft
right sub-tree.
sub-tree.
} PreOrder(cur-> right); // Process nodes in right sub-tree. PreOrder(root);
} }
The Pre-order Traversal cur “a” root
Output:
a b d e c
“b” cur “c”
NULL NULL

“d” “e”
NULL NULL NULL NULL

void PreOrder(Node *cur)


void
{ PreOrder(Node *cur)
{ if (cur == NULL) // if empty, return… main()
if (curreturn;
== NULL) // if empty, return… {
return;
cout << cur->value; // Process the current node. Node *root;
cout << cur->value; // Process the current node.
PreOrder(cur->left); // Process nodes in left sub-tree. …
PreOrder(cur->left);
PreOrder(cur-> right);////Process nodes
Process nodesin in
left sub-tree.
right sub-tree.
}PreOrder(cur-> right); // Process nodes in right sub-tree.
PreOrder(root);
} }
Recursive Traversal Algorithms
Inorder Traversal
Inorder(T)
Step 1: Traverse the left subtree in Inorder
Step 2: Process the root node (say R) → Visit
Step 3: Traverse the right subtree in Inorder
Example: A Inorder Sequence:
D B H E A F C G I
B C

D E F G

H I
The In-order Traversal
1. Process the nodes in the left
sub-tree. cur “a” root
2. Process the current node.
3. Process the nodes in the right
sub-tree. cur “b” “c”
NULL NULL NULL NULL

void InOrder(Node *cur)


{
void InOrder(Node *cur)
if (cur == NULL) // if empty, return…
{
return;
if (cur == NULL) // if empty, return… Output:
return;
InOrder(cur->left); // Process nodes in left sub-tree.
InOrder(cur->left); ////Process
b
cout << cur->value; Processnodes in left sub-tree.
the current node.
cout << cur->value; // //
InOrder(cur->right); Process thenodes
Process current node.sub-tree.
in right
}
InOrder(cur->right); // Process nodes in right sub-tree.
}
The In-order Traversal
1. Process the nodes in the left
sub-tree. cur “a” root
2. Process the current node.
3. Process the nodes in the right
sub-tree. “b” cur “c”
NULL NULL NULL NULL

void InOrder(Node *cur)


{
void InOrder(Node *cur)
if (cur == NULL) // if empty, return…
{
return;
if (cur == NULL) // if empty, return… Output:
return;
InOrder(cur->left); // Process nodes in left sub-tree.
InOrder(cur->left); ////Process
bac
cout << cur->value; Processnodes in left sub-tree.
the current node.
cout << cur->value; // //
InOrder(cur->right); Process thenodes
Process current node.sub-tree.
in right
}
InOrder(cur->right); // Process nodes in right sub-tree.
}
Recursive Traversal Algorithms
Postorder Traversal
Postorder(T)
Step 1: Traverse the left subtree in Postorder
Step 2: Traverse the right subtree in Postorder
Step 3: Process the root node (say R) → Visit
Example: A Postorder Sequence:
D H E B F I G C A
B C

D E F G

H I
The Post-order Traversal
1. Process the nodes in the left
sub-tree. cur “a” root
2. Process the nodes in the right
sub-tree.
3. Process the current node. cur “b” “c”
NULL NULL NULL NULL

void PostOrder(Node *cur)


{
void PostOrder(Node *cur)
if (cur == NULL) // if empty, return…
{
return;
if (cur == NULL) // if empty, return… Output:
return;
PostOrder(cur->left); // Process nodes in left sub-tree.
PostOrder(cur->left);
PostOrder(cur-> right);////
Process nodes
Process in in
nodes left sub-tree.
right sub-tree.
b
PostOrder(cur-> right); //
cout << cur->value; // Process
Process the
nodes in right
current sub-tree.
node.
}
cout << cur->value; // Process the current node.
}
The Post-order Traversal
1. Process the nodes in the left
sub-tree. cur “a” root
2. Process the nodes in the right
sub-tree.
3. Process the current node. “b” cur “c”
NULL NULL NULL NULL

void PostOrder(Node *cur)


{
void PostOrder(Node *cur)
if (cur == NULL) // if empty, return…
{
return;
if (cur == NULL) // if empty, return… Output:
return;
PostOrder(cur->left); // Process nodes in left sub-tree.
PostOrder(cur->left);
PostOrder(cur-> right);////
Process nodes
Process in in
nodes left sub-tree.
right sub-tree.
bc a
PostOrder(cur-> right); //
cout << cur->value; // Process
Process the
nodes in right
current sub-tree.
node.
}
cout << cur->value; // Process the current node.
}
Traverse the Binary Tree
A
Postorder
Preorder
Inorder
???
???
B C

D E F G

H I J

Preorder: A B D E H C F G I K J K

Inorder: D B H E A F C K I G J

Postorder: D H E B F K I J G C A
In Preorder Traversal Sequence:
The root is always present at the
beginning (followed by the left & then
the right subtree nodes)

Preorder:
A B D E H C F G I K J

Root Left Right


Subtree Subtree
In Inorder Traversal Sequence:
The root is always present at the middle
(following the left & followed by the
right subtree nodes)

Inorder:
D B H E A F C K I G J

Left Root Right


Subtree Subtree
In Postorder Traversal Sequence:
The root is always present at the end
(starting with the left & then the right
subtree nodes)

Postorder:
D H E B F K I J G C A

Left Right Root


Subtree Subtree
The Level Order Traversal
In a level order traversal we visit each level’s nodes, from
left to right, before visiting nodes in the next level.
temp 800
700
720
780
Here’s the algorithm:
700
1. Use a temp pointer variable and 700 root
“a”
a queue of node pointers. 720780

2. Insert the root node pointer


720 780
into the queue. “b” “c”
800760 NULL 900
3. While the queue is not empty:
A. Dequeue the top node
800 “d” 760 “e” 900 “f”
pointer and put it in temp. NULL NULL NULL NULL NULL NULL

B. Process the node.


C. Add the node’s children to
queue if they are not NULL. 700
780
720900
760
800760780
800760
900
a b c d Etc… front rear
67

Big-Oh of Traversals?
Question: What’re the big-ohs of each of our traversals?

Answer: Well, since a traversal must visit each node


exactly once…
and since there are n nodes in a tree…
the big-oh for any of the traversals is…
void PreOrder(Node *cur)
{

O(n)
if (cur == NULL)
return;
cout << cur->value;
PostOrder(cur->left);
PostOrder(cur-> right);
}
An Easy Way to Remember the Order of
Pre/In/Post Traversals

Starting just above-left of the root


node, draw a loop counter-clockwise
around all of the nodes.

Ok, got that?


Pre-order Traversal: Dot on the LEFT
To determine the order of nodes
1
visited in a pre-order traversal…

2 7
Draw a dot next to each node as
3 4 8 you pass by its left side.
5 6 9

The order you draw the dots is the


Pre-order: order of the pre-order traversal!
FBADCEGIH
In-order Traversal: Dot UNDER the node
To determine the order of nodes
visited in a in-order traversal…
6

2 7 Draw a dot next to each node as


you pass by its under-side.
1 4 9

3 5 8 The order you draw the dots is the


order of the in-order traversal!
In-order:
ABCDEFGHI
Post-order Traversal: Dot on the RIGHT
To determine the order of nodes
9
visited in a post-order traversal…

5 8
Draw a dot next to each node as
1 4 7 you pass by its right side.
2 3 6
The order you draw the dots is the
order of the post-order traversal!
Post-order:
ACEDBHIGF
Level-order Traversal: Level-by-level
To determine the order of nodes
1
visited in a level-order traversal…
2 3
Start at the top node and draw a
4 5 6
horizontal line left-to-right
7 8 9 through all nodes on that row.

Repeat for all remaining rows.


Level-order:
FBGADICEH The order you draw the lines is the
order of the level-order traversal!
Question

1
/\
2 3
/
4
/
5
Question

Inorder Traversal (Left, Root, Right):


1
5, 4, 2, 1, 3
/\
Preorder Traversal (Root, Left, Right):
2 3
1, 2, 4, 5, 3
/
Postorder Traversal (Left, Right, Root):
4
5, 4, 2, 3, 1
/
Level Order Traversal:
5
1, 2, 3, 4, 5
Question

50
/ \
25 75
/ \ / \
22 40 60 80
/\ /
15 30 90
Question

Inorder Traversal:
50
15, 22, 25, 30, 40, 50, 60, 75, 80, 90
/ \
Preorder Traversal:
25 75
50, 25, 22, 15, 30, 40, 75, 60, 80, 90
/ \ / \
Postorder Traversal:
22 40 60 80
15, 30, 22, 40, 25, 60, 90, 80, 75, 50
/\ /
Level Order Traversal:
15 30 90
50, 25, 75, 22, 40, 60, 80, 15, 30, 90
77

Practice Question
Construct a binary tree from its
inorder and preorder traversals

• Explain that we are given two lists (or arrays):

– Preorder Traversal: This is the order in


which nodes are visited as we traverse the
tree in "root-left-right" order.
– Inorder Traversal: This is the order of nodes
in "left-root-right" order.
• Goal: To reconstruct the binary tree structure
from these two lists.
Approach to Construct the
Tree
1. Identify the root using preorder
traversal (first element).
2. Locate the root in the inorder
traversal to split it into left and right
subtrees.
3. Recursively apply the same steps to
build left and right subtrees.
Example Data:
• Preorder: [A, B, D, E, C, F]
• Inorder: [D, B, E, A, F, C]
Step 1: Find the root (first element of preorder).
• Root = A
Step 2: Locate A in the inorder list.
• Inorder: [D, B, E, A, F, C]
• Left subtree: [D, B, E]
• Right subtree: [F, C]
Step 3: Repeat the process for left and right subtrees.
• Left Subtree Preorder: [B, D, E]
• Right Subtree Preorder: [C, F]
For each subtree, continue to:
• Select the next root from the remaining
preorder list.
• Split the inorder list at the root’s position to
separate left and right subtrees.
• Build left and right subtrees recursively.
Final Tree Structure
A
/\
B C
/\ \ To build the tree:
D E F • Use preorder to determine root nodes.
• Use inorder to determine subtree
boundaries.
• Recursively apply these rules to
reconstruct the tree.
Question

Given the following preorder and inorder


traversals of a binary tree, construct the binary
tree:
• Preorder Traversal: [3, 9, 20, 15, 7]
• Inorder Traversal: [9, 3, 15, 20, 7]
Solution

3
/\
9 20
/ \
15 7
Construct a binary tree from its inorder
and postorder traversals

Now consider the in-order traversal and post-


order traversal sequences of a given binary tree.
Before constructing the binary tree, remember
that in post-order traversal the root node is
the last node.
Example
Given the following inorder and postorder traversals of
a binary tree, construct the binary tree:
• Inorder Traversal: [4, 2, 5, 1, 6, 3, 7]
• Postorder Traversal: [4, 5, 2, 6, 7, 3, 1]
Identify the Root:
• In postorder traversal, the last element is always the root of the tree.
• Here, the last element of the postorder list is 1, so 1 is the root.
Locate the Root in Inorder Traversal:
• Find 1 in the inorder list to split it into left and right subtrees.
• Inorder Traversal: [4, 2, 5, 1, 6, 3, 7]
– Left Subtree (elements to the left of 1): [4, 2, 5]
– Right Subtree (elements to the right of 1): [6, 3, 7]
Recursive Construction of Subtrees:
• Using the remaining elements of the postorder list, recursively repeat the process for each
subtree:
Left Subtree:
• Inorder: [4, 2, 5]
• Postorder: [4, 5, 2]
• Root is 2 (last element in the left subtree’s postorder list).
• Split at 2 in inorder gives left [4] and right [5].
Right Subtree:
• Inorder: [6, 3, 7]
• Postorder: [6, 7, 3]
• Root is 3 (last element in the right subtree’s postorder list).
• Split at 3 in inorder gives left [6] and right [7].
Solution
1
/\
2 3
/\ /\
4 56 7
Facts
We Cannot uniquely construct a binary tree if only the preorder
and postorder traversals are given. Here's why:
1. Lack of Unique Structure:
• Preorder and postorder traversals do not provide information about
the inorder sequence of nodes, which is essential to determine the
left and right child relationships for each node uniquely.
• With just preorder and postorder, multiple valid binary tree
structures could result from the same pair of traversals.
2. Special Case:
• However, if the binary tree is full (every node has 0 or 2 children),
then we can construct the tree uniquely using preorder and
postorder traversals. This is because, in a full binary tree, there’s a
fixed structure, and we can infer the boundaries of the left and right
subtrees based on node positions.
Example of Ambiguity
For example, consider these preorder and postorder traversals:
• Preorder: [A, B, D, E, C, F]
• Postorder: [D, E, B, F, C, A]

With only these traversals, two different trees could


match:

Tree 1 Tree 2
A A
/\ / \
B C B C
/\ \ /\ /
D E F D E F
Expression Evaluation
We can represent arithmetic expressions using a
binary tree.

For example, the tree on


the left represents the
ptr expression: (5+6)*(3-1)

Once you have an expression


in a tree, its easy to
evaluate it and get the
result.

Let’s see how!


Expression Evaluation
Here’s our evaluation function. We start by passing in a
pointer to the root of the tree.

1. If the current node is a (5+6)*(3-1)


1. Ifnumber,
the current
returnnode
its is a
value.
1. If the current
number, returnnode is a
its value. ptr
2. Recursively
number, returnevaluate
its value.the left
2. Recursively
subtree evaluate
and get the the left
result. cur
2. Recursively evaluate the
subtree and get the result. left
3. Recursively
subtree and getevaluate
the result.the right
3. Recursively
subtree andevaluate
get the the right
result.
3. Recursively
subtree and evaluate
get thethe right
result. cur
4. Applyand
subtree theget
operator in the
the result.
4. Apply the node
current operator
to in the
the left and
4. Apply the
current operator
node toreturnin the
the left and
right
current results;
node toreturn
the left the
and
right results;
result. the
right results; return the
result.
result.
Expression Evaluation
Here’s our evaluation function. We start by passing in a
pointer to the root of the tree.

1. If the current node is a (5+6)*(3-1)


1. Ifnumber,
the current
return node
its is a
value.
1. If the current
number, returnnode is a
its value. ptr
2.number,
Recursively
returnevaluate
its value. the left
2. Recursively
subtree evaluate
and get the the left
result. cur
2. Recursively
subtree andResult
evaluate
get the= 5 result.
the left
3.subtree
Recursively
and getevaluate
the result.the right
3. Recursively
subtree andevaluate
get the the right
result.
3. Recursively
subtree and evaluate
get thethe right
result. cur
4.subtree
Apply and
the get
operator in the
the result.
4. Apply
currentthenode
operator
to thein left
the and
4. Apply thenode
current operator
to thein left
the and
right results;
current node to return
the left the
and
right results;
result. return the
right results; return the
result.
result.
94

Expression Evaluation
Here’s our evaluation function. We start by passing in a
pointer to the root of the tree.

(5+6)*(3-1)
1. If the current node is a
1. If the current
number, returnnode is a
its value. ptr
number, return its value.
2. Recursively evaluate the left cur
2. RecursivelyResult
subtree and evaluate= 5the
get the left
result.
subtree and get the result.
3. Recursively evaluate the right
3. RecursivelyResult
subtree and evaluate= 6the
get the right
result. cur
subtree and get the result.
4. Apply the operator in the
4. Apply thenode
current operator
to thein left
the and
current node toreturn
right results; the lefttheand
right results; return the
result. 5+6 = 11
result.
Expression Evaluation
Here’s our evaluation function. We start by passing in a
pointer to the root of the tree.

(5+6)*(3-1)
1. If the current node is a
1. If the current
number, returnnode is a
its value. ptr
number, return its value.
2. Recursively evaluate the left cur
2. RecursivelyResult
evaluate
subtree Result
and = 3the
get=the left
result.
11
subtree and get the result.
3. Recursively evaluate the right
3. Recursively
subtree andResult
evaluate= 1the
get the right
result.
subtree and get the result.
4. Apply the operator in the
4. Apply thenode
current operator
to thein left
the and
current node toreturn
right results; the lefttheand
right results; return the
result. 3-1 = 2
result.
Expression Evaluation
Here’s our evaluation function. We start by passing in a
pointer to the root of the tree.

The result is 22. (5+6)*(3-1)


1. If the current node is a ptr
number, return its value.
cur
2. Recursively evaluate the left
Result = 11
subtree and get the result.
3. Recursively evaluate the right
Result
subtree and = 2 result.
get the
4. Apply the operator in the
current node to the left and
right results; return the 11*2=22
3-1 =2
result.
Expression Evaluation
Here’s our evaluation function. We start by passing in a
pointer to the root of the tree.

1. If the current node is a Question: Which other


number, return its value. algorithm does this remind
2. Recursively evaluate the left you of?
subtree and get the result.
3. Recursively evaluate the right
subtree and get the result.
4. Apply the operator in the
current node to the left and
right results; return the
result.
Some Questions
Which data structure is suitable to represent hierarchical
relationship between elements?

a) Deque
b) Priority Queue
c) Tree
d) All the above

Answer
c
Solve This
The depth of a complete binary tree with n nodes is
given by

a) D = n log n
b) D = log n +1
c) D = log n

d) D = n log n +1

Answer
b
Answer This
Which of the following is a pre-order traversal?

a) Left subtree→ Root→ Right subtree


b) Left subtree→ Right subtree→ Root
c) Root→ Left subtree→ Right subtree
d) Right subtree→ Root→ Left subtree

Answer
c
One More
If node N is a terminal node in a binary tree then its .........

a) Right tree is empty


b) Root node is empty
c) Left tree is empty
d) Both left & right sub trees are
empty

Answer
d
Binary Search Tree
A binary tree T is termed as a Binary Search Tree(BST), if each node n
of T satisfies the following properties:
• The value at n is greater than every value on the left subtree of n,
and
• The value at n is less than or equal to every value on the right
subtree of n.

Example: Left Subtree 50 Right


of 50 Subtree of 50

Left 30 70 Right
Subtree Subtree of 70
of 30
Left 20 40 60 80
Subtree Left
of 20 Right
10 Subtree of 30 Subtree of 70
Operations on a Binary Search Tree
Here’s what we can do to a BST:

• Determine if the binary search tree is empty


• Search the binary search tree for a value
• Insert an item in the binary search tree
• Delete an item from the binary search tree
• Find the height of the binary search tree
• Find the number of nodes and leaves in the
binary search tree
• Traverse the binary search tree
• Free the memory used by the binary search tree
BST
Create a binary search tree using the
following data elements: 45, 39, 56, 12, 34,
78, 32, 10, 89, 54, 67, 81
BST
Searching a BST
Input: A value V to search for
Output: TRUE if found, FALSE otherwise

Start at the root of the tree


Keep going until we hit the NULL pointer
If V is equal to current node’s value, then found!
If V is less than current node’s value, go left
If V is greater than current node’s value, go right
If we hit a NULL pointer, not found. “Larry”

Gary
Gary==
<== Larry??
> Fran??
Larry??
Fran??
Fran??
Gary?? “Fran” “Ronda”
NULL NULL

Let’s search for “Barry” “Gary”


Gary. NULL NULL NULL NULL
Searching a BST
Start at the root of the tree
Keep going until we hit the NULL pointer
If V is equal to current node’s value, then found!
If V is less than current node’s value, go left
If V is greater than current node’s value, go right
If we hit a NULL pointer, not found.

Show how to search for:


1. Khang
2. Dale
3. Sam
Searching a BST
Here are two different BST search algorithms, one
recursive and one iterative:

bool Search(int V,Node *ptr)


bool Search(int V, Node *ptr) {
{ while (ptr != NULL)
if (ptr == NULL) {
return(false); // nope if (V == ptr->value)
else if (V == ptr->value) return(true);
return(true); // found!!! else if (V < ptr->value)
else if (V < ptr->value) ptr = ptr->left;
return(Search(V,ptr->left)); else
else ptr = ptr->right;
return(Search(V,ptr->right)); }
} return(false); // nope
}

Let’s trace through the recursive version…


Recursive BST Search
Lets search for 14.

pRoot

14 == 13??
< 17??
13??
17??
14?? ptr-> 13

bool Search(int V, Node *ptr)


bool Search(int V, Node *ptr)
{
7 ptr-> 17
{ if (ptr == NULL)
boolif Search(int
(ptr == NULL) V, Node
// *ptr) NULL
return(false); nope true
{ else return(false); // nope
if (V == ptr->value)
if (ptr
else if ==
(V NULL)
== ptr->value)
return(true); // found!!! 3 ptr-> 14 19
return(false);
return(true); //
//
else if (V < ptr->value) nope
found!!! NULL NULL NULL NULL NULL NULL
else
else if
if (V
(V ==
< ptr->value)
ptr->value)
return(Search(V,ptr->left));
return(true); // found!!!
return(Search(V,ptr->left));
else void main(void)
else
else if (V < ptr->value)
return(Search(V,ptr->right));
} return(Search(V,ptr->left));
return(Search(V,ptr->right)); {
} else bool bFnd;
return(Search(V,ptr->right)); bFnd = Search(14,pRoot);
} }
Recursive BST Search
Lets search for 14.

pRoot

ptr-> 13
true
bool Search(int V, Node *ptr)
7 ptr-> 17
{
boolif Search(int V, Node *ptr)
(ptr == NULL) NULL
true
{ return(false); // nope
if (ptr
else if ==
(V NULL)
== ptr->value)
3 14 19
return(false);
return(true); // // found!!!
nope NULL NULL NULL NULL NULL NULL
else
else if
if (V
(V == ptr->value)
< ptr->value)
return(true); true
// found!!!
return(Search(V,ptr->left));
void main(void)
else
else if (V < ptr->value)
return(Search(V,ptr->left));
return(Search(V,ptr->right)); {
} else bool bFnd;
return(Search(V,ptr->right)); bFnd = Search(14,pRoot);
} }
Recursive BST Search
Lets search for 14.

pRoot true
ptr-> 13
true

7 17
bool Search(int V, Node *ptr) NULL
true
{
if (ptr == NULL)
3 14 19
return(false); // nope NULL NULL NULL NULL NULL NULL
else if (V == ptr->value)
return(true); // found!!!
int main(void)
else if (V < ptr->value)
return(Search(V,ptr->left)); {
else bool bFnd;
true
return(Search(V,ptr->right)); true
bFnd = Search(14,pRoot);
} }
112

Big Oh of BST Search


Question:
In the average BST with N values, 50% eliminated!
50%
how many steps are required to eliminated!
find our value?
50%
Right! log2(N) steps eliminated!
50%
eliminated!
Question:
In the worst case BST with
N values, how many steps are
required find our value?

Right! N steps
Inserting A New Value Into A BST
To insert a new node in our BST, we must place the
new node so that the resulting tree is still a valid BST!

Where would the following


new values go?
Carly
Ken
Alice
Ken

Alice Carly
Pseudo Code

Node* Insert(Node* tree, int val) {


if (tree == NULL) {
tree = new Node(); // Allocate memory for new node
tree->data = val; // Set the data of the node to val
tree->left = NULL; // Initialize left child to NULL
tree->right = NULL; // Initialize right child to NULL
}
else if (val < tree->data) {
tree->left = Insert(tree->left, val); // Recur on the left subtree
}
else {
tree->right = Insert(tree->right, val); // Recur on the right subtree
}
return tree;
}
Inserting nodes with values 12 and 55 in the given binary search tree
Big Oh of BST Insertion
So, what’s the big-oh of BST Insertion?
Right! It’s also O(log2n)

Why? Because we have to first use a binary search to find


where to insert our node and binary search is O(log2n).

Once we’ve found the right spot, we can insert our new
node in O(1) time.
Finding Min & Max of a BST
How do we find the minimum and maximum values in a BST?
The minimum value is located at the left-most node.
The maximum value is located at the right-most node.

int GetMin(node *pRoot) int GetMax(node *pRoot)


{ {
if (pRoot == NULL) if (pRoot == NULL)
return(-1); // empty return(-1); // empty

while (pRoot->left != NULL) while (pRoot->right != NULL)


pRoot = pRoot->left; pRoot = pRoot->right;

return(pRoot->value); return(pRoot->value);
} }

Question: What’s the big-oh to find the minimum or


maximum element?
Finding Min & Max of a BST
And here are recursive versions for you…

int GetMin(node *pRoot) int GetMax(node *pRoot)


{ {
if (pRoot == NULL) if (pRoot == NULL)
return(-1); // empty return(-1); // empty

if (pRoot->left == NULL) if (pRoot->right == NULL)


return(pRoot->value); return(pRoot->value);

return(GetMin(pRoot->left)); return(GetMax(pRoot->right));
} }
Printing a BST In Alphabetical Order

Can anyone guess root


cur “jane”
what algorithm we
use to print out a
BST in alphabetical cur “danny” cur “waa”
order? NULL NULL

“bill” “frank”
cur NULL NULL NULL NULL cur
void InOrder(Node *cur)
{ Big-oh Alert!
if (cur == NULL) // if empty, return… Output:
return; the big-Oh of printing
So what’s
bill
all the items in the
InOrder(cur->left); tree?
// Process nodes in left sub-tree.
danny
cout << cur->value; // Process the current node. frank
Right! O(n) since we have to visit jane
InOrder(cur->right); // Process nodes in right sub-tree.
} and print all n items. waa
Freeing The Whole Tree
When we are done with our BST, we have to free every
node in the tree, one at a time.

Question: Can anyone think of an algorithm for this?

void FreeTree(Node *cur)


{
if (cur == NULL) // if empty, return…
return;
FreeTree(cur->left); // Delete nodes in left sub-tree.
FreeTree (cur->right); // Delete nodes in right sub-tree.

delete cur; // Free the current node


}
Freeing The Whole Tree
cur-> “Larry”

cur-> “Fran” “Ronda”


cur = NULL NULL NULL

void FreeTree(Node *cur)


cur-> “Barry” “Gabby”
{ FreeTree(Node *cur)
void
NULL NULL NULL NULL
void if (cur == NULL)
{ FreeTree(Node *cur)
if (curreturn;
{ FreeTree(Node
void == NULL)
*cur)
{ if (cur return;
== NULL)
FreeTree(cur->left);
return;
if (curFreeTree(cur->left);
== NULL)
return;FreeTree (cur-> right);
FreeTree(cur->left);
FreeTree (cur-> right);
FreeTree(cur->left);
delete(cur->
FreeTree cur; right);
}
delete cur; right);
FreeTree (cur->
}
delete cur;
}
delete cur;
}
Freeing The Whole Tree
cur-> “Larry”

cur-> “Fran” “Ronda”


NULL NULL

cur-> “Barry” “Gabby”


void FreeTree(Node *cur)
NULL NULL NULL NULL
void{ FreeTree(Node *cur)
void if (cur == NULL)
{ FreeTree(Node *cur)
{ if (curreturn;
== NULL)
return;
if (curFreeTree(cur->left);
== NULL)
return;
FreeTree(cur->left);
FreeTree (cur-> right);
FreeTree(cur->left);
FreeTree (cur-> right);
delete(cur->
FreeTree cur; right);
}
delete cur;
}
delete cur;
}
Freeing The Whole Tree
cur-> “Larry”

cur-> “Fran” “Ronda”


NULL NULL

cur-> “Gabby”
void FreeTree(Node *cur) NULL NULL
void
{ FreeTree(Node *cur)
{ FreeTree(Node
void if (cur == NULL)
*cur)
{ if (curreturn;
== NULL)
if (curreturn;
== NULL)
FreeTree(cur->left);
return;
FreeTree(cur->left);
FreeTree (cur-> right);
FreeTree(cur->left);
FreeTree (cur-> right);
delete(cur->
FreeTree cur; right);
delete
} cur;
}
delete cur;
}
Freeing The Whole Tree
cur-> “Larry”

cur-> “Fran” “Ronda”


NULL NULL

void FreeTree(Node *cur)


{ FreeTree(Node *cur)
void
{ if (cur == NULL) Big-oh Alert!
if (curreturn;
== NULL)
return;
And so on…
FreeTree(cur->left); So what’s the big-Oh of freeing
FreeTree(cur->left);
FreeTree (cur-> right); all the items in the tree?
FreeTree (cur-> right);
delete cur;
}
It’s still O(n) since we have
delete cur;
} to visit all n items.
Deleting a Node from a Binary Search Tree
ByNow,
simplylet’s
moving an arbitrary
learn how to node into
delete
Darren’s slot, we violate our Binary
an item from a BST.
Search Tree ordering requirement! It’s not as easy as
Carey is NOT less than Arissa! you might think!
Let’s say we want to delete
Next we’ll see how to do this
Darren from our tree…
properly….

Now how do I re-link the


nodes back together?

Can I just move Arissa


X
into Darren’s old slot?
Arissa
Hmm.. It seems OK, but is our tree
still a valid binary search tree?
Deleting a Node from a Binary Search Tree

Algorithm to delete a node from a Binary Search Tree:

Given a value V to delete from the tree:

1. Find the value V in the tree, with a slightly-modified


BST search.
- Use two pointers: a cur pointer & a parent pointer

2. If the node was found, delete it from the tree,


making sure to preserve its ordering!
- There are three cases, so be careful!
BST Deletion: Step #1
Step 1: Searching for value V
Let’s delete Casey
1. parent = NULL
2. cur = root Casey< <Darren?
Casey
Casey < Carey?
Mel?
3. While (cur != NULL)
A. If (V == cur->value) then we’re done.
B. If (V < cur->value) parentparent
cur
parent = cur;
cur = cur->left; parent
cur
C. Else if (V > cur->value)
parent = cur; parent
cur
cur = cur->right;
cur
Now cur points at the node we want to delete,
parent
and parent points to the nodeNULL
above it!
BST Deletion: Step #2
Once we’ve found our target node, we have to delete it.
There are 3 cases.

Case 1: Case 2: Case 3:


Node is a leaf. Node has one child Node has two
children.
parent parent
cur

parent

cur
Example- Case 1: Node is a leaf.
Example- Case 2: Node has one child
Example- Case 3: Node has two children.
in-order predecessor (largest value in the left sub-tree)

Note: Deleting a Node with Two Children To handle case 3, replace the
node’s value with its in-order predecessor (largest value in the left sub-tree)
or in-order successor (smallest value in the right sub-tree).
Example- Case 3: Node has two children.
in-order successor (smallest value in the right sub-tree)
Code
#include <stdio.h>
#include <stdlib.h>

// Define the structure for a node in the BST


struct Node {
int data;
struct Node *left, *right;
};
// Function to create a new node
struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->left = newNode->right = NULL;
return newNode;
}

// Function to insert a node into the BST


struct Node* insert(struct Node* root, int data) {
if (root == NULL) {
return createNode(data);
}
if (data < root->data) {
root->left = insert(root->left, data);
} else if (data > root->data) {
root->right = insert(root->right, data);
}
return root;
}
// Function to find the minimum value node in a BST

struct Node* findMin(struct Node* root) {


while (root->left != NULL) {
root = root->left;
}
return root;
}
// Function to delete a node from the BST
struct Node* deleteNode(struct Node* root, int key)
{
if (root == NULL) {
return root;
}

// Traverse the tree to find the node to delete


if (key < root->data) {
root->left = deleteNode(root->left, key);
} else if (key > root->data) {
root->right = deleteNode(root->right, key);
} else {
// Node to be deleted is found
// Case 1: Node is a leaf
if (root->left == NULL && root->right == NULL)
{
free(root);
return NULL;
}
// Case 2: Node has one child
if (root->left == NULL) {
struct Node* temp = root->right;
free(root);
return temp;
}
else if (root->right == NULL) {
struct Node* temp = root->left;
free(root);
return temp;
}

// Case 3: Node has two children


struct Node* temp = findMin(root->right); // Find the in-order successor
root->data = temp->data; // Replace data
root->right = deleteNode(root->right, temp->data); // Delete in-order successor
}
return root;
}
Deletion Exercise
Deletion Exercise
k Explain how you would go about
deleting node k.
f n Explain how you would go about
deleting node e.
b h l p
Explain how you would go
a d g j m o q about deleting node i.

c e i

igloo

infer
AVL
TREES
Balanced binary tree
✓ The disadvantage of a binary search tree is that its height can be as
large as N-1

✓ This means that the time needed to perform insertion and deletion
and many other operations can be O(N) in the worst case

✓ We want a tree with small height

✓ A binary tree with N node has height at least (log N)


✓ Thus, our goal is to keep the height of a binary search tree O(log N)

✓ Such trees are called balanced binary search trees. Examples are
AVL tree, red-black tree.
Balanced Search Trees
Question:
What happens if we insert the following values into a
binary search tree?

5, 10, 7, 9, 8, 20, 18, 17, 16, 15, 14, 13, 12, 11


Right! We get an unbalanced tree!

Question:
What is the approximate big-oh cost of searching
for a value in this tree?

O(N)…
Balanced Search Trees
In real life, BSTs often
end up looking just like
our example, especially
after repeated insertions
and deletions.

It’d be nice if we could


come up with an improved
BST ADT that always
maintains its balance.

This would ensure that all


insertions, searches and
deletions would be O(log n).
Balanced Search Trees
Well, guess what?

CS nerds have come to the rescue!

They’ve invented numerous improved binary search tree


ADTs like 2-3 Trees, Red-Black Trees, and AVL Trees.

These BST variations work (mostly)


just like a regular binary search tree…

but every time you add/delete a value, they automatically


shift the nodes around so the tree is balanced!
Balancing a Tree On Insertion
For example, the AVL Tree tracks the height of ALL subtrees in the BST.

J
Consider node T…

B T

R Z
3
3

Its left
And its right
subtree
has a subtree has a
height height of 3 too…
of 3…
Balancing a Tree On Insertion
For example, the AVL Tree tracks the height of ALL subtrees in the BST.

Or consider
node J… The AVL tree tracks these
subtree height values for every
J node in the tree!

B T
3

R Z And its right


subtree has a
height of 4…

Its left
subtree has a
height of 3…
Balancing a Tree On Insertion
For example, the AVL Tree tracks the height of ALL subtrees in the BST.

After an insertion/deletion, if the height of the subtrees


under any node is different by more than one level…
Then the AVL algorithm shifts thedifference
So the nodes around to maintain balance.
J between J’s two
subtrees is 2 levels! J
While the shifting looks
complex (it is ☺),Tit only
B T
takes O(log n) time! B
3

4
45

So with just a little extra


R is always
work, the tree Z
R Z
balanced and can always be
searched in log n time!
For instance,
J’s left But now its right
subtree has a subtree has a
height of 3… height of 5!
Balanced Search Trees
You don’t need to know the gory details of any of these
balanced BSTs for your final or projects.

Just remember, that balanced BSTs are


always O(log n) for insertion and deletion.

And if you’re ever in a job/internship interview


and are asked a BST question…

Always make sure to ask the interviewer


if you may assume the BST is balanced!

It could make or break your interview!


Motivation
✓ When building a binary search tree, what type of trees
would we like? Example: 3, 5, 8, 20, 18, 13, 22

3
5 13
8
5 20
13
18 3 8 18 22
20
22
Motivation
❖ Complete binary tree is hard to build when we allow
dynamic insert and remove.
➢ We want a tree that has the following properties
✓ Tree height = O(log(N))
✓ allows dynamic insert and remove with O(log(N)) time
complexity.
▪ The AVL tree is one of this kind of trees.
8
13
5 18
5 20
3 13 20
3 8 18 22 22
AVL (Adelson-Velskii and Landis) Trees
4
44
• An AVL Tree is a binary 2 3
search tree such that for 17 78
every internal node v of T, 1 2 1
the heights of the children 32 50 88
of v can differ by at most 1. 1 1
48 62

An example of an AVL tree where the


heights are shown next to the nodes
AVL (Adelson-Velskii and Landis) Trees

✓ AVL tree is a binary search tree with balance


condition
✓ To ensure depth of the tree is O(log(N))
✓ And consequently, search/insert/remove complexity
bound O(log(N))
✓ Balance condition
✓ For every node in the tree, height of left and right subtree
can differ by at most 1
Node Heights

Tree A Tree B
(AVL) (AVL)
height=2 BF=1-0=1 2
6 6
1 0 1 1
4 9 4 9
0 0 0 0 0
1 5 1 5 8

height of node = h
balance factor = hleft-hright
empty height = -1
Node Heights after Insert 7

Tree A (AVL) Tree B (not AVL) balance factor


2 3 1-(-1) = 2
6 6
1 1 1 2
4 9 4 9
0 0 0 0 0 1 -1
1 5 7 1 5 8
0
7
height of node = h
balance factor = hleft-hright
empty height = -1
Insert and Rotation in AVL Trees
✓ Insert operation may cause balance factor to become 2 or –2
for some node
✓ only nodes on the path from insertion point to root node
have possibly changed in height

✓ So after the Insert, go back up to the root node by node,


updating heights

✓ If a new balance factor (the difference hleft-hright) is 2 or


–2, adjust tree by rotation around the node
Balanced and unbalanced BST
1 4
2 2 5
3
1 3
4
4 Is this “balanced”?
5
2 6 6
1 3 5 7 7
AVL Trees 156
Perfect Balance
• Want a complete tree after every operation
› tree is full except possibly in the lower right
• This is expensive
› For example, insert 2 in the tree on the left and
then rebuild as a complete tree
6 5
Insert 2 &
4 9 complete tree 2 8

1 5 8 1 4 6 9
AVL Trees 157
AVL - Good but not Perfect
Balance
• AVL trees are height-balanced binary
search trees
• Balance factor of a node
› height(left subtree) - height(right subtree)
• An AVL tree has balance factor
calculated at every node
› For every node, heights of left and right
subtree can differ by no more than 1
› Store current heights in each node
AVL Trees 158
Insert and Rotation in AVL
Trees
• Insert operation may cause balance factor
to become 2 or –2 for some node
› only nodes on the path from insertion point to
root node have possibly changed in height
› So after the Insert, go back up to the root
node by node, updating heights
› If a new balance factor (the difference hleft-
hright) is 2 or –2, adjust tree by rotation around
the node
AVL Trees 159
Rotation in an AVL Tree
-LL rotation: The new node is inserted in the left sub-
tree of the left sub-tree of the critical node.
-RR rotation: The new node is inserted in the right
sub-tree of the right sub-tree of the critical node.
-LR rotation: The new node is inserted in the right
sub-tree of the left sub-tree of the critical node.
-RL rotation: The new node is inserted in the left sub-
tree of the right sub-tree of the critical node.
Single Rotation in an AVL
Tree
2 2
6 6
1 2 1 1
4 9 4 8
0 0 1 0 0 0 0
1 5 8 1 5 7 9
0
7

AVL Trees 161


Insertions in AVL Trees
Let the node that needs rebalancing be .

There are 4 cases:


Outside Cases (require single rotation) :
1. Insertion into left subtree of left child of .
2. Insertion into right subtree of right child of .
Inside Cases (require double rotation) :
3. Insertion into right subtree of left child of .
4. Insertion into left subtree of right child of .
The rebalancing is performed through four
separate rotation algorithms.
AVL Trees 162
AVL Insertion: Outside Case
Consider a valid
AVL subtree
j

k h

h
h
Z
X Y
AVL Trees 163
AVL Insertion: Outside Case
j Inserting into X
destroys the AVL
property at node j
k h

h+1 h Z
Y
X
AVL Trees 164
AVL Insertion: Outside Case
j Do a “right rotation”

k h

h+1 h Z
Y
X
AVL Trees 165
Single right rotation
j Do a “right rotation”

k h

h+1 h Z
Y
X
AVL Trees 166
Outside Case Completed
“Right rotation” done!
k (“Left rotation” is mirror
symmetric)

h+1
j
h h

X Y Z
AVL property has been restored!
AVL Trees 167
AVL Insertion: Inside Case
Consider a valid
AVL subtree
j

k h

h h Z
X Y
AVL Trees 168
AVL Insertion: Inside Case
Inserting into Y
destroys the j Does “right rotation”
restore balance?
AVL property
at node j
k h

h h+1 Z
X
Y
AVL Trees 169
AVL Insertion: Inside Case
“Right rotation”
k does not restore
balance… now k is
h j out of balance

X h+1
h

Z
Y
AVL Trees 170
AVL Insertion: Inside Case
Consider the structure
of subtree Y… j
k h

h h+1 Z
X
Y
AVL Trees 171
AVL Insertion: Inside Case
Y = node i and
subtrees V and W
j
k h

h
i h+1 Z
X h or h-1

V W
AVL Trees 172
AVL Insertion: Inside Case
j We will do a left-right
“double rotation” . . .

k
i Z
X
V W
AVL Trees 173
Double rotation : first rotation
j left rotation complete

i
k Z
W
X V
AVL Trees 174
Double rotation : second
rotation
j Now do a right rotation

i
k Z
W
X V
AVL Trees 175
Double rotation : second
rotation
right rotation complete

Balance has been


i restored

k j
h h
h or h-1

X V W Z
AVL Trees 176
Implementation

balance (1,0,-1)
key
left right

No need to keep the height; just the difference in height,


i.e. the balance factor; this has to be modified on the path of
insertion even if you don’t perform rotations
Once you have performed a rotation (single or double) you won’t
need to go back up the tree

AVL Trees 177


Insertion in AVL Trees
• Insert at the leaf (as for all BST)
› only nodes on the path from insertion point to
root node have possibly changed in height
› So after the Insert, go back up to the root
node by node, updating heights
› If a new balance factor (the difference hleft-
hright) is 2 or –2, adjust tree by rotation around
the node

AVL Trees 178


Example of Insertions in an
AVL Tree
2
20 Insert 5, 40
0 1
10 30
0 0
25 35

AVL Trees 179


Example of Insertions in an
AVL Tree
2
3
20 20
1 1 1 2
10 30 10 30
0 0 0 1
0 0
5 25 35 5 25 35
0
40
Now Insert 45

AVL Trees 180


Single rotation (outside case)
3
3
20 20
1 2 1 2
10 30 10 30
0 0 2
0 0
5 25 35 5 25 40 1
0 0
35 45
Imbalance 1 40

0 45
Now Insert 34

AVL Trees 181


Double rotation (inside case)
3
3
20 20
1 3 1 2
10 30 10 35
0 0 2
0 1
5 Imbalance 25 40 5 30 40 1
0
1 35 45 0 0 25 34 45
Insertion of 34 0
34

AVL Trees 182


AVL Tree Deletion
• Similar but more complex than insertion
› Rotations and double rotations needed to
rebalance
› Imbalance may propagate upward so that
many rotations may be needed.

AVL Trees 183


Pros and Cons of AVL Trees
Arguments for AVL trees:
1. Search is O(log N) since AVL trees are always balanced.
2. Insertion and deletions are also O(logn)
3. The height balancing adds no more than a constant factor to the
speed of insertion.

Arguments against using AVL trees:


1. Difficult to program & debug; more space for balance factor.
2. Asymptotically faster but rebalancing costs time.
3. Most large searches are done in database systems on disk and use
other structures (e.g. B-trees).

AVL Trees 184


AVL Tree Example:
• Insert 14, 17, 11, 7, 53, 4, 13 into an empty AVL tree

14

11 17

7 53

4
AVL Tree Example:
• Insert 14, 17, 11, 7, 53, 4, 13 into an empty AVL tree

14

7 17

4 11 53

13
AVL Tree Example:
• Now insert 12

14

7 17

4 11 53

13

12
AVL Tree Example:
• Now insert 12

14

7 17

4 11 53

12

13
AVL Tree Example:
• Now the AVL tree is balanced.

14

7 17

4 12 53

11 13
AVL Tree Example:
• Now insert 8

14

7 17

4 12 53

11 13

8
AVL Tree Example:
• Now insert 8

14

7 17

4 11 53

8 12

13
AVL Tree Example:
• Now the AVL tree is balanced.

14

11 17

7 12 53

4 8 13
AVL Tree Example:
• Now remove 53

14

11 17

7 12 53

4 8 13
AVL Tree Example:
• Now remove 53, unbalanced

14

11 17

7 12

4 8 13
AVL Tree Example:
• Balanced! Remove 11
11

7 14

4 8 12 17

13
AVL Tree Example:
• Remove 11, replace it with the largest in its left branch
8

7 14

4 12 17

13
AVL Tree Example:
• Remove 8, unbalanced
7

4 14

12 17

13
AVL Tree Example:
• Remove 8, unbalanced
7

4 12

14

13 17
AVL Tree Example:
• Balanced!!
12

7 14

4 13 17
Exercises
• Build an AVL tree with the following values:
15, 20, 24, 10, 13, 7, 30, 36, 25
15, 20, 24, 10, 13, 7, 30, 36, 25
20

15
15 24
20
10
24

13

20 20

13 24 15 24

10 15 13

10
15, 20, 24, 10, 13, 7, 30, 36, 25
20
13

13 24 10 20

10 15 7 15 24

7 30

13 36

10 20

7 15 30

24 36
15, 20, 24, 10, 13, 7, 30, 36, 25
13 13

10 20 10 20

7 15 30 7 15 24

24 36 30

25 13 25 36

10 24

7 20 30

15 25 36
Remove 24 and 20 from the AVL tree.

13 13

10 24 10 20

7 20 30 7 15 30

15 25 36 25 36

13 13

10 30 10 15

7 15 36 7 30

25 25 36
Extended Example
Insert 3,2,1,4,5,6,7, 16,15,14
3 2
3
3

2 1
Fig 1 2 3
Fig 4
Fig 2
2 1 2

Fig 3
1
1 3
3
Fig 5 Fig 6 4
4
5
2
2

1
1
4 4
3 5
3 5
Fig 8
Fig 7 6
4
4
2
2 5
5
1 3 6
1 3 6
4
Fig 10 7
Fig 9
2
6
1 3 7

5 Fig 11
4 4

2 2
6 6
1 3 7 1 3 7

5 16 5 16
Fig 12
Fig 13
15
4

2
6
1 3 15
5
16
Fig 14 7
4 4

2 2 7
6
15 1 3 15
1 3 5 6
16
7 5 14 16
Fig 15
14 Fig 16

Deletions can be done with similar rotations


Thank You

Any Questions???

You might also like