Trees-Data-Structure 17

Download as pdf or txt
Download as pdf or txt
You are on page 1of 62

Data Structure and Algorithms

Topperworld.in

BINARY TREES

A data structure is said to be linear if its elements form a sequence or a


linear list. Previous linear data structures that we have studied like an
array, stacks, queues and linked lists organize data in linear order. A data
structure is said to be non linear if its elements form a hierarchical
classification where, data items appear at various levels.

Trees and Graphs are widely used non-linear data structures. Tree and
graph structures represents hierarchial relationship between individual
data elements. Graphs are nothing but trees with certain restrictions
removed.

➔TREES:

A tree is hierarchical collection of nodes. One of the nodes, known as the


root, is at the top of the hierarchy. Each node can have at most one link
coming into it. The node where the link originates is called the parent node.
The root node has no parent. The links leaving a node (any number of links
are allowed) point to child nodes. Trees are recursive structures. Each child
node is itself the root of a subtree. At the bottom of the tree are leaf nodes,
which have no children.

Trees represent a special case of more general structures known as


graphs. In a graph, there is no restrictions on the number of links that
can enter or leave a node, and cycles may be present in the graph. The
figure shows a tree and a non-tree.

a
a

b c b c

d e f d e

A Tree Not a Tree

Figure 5.1.1 A Tree and a not a tree

In a tree data structure, there is no distinction between the various children


of a node i.e., none is the "first child" or "last child". A tree in which such
distinctions are made is called an ordered tree, and data structures built

©Topperworld
Data Structure and Algorithms

on them are called ordered tree data structures. Ordered trees are by
far the commonest form of tree data structure.

➔BINARY TREE:

In general, tree nodes can have any number of children. In a binary tree,
each node can have at most two children. A binary tree is either empty or
consists of a node called the root together with two binary trees called the
left subtree and the right subtree.

A tree with no nodes is called as a null tree. A binary tree is shown in figure

left child B C right child

right subtree
left subtree D E F G

H I

Figure 5.2.1. Binary Tree

Binary trees are easy to implement because they have a small, fixed
number of child links. Because of this characteristic, binary trees are the
a
a

b c b c

d e f d e

A Tree Not a Tree

Figure 5.1.1 A Tree and a not a tree

In a tree data structure, there is no distinction between the various children


of a node i.e., none is the "first child" or "last child". A tree in which such
distinctions are made is called an ordered tree, and data structures built
on them are called ordered tree data structures. Ordered trees are by
far the commonest form of tree data structure.

©Topperworld
Data Structure and Algorithms

Tree Terminology:

Leaf node

A node with no children is called a leaf (or external node). A node


which is not a leaf is called an internal node.

Path
A sequence of nodes n1, n2, . . ., nk, such that ni is the parent of ni
+ 1 for i = 1, 2,. . ., k - 1. The length of a path is 1 less than the
number of nodes on the path. Thus there is a path of length zero
from a node to itself.

For the tree shown in figure, the path between A and I is A, B, D, I.

Siblings

The children of the same parent are called siblings.

For the tree shown in figure, F and G are the siblings of the parent
node C and H and I are the siblings of the parent node D.

Ancestor and Descendent

If there is a path from node A to node B, then A is called an ancestor


of B and B is called a descendent of A.

Subtree

Any node of a tree, with all of its descendants is a subtree.

Level
The level of the node refers to its distance from the root. The root of
the tree has level O, and the level of any other node in the tree is
one more than the level of its parent. For example, in the binary tree
of Figure 5.2.1 node F is at level 2 and node H is at level 3. The
maximum number of nodes at any level is 2n.

©Topperworld
Data Structure and Algorithms

a
a

b c b c

d e f d e

A Tree Not a Tree

Figure 5.1.1 A Tree and a not a tree

In a tree data structure, there is no distinction between the various children


of a node i.e., none is the "first child" or "last child". A tree in which such
distinctions are made is called an ordered tree, and data structures built
on them are called ordered tree data structures. Ordered trees are by
far the commonest form of tree data structure.

Assigning level numbers and Numbering of nodes for a


binary tree:

The nodes of a binary tree can be numbered in a natural way, level by level,
left to right. The nodes of a complete binary tree can be numbered so that
the root is assigned the number 1, a left child is assigned twice the number
assigned its parent, and a right child is assigned one more than twice the
number assigned its parent. For example, see Figure .

Figure Level by level numbering of binary tree

Properties of binary trees:

Some of the important properties of a binary tree are as follows:

1. If h = height of a binary tree, then

a. Maximum number of leaves = 2h

©Topperworld
Data Structure and Algorithms

b. Maximum number of nodes = 2h + 1 – 1

2. If a binary tree contains m nodes at level l, it contains at most 2m


nodes at level l + 1.

3. Since a binary tree can contain at most one node at level 0 (the root),
it can contain at most 2l node at level l.

4. The total number of edges in a full binary tree with n node is n - 1.

➔ Strictly Binary tree:

If every non-leaf node in a binary tree has nonempty left and right
subtrees, the tree is termed as strictly binary tree. Thus the tree of figure
is strictly binary. A strictly binary tree with n leaves always contains 2n - 1
nodes.

➔ Full Binary tree:

A full binary tree of height h has all its leaves at level h. Alternatively; All
non leaf nodes of a full binary tree have two children, and the leaf nodes
have no children.

A full binary tree with height h has 2h + 1 - 1 nodes. A full binary tree of
height h is a strictly binary tree all of whose leaves are at level h. Figure
5.2.3(d) illustrates the full binary tree containing 15 nodes and of height 3.
A full binary tree of height h contains 2h leaves and, 2h - 1 non-leaf nodes.
h
Thus by induction, total number of nodes (tn) = ∑ 2 l = 2 h+1−1.

l =0

For example, a full binary tree of height 3 contains 23+1 – 1 = 15 nodes.

©Topperworld
Data Structure and Algorithms

➔Complete Binary tree:

A binary tree with n nodes is said to be complete if it contains all


the first n nodes of the above numbering scheme. Figure shows
examples of complete and incomplete binary trees.

A complete binary tree of height h looks like a full binary tree down
to level h-1, and the level h is filled from left to right.

A complete binary tree with n leaves that is not strictly binary has
2n nodes. For example, the tree of Figure is a complete binary tree
having 5 leaves and 10 nodes.

1 1 1

2 3 2 3 2

4 5 6 4 5 7 4

Complete Binary Tree Not Complete and not Not Complete and not
but not strict strict strict
(a) (b) (c)

Figure: Examples of complete and incomplete binary trees

©Topperworld
Data Structure and Algorithms

Internal and external nodes:

We define two terms: Internal nodes and external nodes. An internal node
is a tree node having at least one–key and possibly some children. It is
some times convenient to have another types of nodes, called an external
node, and pretend that all null child links point to such a node. An external
node doesn’t exist, but serves as a conceptual place holder for nodes to be
inserted.

We draw internal nodes using circles, with letters as labels. External nodes
are denoted by squares. The square node version is sometimes called an
extended binary tree. A binary tree with n internal nodes has n+1 external
nodes. Figure shows a sample tree illustrating both internal and external
nodes.

a d Internal Nodes: a, b, c, d
External Nodes: 1, 2, 3, 4, 5

1 b 4 5

2 3

Figure: Internal and external nodes

Data Structures for Binary Trees:

1. Arrays; especially suited for complete and full binary trees.


2. Pointer-based.

Array-based Implementation:

Binary trees can also be stored in arrays, and if the tree is a complete
binary tree, this method wastes no space. In this compact arrangement, if
a node has an index i, its children are found at indices 2i+1 and 2i+2, while
its parent (if any) is found at index floor((i-1)/2) (assuming the root of the
tree stored in the array at an index zero).
This method benefits from more compact storage and better locality of
reference, particularly during a preorder traversal. However, it requires
contiguous memory, expensive to grow and wastes space proportional to
2h - n for a tree of height h with n nodes.

©Topperworld
Data Structure and Algorithms

0 1 2 3 4 5 6

Linked Representation (Pointer based):

Array representation is good for complete binary tree, but it is wasteful for
many other binary trees. The representation suffers from insertion and
deletion of node from the middle of the tree, as it requires the moment of
potentially many nodes to reflect the change in level number of this node.
To overcome this difficulty we represent the binary tree in linked
representation.
In linked representation each node in a binary has three fields, the left child
field denoted as LeftChild, data field denoted as data and the right child
field denoted as RightChild. If any sub-tree is empty then the
corresponding pointer’s LeftChild and RightChild will store a NULL value.
If the tree itself is empty the root pointer will store a NULL value.

The advantage of using linked representation of binary tree is that:

• Insertion and deletion involve no data movement and no


movement of nodes except the rearrangement of pointers.

The disadvantages of linked representation of binary tree includes:

• Given a node structure, it is difficult to determine its parent node.

• Memory spaces are wasted for storing NULL pointers for the
nodes, which have no subtrees.

The structure definition, node representation empty binary tree is shown in


figure and the linked representation of binary tree using this node structure
is given in figure.

©Topperworld
Data Structure and Algorithms

A root

B C
A

D E F G
B C
H I

D X E X X F X X G X

X H X X I X

Figure: Linked representation for the binary tree

Binary Tree Traversal Techniques:

A tree traversal is a method of visiting every node in the tree. By visit, we


mean that some type of operation is performed. For example, you may
wish to print the contents of the nodes.

There are four common ways to traverse a binary tree:

1. Preorder
2. Inorder
3. Postorder
4. Level order

In the first three traversal methods, the left subtree of a node is traversed
before the right subtree. The difference among them comes from the
difference in the time at which a root node is visited.

Recursive Traversal Algorithms:

Inorder Traversal:

In the case of inorder traversal, the root of each subtree is visited after its
left subtree has been traversed but before the traversal of its right subtree
begins. The steps for traversing a binary tree in inorder traversal are:

1. Visit the left subtree, using inorder.


2. Visit the root.

©Topperworld
Data Structure and Algorithms

3. Visit the right subtree, using inorder.

The algorithm for inorder traversal is as follows:

void inorder(node *root)


{
if(root != NULL)
{
inorder(root->lchild);
print root -> data;
inorder(root->rchild);
}
}

Preorder Traversal:

In a preorder traversal, each root node is visited before its left and right
subtrees are traversed. Preorder search is also called backtracking. The
steps for traversing a binary tree in preorder traversal are:

1. Visit the root.


2. Visit the left subtree, using preorder.
3. Visit the right subtree, using preorder.

The algorithm for preorder traversal is as follows:

void preorder(node *root)


{
if( root != NULL )
{
print root -> data;
preorder (root -> lchild);
preorder (root -> rchild);
}
}

©Topperworld
Data Structure and Algorithms

Postorder Traversal:

In a postorder traversal, each root is visited after its left and right subtrees
have been traversed. The steps for traversing a binary tree in postorder
traversal are:
1. Visit the left subtree, using postorder.
2. Visit the right subtree, using postorder
3. Visit the root.

The algorithm for postorder traversal is as follows:

void postorder(node *root)


{
if( root != NULL )
{
postorder (root -> lchild);
postorder (root -> rchild);
print (root -> data);
}
}

Level order Traversal:

In a level order traversal, the nodes are visited level by level starting from
the root, and going from left to right. The level order traversal requires a
queue data structure. So, it is not possible to develop a recursive procedure
to traverse the binary tree in level order. This is nothing but a breadth first
search technique.
The algorithm for level order traversal is as follows:

void levelorder()
{
int j;
for(j = 0; j < ctr; j++)
{
if(tree[j] != NULL)
print tree[j] -> data;
}
}

©Topperworld
Data Structure and Algorithms

Example 1:

Traverse the following binary tree in pre, post, inorder

A • Preorder traversal yields:


A, B, D, C, E, G, F, H, I
B C

D E F
• Postorder traversal
yields:
G H I D, B, G, E, H, I, F, C, A

• Inorder traversal yields:


D, B, A, E, G, C, H, F, I

Level order traversal



yields: A, B, C, D, E, F, G,
H, I
Binary Tree Pre, Post, Inorder and level order Traversing

Example 2:

Traverse the following binary tree in pre, post, inorder and level order.

P • Preorder traversal yields:


F S
P, F, B, H, G, S, R, Y, T, W, Z

B H R Y • Postorder traversal yields:


B, G, H, F, R, W, T, Z, Y, S, P
G T Z

W
• Inorder traversal yields:
B, F, G, H, P, R, S, T, W, Y, Z

Level order traversal yields:



P, F, S, B, H, R, Y, G, T, Z, W
Binary Tree Pre, Post, Inorder and level order Traversing

©Topperworld
Data Structure and Algorithms

Example 3:
Traverse the following binary tree in pre, post, inorder and level order.

2 • Preorder
7 5 traversal yields:
2, 7, 2, 6, 5, 11,
2 6 9 5, 9, 4

5 11 4
• Postorder
travarsal yields:
2, 5, 11, 6, 7, 4,
9, 5, 2

• Inorder
travarsal yields:
2, 7, 5, 6, 11, 2,
5, 4, 9

• Level order
traversal yields: 2,
7, 5, 2, 6, 9, 5, 11, 4
Binary Tree Pre, Post, Inorder and level order Traversing

Example 4:

Traverse the following binary tree in pre, post, inorder and level order.

A • Preorder traversal yields:


B C A, B, D, G, K, H, L, M, C, E

D E • Postorder travarsal yields:


K, G, L, M, H, D, B, E, C, A
H

L M
• Inorder travarsal yields:
K, G, D, L, H, M, B, A, E, C
G
• Level order traversal yields:
K A, B, C, D, E, G, H, K, L, M
Binary Tree Pre, Post, Inorder and level order Traversing

©Topperworld
Data Structure and Algorithms

Building Binary Tree from Traversal Pairs:


Sometimes it is required to construct a binary tree if its traversals are
known. From a single traversal it is not possible to construct unique binary
tree. However any of the two traversals are given then the corresponding
tree can be drawn uniquely:

• Inorder and preorder


• Inorder and postorder
• Inorder and level order

The basic principle for formulation is as follows:

If the preorder traversal is given, then the first node is the root node. If
the postorder traversal is given then the last node is the root node. Once
the root node is identified, all the nodes in the left sub-trees and right sub-
trees of the root node can be identified using inorder.

Same technique can be applied repeatedly to form sub-trees.

It can be noted that, for the purpose mentioned, two traversal are essential
out of which one should be inorder traversal and another preorder or
postorder; alternatively, given preorder and postorder traversals, binary
tree cannot be obtained uniquely.

Example 1:

Construct a binary tree from a given preorder and inorder sequence:

Preorder: A B D G C E H I F
Inorder: D G B A H E I C F

Solution:

From Preorder sequence A B D G C E H I F, the root is: A

From Inorder sequence D G B A H E I C F, we get the left and right sub


trees:

Left sub tree is: D G B

Right sub tree is: H E I C F


The Binary tree upto this point looks like:

©Topperworld
Data Structure and Algorithms

DGB HEICF

To find the root, left and right sub trees for D G B:

From the preorder sequence B D G, the root of tree is: B

From the inorder sequence D G B, we can find that D and G are to the left
of B.

The Binary tree upto this point looks like:


A

B HEICF

DG

To find the root, left and right sub trees for D G:

From the preorder sequence D G, the root of the tree is: D

From the inorder sequence D G, we can find that there is no left node to D
and G is at the right of D.

The Binary tree upto this point looks like:


A

B HEICF

To find the root, left and right sub trees for H E I C F:

©Topperworld
Data Structure and Algorithms

From the preorder sequence C E H I F, the root of the left sub tree
is: C

From the inorder sequence H E I C F, we can find that H E I are at the left
of C and F is at the right of C.

The Binary tree upto this point looks like:


A

B C

D HEI F

To find the root, left and right sub trees for H E I:

From the preorder sequence E H I, the root of the tree is: E

From the inorder sequence H E I, we can find that H is at the left of E and
I is at the right of E.

The Binary tree upto this point looks like:

B C

D E F

G H I

Example 2:

Construct a binary tree from a given postorder and inorder sequence:

Inorder: D G B A H E I C F
Postorder: G D B H I E F C A

Solution:

From Postorder sequence G D B H I E F C A, the root is: A

©Topperworld
Data Structure and Algorithms

From Inorder sequence D G B A H E I C F, we get the left and right sub


trees:

Left sub tree is: D G B


Right sub tree is: H E I C F

The Binary tree upto this point looks like:


A

DGB HEICF

To find the root, left and right sub trees for D G B:

From the postorder sequence G D B, the root of tree is: B

From the inorder sequence D G B, we can find that D G are to the left of B
and there is no right subtree for B.

The Binary tree upto this point looks like:


A

B HEICF

DG

To find the root, left and right sub trees for D G:

From the postorder sequence G D, the root of the tree is: D

From the inorder sequence D G, we can find that is no left subtree for D
and G is to the right of D.

The Binary tree upto this point looks like:


A

B HEICF

To find the root, left and right sub trees for H E I C F:

©Topperworld
Data Structure and Algorithms

From the postorder sequence H I E F C, the root of the left sub tree
is: C

From the inorder sequence H E I C F, we can find that H E I are to the left
of C and F is the right subtree for C.
The Binary tree upto this point looks like:
A

B C

D HEI F

To find the root, left and right sub trees for H E I:

From the postorder sequence H I E, the root of the tree is: E

From the inorder sequence H E I, we can find that H is left subtree for E
and I is to the right of E.

The Binary tree upto this point looks like:


A

B C

D E F

G H I

Example 3:

Construct a binary tree from a given preorder and inorder sequence:

Inorder: n1 n2 n3 n4 n5 n6 n7 n8 n9
Preorder: n6 n2 n1 n4 n3 n5 n9 n7 n8

Solution:
From Preorder sequence n6 n2 n1 n4 n3 n5 n9 n7 n8, the root is:
n6

©Topperworld
Data Structure and Algorithms

From Inorder sequence n1 n2 n3 n4 n5 n6 n7 n8 n9, we get the left and


right sub trees:

Left sub tree is: n1 n2 n3 n4 n5

Right sub tree is: n7 n8 n9

The Binary tree upto this point looks like:


n6

n1 n2 n3 n4 n5 n7 n8 n9

To find the root, left and right sub trees for n1 n2 n3 n4 n5:

From the preorder sequence n2 n1 n4 n3 n5, the root of tree is: n2

From the inorder sequence n1 n2 n3 n4 n5, we can find that n1 is to the


left of n2 and n3 n4 n5 are to the right of n2. The Binary tree upto this
point looks like:
n6

n2 n7 n8 n9

n1 n3 n4 n5

To find the root, left and right sub trees for n3 n4 n5:

From the preorder sequence n4 n3 n5, the root of the tree is: n4

From the inorder sequence n3 n4 n5, we can find that n3 is to the left of
n4 and n5 is at the right of n4.

The Binary tree upto this point looks like:


n6

n2 n7 n8 n9

n1 n4

n3 n5

©Topperworld
Data Structure and Algorithms

To find the root, left and right sub trees for n7 n8 n9:

From the preorder sequence n9 n7 n8, the root of the left sub tree
is: n9

From the inorder sequence n7 n8 n9, we can find that n7 and n8 are at
the left of n9 and no right subtree of n9.

The Binary tree upto this point looks like:


n6

n9
n2

n1 n4 n7 n8

n3 n5

To find the root, left and right sub trees for n7 n8:

From the preorder sequence n7 n8, the root of the tree is: n7

From the inorder sequence n7 n8, we can find that is no left subtree for
n7 and n8 is at the right of n7.

The Binary tree upto this point looks like:


n6

n9
n2

n1 n4 n7

n3 n5 n8

Example 4:

Construct a binary tree from a given postorder and inorder sequence:

Inorder: n1 n2 n3 n4 n5 n6 n7 n8 n9
Postorder: n1 n3 n5 n4 n2 n8 n7 n9 n6

©Topperworld
Data Structure and Algorithms

Solution:

From Postorder sequence n1 n3 n5 n4 n2 n8 n7 n9 n6, the root is:


n6

From Inorder sequence n1 n2 n3 n4 n5 n6 n7 n8 n9, we get the left and


right sub trees:

Left sub tree is: n1 n2 n3 n4 n5


Right sub tree is: n7 n8 n9

The Binary tree upto this point looks like:

n6

n1 n2 n3 n4 n5 n7 n8 n9

To find the root, left and right sub trees for n1 n2 n3 n4 n5:

From the postorder sequence n1 n3 n5 n4 n2, the root of tree is:


n2

From the inorder sequence n1 n2 n3 n4 n5, we can find that n1 is to the


left of n2 and n3 n4 n5 are to the right of n2.

The Binary tree upto this point looks like:

n6

n2 n7 n8 n9

n1 n3 n4 n5

To find the root, left and right sub trees for n3 n4 n5:

From the postorder sequence n3 n5 n4, the root of the tree is: n4
From the inorder sequence n3 n4 n5, we can find that n3 is to the left of
n4 and n5 is to the right of n4. The Binary tree upto this point looks like:

©Topperworld
Data Structure and Algorithms

n6

n2 n7 n8 n9

n1 n4

n3 n5

To find the root, left and right sub trees for n7 n8 and n9:

From the postorder sequence n8 n7 n9, the root of the left sub tree
is: n9

From the inorder sequence n7 n8 n9, we can find that n7 and n8 are to
the left of n9 and no right subtree for n9.

The Binary tree upto this point looks like:

n6

n2 n9

n1 n4 n7 n8

n3 n5

To find the root, left and right sub trees for n7 and n8:

From the postorder sequence n8 n7, the root of the tree is: n7

From the inorder sequence n7 n8, we can find that there is no left subtree
for n7 and n8 is to the right of n7. The Binary tree upto this point looks
like:

n6

n2 n9

n1 n4 n7

n3 n5 n8

©Topperworld
Data Structure and Algorithms

Binary Tree Creation and Traversal Using Arrays:

This program performs the following operations:

1. Creates a complete Binary Tree


2. Inorder traversal
3. Preorder traversal
4. Postorder traversal
5. Level order traversal
6. Prints leaf nodes
7. Finds height of the tree created

import java.util.LinkedList;
import java.util.Queue;

class TreeNode {
int data;
TreeNode left;
TreeNode right;

public TreeNode(int data) {


this.data = data;
left = null;
right = null;
}
}

public class BinaryTreeOperations {


TreeNode root;

public BinaryTreeOperations() {
root = null;
}

public void createCompleteBinaryTree(int[] arr) {


if (arr.length == 0) {
System.out.println("Array is empty.");
return;
}
root = createCompleteBinaryTree(arr, root, 0);
}

private TreeNode createCompleteBinaryTree(int[] arr, TreeNode node,


int index) {

©Topperworld
Data Structure and Algorithms

if (index < arr.length) {


TreeNode newNode = new TreeNode(arr[index]);
node = newNode;

node.left = createCompleteBinaryTree(arr, node.left, 2 *


index + 1);
node.right = createCompleteBinaryTree(arr, node.right, 2 *
index + 2);
}
return node;
}

public void inorderTraversal(TreeNode node) {


if (node != null) {
inorderTraversal(node.left);
System.out.print(node.data + " ");
inorderTraversal(node.right);
}
}

public void preorderTraversal(TreeNode node) {


if (node != null) {
System.out.print(node.data + " ");
preorderTraversal(node.left);
preorderTraversal(node.right);
}
}

public void postorderTraversal(TreeNode node) {


if (node != null) {
postorderTraversal(node.left);
postorderTraversal(node.right);
System.out.print(node.data + " ");
}
}

public void levelOrderTraversal(TreeNode root) {


if (root == null) {
return;
}

Queue<TreeNode> queue = new LinkedList<>();


queue.add(root);

©Topperworld
Data Structure and Algorithms

while (!queue.isEmpty()) {
TreeNode current = queue.poll();
System.out.print(current.data + " ");

if (current.left != null) {
queue.add(current.left);
}
if (current.right != null) {
queue.add(current.right);
}
}
}

public void printLeafNodes(TreeNode node) {


if (node == null) {
return;
}

if (node.left == null && node.right == null) {


System.out.print(node.data + " ");
}

printLeafNodes(node.left);
printLeafNodes(node.right);
}

public int findHeight(TreeNode node) {


if (node == null) {
return 0;
}

int leftHeight = findHeight(node.left);


int rightHeight = findHeight(node.right);

return Math.max(leftHeight, rightHeight) + 1;


}

public static void main(String[] args) {


int[] arr = {1, 2, 3, 4, 5, 6, 7};

BinaryTreeOperations tree = new BinaryTreeOperations();


tree.createCompleteBinaryTree(arr);

System.out.println("Inorder Traversal:");

©Topperworld
Data Structure and Algorithms

tree.inorderTraversal(tree.root);
System.out.println();

System.out.println("Preorder Traversal:");
tree.preorderTraversal(tree.root);
System.out.println();

System.out.println("Postorder Traversal:");
tree.postorderTraversal(tree.root);
System.out.println();

System.out.println("Level Order Traversal:");


tree.levelOrderTraversal(tree.root);
System.out.println();

System.out.println("Leaf Nodes:");
tree.printLeafNodes(tree.root);
System.out.println();

int height = tree.findHeight(tree.root);


System.out.println("Height of the Tree: " + height);
}
}

OUTPUT:-
Inorder Traversal:
4251637

Preorder Traversal:
1245367

Postorder Traversal:
4526731

Level Order Traversal:


1234567

Leaf Nodes:
4567

Height of the Tree: 3

©Topperworld
Data Structure and Algorithms

Binary Tree Creation and Traversal Using Pointers:

This program performs the following operations:

1. Creates a complete Binary Tree


2. Inorder traversal
3. Preorder traversal
4. Postorder traversal
5. Level order traversal
6. Prints leaf nodes
7. Finds height of the tree created
8. Deletes last node
9. Finds height of the tree created

import java.util.LinkedList;
import java.util.Queue;

class TreeNode {
int data;
TreeNode left;
TreeNode right;

public TreeNode(int data) {


this.data = data;
left = null;
right = null;
}
}

public class BinaryTreeOperations {


TreeNode root;

public BinaryTreeOperations() {
root = null;
}

public void createCompleteBinaryTree(int[] arr) {


if (arr.length == 0) {
System.out.println("Array is empty.");
return;
}
root = createCompleteBinaryTree(arr, root, 0);
}

©Topperworld
Data Structure and Algorithms

private TreeNode createCompleteBinaryTree(int[] arr, TreeNode node,


int index) {
if (index < arr.length) {
TreeNode newNode = new TreeNode(arr[index]);
node = newNode;

node.left = createCompleteBinaryTree(arr, node.left, 2 *


index + 1);
node.right = createCompleteBinaryTree(arr, node.right, 2 *
index + 2);
}
return node;
}

public void inorderTraversal(TreeNode node) {


if (node != null) {
inorderTraversal(node.left);
System.out.print(node.data + " ");
inorderTraversal(node.right);
}
}

public void preorderTraversal(TreeNode node) {


if (node != null) {
System.out.print(node.data + " ");
preorderTraversal(node.left);
preorderTraversal(node.right);
}
}

public void postorderTraversal(TreeNode node) {


if (node != null) {
postorderTraversal(node.left);
postorderTraversal(node.right);
System.out.print(node.data + " ");
}
}

public void levelOrderTraversal(TreeNode root) {


if (root == null) {
return;
}

©Topperworld
Data Structure and Algorithms

Queue<TreeNode> queue = new LinkedList<>();


queue.add(root);

while (!queue.isEmpty()) {
TreeNode current = queue.poll();
System.out.print(current.data + " ");

if (current.left != null) {
queue.add(current.left);
}
if (current.right != null) {
queue.add(current.right);
}
}
}

public void printLeafNodes(TreeNode node) {


if (node == null) {
return;
}

if (node.left == null && node.right == null) {


System.out.print(node.data + " ");
}

printLeafNodes(node.left);
printLeafNodes(node.right);
}

public int findHeight(TreeNode node) {


if (node == null) {
return 0;
}

int leftHeight = findHeight(node.left);


int rightHeight = findHeight(node.right);

return Math.max(leftHeight, rightHeight) + 1;


}

public boolean deleteLastNode() {


return deleteLastNode(root);
}

©Topperworld
Data Structure and Algorithms

private boolean deleteLastNode(TreeNode node) {


if (node == null) {
return false;
}

if (node.left == null && node.right == null) {


// Node is a leaf node; delete it
root = null; // or set root to null if the tree has only
one node
return true;
}

if (deleteLastNode(node.right)) {
node.right = null;
return true;
}

if (deleteLastNode(node.left)) {
node.left = null;
return true;
}

return false;
}

public static void main(String[] args) {


int[] arr = {1, 2, 3, 4, 5, 6, 7};

BinaryTreeOperations tree = new BinaryTreeOperations();


tree.createCompleteBinaryTree(arr);

System.out.println("Inorder Traversal:");
tree.inorderTraversal(tree.root);
System.out.println();

System.out.println("Preorder Traversal:");
tree.preorderTraversal(tree.root);
System.out.println();

System.out.println("Postorder Traversal:");
tree.postorderTraversal(tree.root);
System.out.println();

System.out.println("Level Order Traversal:");

©Topperworld
Data Structure and Algorithms

tree.levelOrderTraversal(tree.root);
System.out.println();

System.out.println("Leaf Nodes:");
tree.printLeafNodes(tree.root);
System.out.println();

int height = tree.findHeight(tree.root);


System.out.println("Height of the Tree: " + height);

boolean deleted = tree.deleteLastNode();


if (deleted) {
System.out.println("Last node deleted successfully.");
} else {
System.out.println("No last node to delete.");
}

height = tree.findHeight(tree.root);
System.out.println("Height of the Tree after deletion: " +
height);
}
}

OUTPUT:-
Inorder Traversal:
4251637

Preorder Traversal:
1245367

Postorder Traversal:
4526731

Level Order Traversal:


1234567

Leaf Nodes:
4567

Height of the Tree: 3


Last node deleted successfully.

©Topperworld
Data Structure and Algorithms

Height of the Tree after deletion: 2

➔Non Recursive Traversal Algorithms:

At first glance, it appears that we would always want to use the flat
traversal functions since they use less stack space. But the flat versions
are not necessarily better. For instance, some overhead is associated with
the use of an explicit stack, which may negate the savings we gain from
storing only node pointers. Use of the implicit function call stack may
actually be faster due to special machine instructions that can be used.

Inorder Traversal:

Initially push zero onto stack and then set root as vertex. Then repeat the
following steps until the stack is empty:

1. Proceed down the left most path rooted at vertex, pushing each
vertex onto the stack and stop when there is no left son of vertex.

2. Pop and process the nodes on stack if zero is popped then exit. If a
vertex with right son exists, then set right son of vertex as current
vertex and return to step one.

©Topperworld
Data Structure and Algorithms

Algorithm inorder()
{
stack[1] = 0
vertex = root
top: while(vertex ≠ 0)
{
push the vertex into the
stack vertex =
leftson(vertex)
}

pop the element from the stack and make it as vertex

while(vertex ≠ 0)
{
print the vertex node
if(rightson(vertex) ≠ 0)
{ vertex =
rightson(vertex)
goto top
}
pop the element from the stack and made it
as vertex
}
}

Preorder Traversal:

Initially push zero onto stack and then set root as vertex. Then repeat the
following steps until the stack is empty:

1. Proceed down the left most path by pushing the right son of vertex
onto stack, if any and process each vertex. The traversing ends after
a vertex with no left child exists.

2. Pop the vertex from stack, if vertex ≠ 0 then return to step one
otherwise exit.

©Topperworld
Data Structure and Algorithms

Algorithm preorder( )
{
stack[1] = 0 vertex =
root.
while(vertex ≠ 0)
{
print vertex node
if(rightson(vertex) ≠ 0) push the right son of vertex into the stack.
if(leftson(vertex) ≠ 0)
vertex = leftson(vertex)
else
pop the element from the stack and made it as vertex
}
}

Postorder Traversal:

Initially push zero onto stack and then set root as vertex. Then repeat the
following steps until the stack is empty:

1. Proceed down the left most path rooted at vertex. At each vertex of
path push vertex on to stack and if vertex has a right son push –
(right son of vertex) onto stack.

2. Pop and process the positive nodes (left nodes). If zero is popped
then exit. If a negative node is popped, then ignore the sign and
return to step one.

©Topperworld
Data Structure and Algorithms

Algorithm postorder( )
{
stack[1] = 0
vertex = root

top: while(vertex ≠ 0)
{
push vertex onto stack
if(rightson(vertex) ≠ 0)
push – (vertex) onto stack
vertex = leftson(vertex)
}
pop from stack and make it as vertex
while(vertex > 0)
{
print the vertex node
pop from stack and make it as vertex
}
if(vertex < 0)
{
vertex = - (vertex)
goto top
}
}

Example 1:

Traverse the following binary tree in pre, post and inorder using non-
recursive traversing algorithm.

A
• Preorder traversal yields:
B C A, B, D, G, K, H, L, M, C, E
D E
• Postorder travarsal yields:
G H K, G, L, M, H, D, B, E, C, A

K L M • Inorder travarsal yields:


K, G, D, L, H, M, B, A, E, C

Binary Tree Pre, Post and Inorder Traversing

©Topperworld
Data Structure and Algorithms

Inorder Traversal:

Initially push zero onto stack and then set root as vertex. Then repeat the
following steps until the stack is empty:

1. Proceed down the left most path rooted at vertex, pushing each
vertex onto the stack and stop when there is no left son of vertex.

2. Pop and process the nodes on stack if zero is popped then exit. If a
vertex with right son exists, then set right son of vertex as current
vertex and return to step one.

CURRENT PROCESSED
STACK REMARKS
VERTEX NODES
A 0 PUSH 0
0ABDG PUSH the left most path of
K A
K 0ABDG K POP K
POP G since K has no right
G 0ABD KG
son
POP D since G has no right
D 0AB KGD
son
Make the right son of D as
H 0AB KGD
vertex
0ABHL KGD PUSH the leftmost path of H

L 0ABH KGDL POP L


POP H since L has no right
H 0AB KGDLH
son
Make the right son of H as
M 0AB KGDLH
vertex
PUSH the left most path of
0ABM KGDLH
M
M 0AB KGDLHM POP M
POP B since M has no right
B 0A KGDLHMB
son
Make the right son of A as
A 0 KGDLHMBA
vertex

©Topperworld
Data Structure and Algorithms

PUSH the left most path of


C 0CE KGDLHMBA
C
KGDLHMBA
E 0C POP E
E
KGDLHMBA
C 0 Stop since stack is empty
EC

Postorder Traversal:

Initially push zero onto stack and then set root as vertex. Then repeat the
following steps until the stack is empty:

1. Proceed down the left most path rooted at vertex. At each vertex of
path push vertex on to stack and if vertex has a right son push –
(right son of vertex) onto stack.

2. Pop and process the positive nodes (left nodes). If zero is popped
then exit. If a negative node is popped, then ignore the sign and
return to step one.

CURRENT PROCESSED
STACK REMARKS
VERTEX NODES
A 0 PUSH 0
0 A –C B D –H PUSH the left most path of
GK A with a -ve for right sons
0 A –C B D –H K G POP all +ve nodes K and G

H 0 A –C B D KG Pop H
0 A –C B D H – PUSH the left most path of
KG
ML H with a -ve for right sons
0 A –C B D H –
L KGL POP all +ve nodes L
M
M 0 A –C B D H KGL Pop M
PUSH the left most path of
0 A –C B D H M K G L
M with a -ve for right sons
POP all +ve nodes M, H, D
0 A –C KGLMHDB
and B

©Topperworld
Data Structure and Algorithms

C 0A KGLMHDB Pop C
PUSH the left most path of
0ACE KGLMHDB
C with a -ve for right sons
K GLMHDBE POP all +ve nodes E, C and
0
C A A
K GLMHDBE
0 Stop since stack is empty
C A

Preorder Traversal:

Initially push zero onto stack and then set root as vertex. Then repeat the
following steps until the stack is empty:

1. Proceed down the left most path by pushing the right son of vertex
onto stack, if any and process each vertex. The traversing ends after
a vertex with no left child exists.

2. Pop the vertex from stack, if vertex ≠ 0 then return to step one
otherwise exit.

CURRENT PROCESSED
STACK REMARKS
VERTEX NODES
A 0 PUSH 0
PUSH the right son of each vertex
0CH ABDGK onto stack and process each vertex
in the left most path
H 0C ABDGK POP H
PUSH the right son of each vertex
0CM ABDGKHL onto stack and process each vertex
in the left most path
M 0C ABDGKHL POP M
PUSH the right son of each vertex
onto stack and process each vertex
0C ABDGKHLM
in the left most path; M has no left
path
C 0 A B D G K H L M Pop C

©Topperworld
Data Structure and Algorithms

PUSH the right son of each vertex


A B D G K H L M onto stack and process each vertex
0
CE in the left most path; C has no right
son on the left most path
ABDGKHLM
0 Stop since stack is empty
CE

Example 2:

Traverse the following binary tree in pre, post and inorder using non-
recursive traversing algorithm.

2 • Preorder traversal yields:


7 5
2, 7, 2, 6, 5, 11, 5, 9, 4

2 6 9 • Postorder travarsal yields:


2, 5, 11, 6, 7, 4, 9, 5, 2
5 11 4

• Inorder travarsal yields:


2, 7, 5, 6, 11, 2, 5, 4, 9
Binary Tree Pre, Post and In order Traversing

Inorder Traversal:

Initially push zero onto stack and then set root as vertex. Then repeat the
following steps until the stack is empty:

1. Proceed down the left most path rooted at vertex, pushing each
vertex onto the stack and stop when there is no left son of vertex.

2. Pop and process the nodes on stack if zero is popped then exit. If a
vertex with right son exists, then set right son of vertex as current
vertex and return to step one.

CURRENT STACK PROCESSED REMARKS


VERTEX NODES

©Topperworld
Data Structure and Algorithms

2 0

027
2
2 027 2

7 02 27

6 026 27
5
5 026 275

6 02 2756

11 0 2 11 2 7 5 6

11 02 2 7 5 6 11

2 0 2 7 5 6 11 2

5 05 2 7 5 6 11 2

5 0 2 7 5 6 11 2 5

9 094 2 7 5 6 11 2 5

4 09 2 7 5 6 11 2 5
4
9 0 2 7 5 6 11 2 5 Stop since stack is
49 empty

Postorder Traversal:

Initially push zero onto stack and then set root as vertex. Then repeat the
following steps until the stack is empty:

1. Proceed down the left most path rooted at vertex. At each vertex of
path push vertex on to stack and if vertex has a right son push –
(right son of vertex) onto stack.

2. Pop and process the positive nodes (left nodes). If zero is popped
then exit. If a negative node is popped, then ignore the sign and
return to step one.

©Topperworld
Data Structure and Algorithms

CURRENT STACK PROCESSED REMARKS


VERTEX NODES
2 0

0 2 –5 7 –6
2
2 0 2 –5 7 –6 2

6 0 2 –5 7 2

0 2 –5 7 6 – 2
11 5
5 0 2 –5 7 6 – 25
11
11 0 2 –5 7 6 25
11
0 2 –5 2 5 11 6 7

5 0 2 5 –9 2 5 11 6 7

9 02594 2 5 11 6 7

0 2 5 11 6 7 4 9 Stop since stack is


52 empty

Preorder Traversal:

Initially push zero onto stack and then set root as vertex. Then repeat the
following steps until the stack is empty:

1. Proceed down the left most path by pushing the right son of vertex
onto stack, if any and process each vertex. The traversing ends after
a vertex with no left child exists.

2. Pop the vertex from stack, if vertex ≠ 0 then return to step one
otherwise exit.

CURRENT STACK PROCESSED REMARKS


VERTEX NODES
2 0

056 272
6 0 5 11 2 7 2 6 5

©Topperworld
Data Structure and Algorithms

11 05 2 7 2 6 5 11

05 2 7 2 6 5 11

5 09 2 7 2 6 5 11 5

9 0 2 7 2 6 5 11 5
94
0 2 7 2 6 5 11 5 Stop since stack is
94 empty

Expression Trees:

Expression tree is a binary tree, because all of the operations are binary.
It is also possible for a node to have only one child, as is the case with the
unary minus operator. The leaves of an expression tree are operands, such
as constants or variable names, and the other (non leaf) nodes contain
operators.

Once an expression tree is constructed we can traverse it in three ways:

• Inorder Traversal
• Preorder Traversal
• Postorder Traversal

Figure shows some more expression trees that represent arithmetic


expressions given in infix form.

©Topperworld
Data Structure and Algorithms

+ +

+ / + d

a b c d + c

(a) (a + b) + (c / d) (b) ((a + b) + c) + d


a b

+ *

- + + *

a x y b c a

(c) ((-a) + (x + y)) / ((+b) * (c * a))

Figure: Expression Trees

An expression tree can be generated for the infix and postfix expressions.

An algorithm to convert a postfix expression into an expression


tree is as follows:

1. Read the expression one symbol at a time.

2. If the symbol is an operand, we create a one-node tree and push


a pointer to it onto a stack.

3. If the symbol is an operator, we pop pointers to two trees T1 and


T2 from the stack (T1 is popped first) and form a new tree whose
root is the operator and whose left and right children point to T2
and T1 respectively. A pointer to this new tree is then pushed onto
the stack.

Example 1:

Construct an expression tree for the postfix expression: a b + c d e + * *

Solution:

©Topperworld
Data Structure and Algorithms

The first two symbols are operands, so we create one-node trees and push
pointers to them onto a stack.

a b

Next, a ‘+’ is read, so two pointers to trees are popped, a new tree is
formed, and a pointer to it is pushed onto the stack.

a b

Next, c, d, and e are read, and for each one–node tree is created and a
pointer to the corresponding tree is pushed onto the stack.

a b c d e

Now a ‘+’ is read, so two trees are merged.

+
+ c +

a bb d e

Continuing, a ‘*’ is read, so we pop two tree pointers and form a new tree
with a ‘*’ as root.

©Topperworld
Data Structure and Algorithms

+
+ *

a b c +

d ee

Finally, the last symbol is read, two trees are merged, and a pointer to the
final tree is left on the stack.

+
*

+ *

a b c +

d e
e

For the above tree:


Inorder form of the expression: a + b * c * d + e
Preorder form of the expression: * + a b * c + d e
Postorder form of the expression: a b + c d e + * *

Example 2:

Construct an expression tree for the arithmetic expression:

(A + B * C) – ((D * E + F) / G)

Solution:

First convert the infix expression into postfix notation. Postfix notation of
the arithmetic expression is: A B C * + D E * F + G / -

©Topperworld
Data Structure and Algorithms

The first three symbols are operands, so we create one-node trees and
pointers to three nodes pushed onto the stack.

A B C

Next, a ‘*’ is read, so two pointers to trees are popped, a new tree is
formed, and a pointer to it is pushed onto the stack.

A *

B C

Next, a ‘+’ is read, so two pointers to trees are popped, a new tree is
formed, and a pointer to it is pushed onto the stack.

A
*

B C

Next, D and E are read, and for each one–node tree is created and a pointer
to the corresponding tree is pushed onto the stack.

+ D E

A
*

B C

Continuing, a ‘*’ is read, so we pop two tree pointers and form a new tree
with a ‘*’ as root.

©Topperworld
Data Structure and Algorithms

+ *

A * D E

B C

Proceeding similar to the previous steps, finally, when the last symbol is
read, the expression tree is as follows:

+
-

+ /

A * + G

B C * F

D E

Converting expressions with expression trees:

Let us convert the following expressions from one type to another. These
can be as follows:

1. Postfix to infix
2. Postfix to prefix
3. Prefix to infix
4. Prefix to postfix

1. Postfix to Infix:

The following algorithm works for the expressions whose infix form does
not require parenthesis to override conventional precedence of operators.

A. Create the expression tree from the postfix expression


B. Run inorder traversal on the tree.

©Topperworld
Data Structure and Algorithms

2. Postfix to Prefix:

The following algorithm works for the expressions to convert postfix to


prefix:

A. Create the expression tree from the postfix expression


B. Run preorder traversal on the tree.

3. Prefix to Infix:

The following algorithm works for the expressions whose infix form does
not require parenthesis to override conventional precedence of operators.

A. Create the expression tree from the prefix expression


B. Run inorder traversal on the tree.

4. Prefix to postfix:

The following algorithm works for the expressions to convert postfix to


prefix:

A. Create the expression tree from the prefix expression


B. Run postorder traversal on the tree.

Threaded Binary Tree:

The linked representation of any binary tree has more null links than actual
pointers. If there are 2n total links, there are n+1 null links. A clever way
to make use of these null links has been devised by A.J. Perlis and C.
Thornton.

Their idea is to replace the null links by pointers called Threads to other
nodes in the tree.

©Topperworld
Data Structure and Algorithms

If the RCHILD(p) is normally equal to zero, we will replace it by a pointer


to the node which would be printed after P when traversing the tree in
inorder.

A null LCHILD link at node P is replaced by a pointer to the node which


immediately precedes node P in inorder. For example, Let us consider the
tree:

B C

D E F G

H I

The Threaded Tree corresponding to the above tree is:

B C

D E F G

H I

The tree has 9 nodes and 10 null links which have been replaced by
Threads. If we traverse T in inorder the nodes will be visited in the order H
D I B E A F C G.

For example, node ‘E’ has a predecessor Thread which points to ‘B’ and a
successor Thread which points to ‘A’. In memory representation Threads
and normal pointers are distinguished between as by adding two extra one
bit fields LBIT and RBIT.

LBIT(P) = 1 if LCHILD(P) is a normal pointer


LBIT(P) = 0 if LCHILD(P) is a Thread

RBIT(P) = 1 if RCHILD(P) is a normal pointer


RBIT(P) = 0 if RCHILD(P) is a Thread
In the above figure two threads have been left dangling in LCHILD(H) and
RCHILD(G). In order to have no loose Threads we will assume a head node
for all threaded binary trees. The Complete memory representation for the
tree is as follows. The tree T is the left sub-tree of the head node.

©Topperworld
Data Structure and Algorithms

Binary Search Tree:

A binary search tree is a binary tree. It may be empty. If it is not empty


then it satisfies the following properties:

1. Every element has a key and no two elements have the same key.

2. The keys in the left subtree are smaller than the key in the root.

3. The keys in the right subtree are larger than the key in the root.

4. The left and right subtrees are also binary search trees.

Figure is a binary search tree, whereas figure 5.2.5(b) is not a binary search
tree.

16 16

12 20 12 20

11 14 19 11 14 19
7

13 13 17

Binary Search Tree Not a Binary Search Tree


(a) (b)

Figure: Examples of binary search trees

General Trees (m-ary tree):

©Topperworld
Data Structure and Algorithms

If in a tree, the outdegree of every node is less than or equal to m, the tree
is called general tree. The general tree is also called as an m-ary tree. If
the outdegree of every node is exactly equal to m or zero then the tree is
called a full or complete m-ary tree. For m = 2, the trees are called
binary and full binary trees.

Differences between trees and binary trees:

TREE BINARY TREE

Each element in a tree can have any Each element in a binary tree has at
number of subtrees. most two subtrees.

The subtrees in a tree are The subtrees of each element in a


unordered. binary tree are ordered (i.e. we
distinguish between left and right
subtrees).

Converting a m-ary tree (general tree) to a binary tree:

There is a one-to-one mapping between general ordered trees and binary


trees. So, every tree can be uniquely represented by a binary tree.
Furthermore, a forest can also be represented by a binary tree.

Conversion from general tree to binary can be done in two stages.

Stage 1:

• As a first step, we delete all the branches originating in every node


except the left most branch.

• We draw edges from a node to the node on the right, if any, which
is situated at the same level.

Stage 2:

©Topperworld
Data Structure and Algorithms

• Once this is done then for any particular node, we choose its left
and right sons in the following manner:

• The left son is the node, which is immediately below the given
node, and the right son is the node to the immediate right of the
given node on the same horizontal line. Such a binary tree will not
have a right subtree.

Example 1:

Convert the following ordered tree into a binary tree:


1

2 3 4 5

6 7 8 9 10 11

Solution:

Stage 1
tree by using the above mentioned procedure is as follows:
1

2 3 4 5

6 7 8 9 10 11

Stage 2 tree by using the above mentioned procedure is as follows:


1

6 3

7 8 4

10

11

©Topperworld
Data Structure and Algorithms

Example 2:

Construct a unique binary tree from the given forest.


1 7

2 3 8 9 10

4 5 6 11 12 13
0

Solution:

Stage 1 tree by using the above mentioned procedure is as follows:


1 7

2 3 8 9 10

4 5 6 11 12 13

Stage 2 tree by using the above mentioned procedure is as follows (binary


tree representation of forest):
1

2 7

4 3 8

5 6 11 9
9

10

12

13

Example 3:

For the general tree shown below:

1. Find the corresponding binary tree T’.

©Topperworld
Data Structure and Algorithms

2. Find the preorder traversal and the postorder traversal of T.


3. Find the preorder, inorder and postorder traversals of T’.
4. Compare them with the preorder and postorder traversals
obtained for T’ with the general tree T.
A

B F J

C D E G H K L M N

P Q
General tree T

Solution:

1. Stage 1:

The tree by using the above-mentioned procedure is as follows:


A

B F J

C D E G B
H
5 K L M N

P Q

Stage 2:

The binary tree by using the above-mentioned procedure is as


follows:

©Topperworld
Data Structure and Algorithms

C F

D G J

10
E H K

L
Binart tree T’

P N

2. Suppose T is a general tree with root R and subtrees T 1, T2, ……….,


TM. The preorder traversal and the postorder traversal of T are:

Preorder:
1) Process the root R.
2) Traverse the subtree T1, T2, ……., TM in preorder.

Postorder:
1) Traverse the subtree T1, T2, ……., TM in postorder.
2) Process the root R.

The tree T has the root A and subtrees T1, T2 and T3 such that:
T1 consists of nodes B, C, D and E.
T2 consists of nodes F, G and H.
T3 consists of nodes J, K, L, M, N, P and Q.

A. The preorder traversal of T consists of the following steps:


(i) Process root A.
(ii) Traverse T1 in preorder: Process nodes B, C, D, E.
(iii) Traverse T2 in preorder: Process nodes F, G, H.
(iv) Traverse T3 in preorder: Process nodes J, K, L, M, P, Q,
N.

©Topperworld
Data Structure and Algorithms

The preorder traversal of T is as follows:


A, B, C, D, E, F, G, H, J, K, L, M, P, Q, N

B. The postorder traversal of T consists of the following steps:


(i) Traverse T1 in postorder: Process nodes C, D, E, B.
(ii) Traverse T2 in postorder: Process nodes G, H, F.
(iii) Traverse T3 in postorder: Process nodes K, L, P, Q, M, N,
J.
(iv) Process root A.

The postorder traversal of T is as follows:


C, D, E, B, G, H, F, K, L, P, Q, M, N, J, A

3. The preorder, inorder and postorder traversals of the binary tree T’


are as follows:

Preorder: A, B, C, D, E, F, G, H, J, K, M, P, Q, N
Inorder: C, D, E, B, G, H, F, K, L, P, Q, M, N, J, A
Postorder: E, D, C, H, G, Q, P, N, M, L, K, J, F, B, A

4. Comparing the preorder and postorder traversals of T’ with the


general tree T:

We can observer that the preorder of the binary tree T’ is identical to


the preorder of the general T.

The inorder traversal of the binary tree T’ is identical to the postorder


traversal of the general tree T.

There is no natural traversal of the general tree T which corresponds


to the postorder traversal of its corresponding binary tree T’.

➔Search and Traversal Techniques for m-ary


trees:

Search involves visiting nodes in a tree in a systematic manner, and may


or may not result into a visit to all nodes. When the search necessarily

©Topperworld
Data Structure and Algorithms

involved the examination of every vertex in the tree, it is called the


traversal. Traversing of a tree can be done in two ways.

1. Depth first search or traversal.


2. Breadth first search or traversal.

Depth first search:

In Depth first search, we begin with root as a start state, then some
successor of the start state, then some successor of that state, then some
successor of that and so on, trying to reach a goal state. One simple way
to implement depth first search is to use a stack data structure consisting
of root node as a start state.

If depth first search reaches a state S without successors, or if all the


successors of a state S have been chosen (visited) and a goal state has not
get been found, then it “backs up” that means it goes to the immediately
previous state or predecessor formally, the state whose successor was ‘S’
originally.

To illustrate this let us consider the tree shown below.


D

A
E

START J
S B

H G GOAL

C F
K
I

Suppose S is the start and G is the only goal state. Depth first search will
first visit S, then A, then D. But D has no successors, so we must back up
to A and try its second successor, E. But this doesn’t have any successors
either, so we back up to A again. But now we have tried all the successors
of A and haven’t found the goal state G so we must back to ‘S’. Now ‘S’ has
a second successor, B. But B has no successors, so we back up to S again
and choose its third successor, C. C has one successor, F. The first
successor of F is H, and the first of H is J. J doesn’t have any successors,
so we back up to H and try its second successor. And that’s G, the only
goal state.

©Topperworld
Data Structure and Algorithms

So the solution path to the goal is S, C, F, H and G and the states considered
were in order S, A, D, E, B, C, F, H, J, G.

Disadvantages:

1. It works very fine when search graphs are trees or lattices, but
can get struck in an infinite loop on graphs. This is because depth
first search can travel around a cycle in the graph forever.

To eliminate this keep a list of states previously visited, and never


permit search to return to any of them.

2. We cannot come up with shortest solution to the problem.

Breadth first search:

Breadth-first search starts at root node S and “discovers" which vertices


are reachable from S. Breadth-first search discovers vertices in increasing
order of distance. Breadthfirst search is named because it visits vertices
across the entire breadth.

To illustrate this let us consider the following tree:


D

A
E

START J
S B

H G GOAL

C F
K
I

Breadth first search finds states level by level. Here we first check all the
immediate successors of the start state. Then all the immediate successors
of these, then all the immediate successors of these, and so on until we
find a goal node. Suppose S is the start state and G is the goal state. In
the figure, start state S is at level 0; A, B and C are at level 1; D, e and F
at level 2; H and I at level 3; and J, G and K at level 4.

So breadth first search, will consider in order S, A, B, C, D, E, F, H, I, J and


G and then stop because it has reached the goal node.

©Topperworld
Data Structure and Algorithms

Breadth first search does not have the danger of infinite loops as we
consider states in order of increasing number of branches (level) from the
start state.

One simple way to implement breadth first search is to use a queue data
structure consisting of just a start state.

Sparse Matrices:

A sparse matrix is a two–dimensional array having the value of majority


elements as null. The density of the matrix is the number of non-zero
elements divided by the total number of matrix elements. The matrices
with very low density are often good for use of the sparse format. For
example,

As far as the storage of a sparse matrix is concerned, storing of null


elements is nothing but wastage of memory. So we should devise technique
such that only non-null elements will be stored. The matrix A produces:

(3, 1) 1
(2, 2) 2
S = (3, 2) 3
(4, 3) 4
(1, 4) 5
The printed output lists the non-zero elements of S, together with their row
and column indices. The elements are sorted by columns, reflecting the
internal data structure. In large number of applications, sparse matrices
are involved. One approach is to use the linked list.
The program to represent sparse matrix:

/* Check whether the given matrix is sparse matrix or not, if so then


print in alternative form for storage. */

import java.util.Scanner;
public class SparseMatrix {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);

©Topperworld
Data Structure and Algorithms

System.out.print("Enter the number of rows: ");


int rows = input.nextInt();
System.out.print("Enter the number of columns: ");
int cols = input.nextInt();
int[][] matrix = new int[rows][cols];
System.out.println("Enter the matrix elements:");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = input.nextInt();
}
}

System.out.println("Original Matrix:");
printMatrix(matrix);
if (isSparse(matrix)) {
System.out.println("The given matrix is a sparse
matrix.");
int[][] compactMatrix = convertToCompactForm(matrix);
System.out.println("Compact Form of the Matrix:");
printMatrix(compactMatrix);
} else {
System.out.println("The given matrix is not
sparse.");
}
}
public static boolean isSparse(int[][] matrix) {
int zeroCount = 0;
int totalElements = matrix.length * matrix[0].length;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] == 0) {
zeroCount++;
}
}
}
// If more than half of the elements are zero, it's
considered sparse.
return zeroCount > (totalElements / 2);
}
public static int[][] convertToCompactForm(int[][] matrix) {
int numRows = matrix.length;

©Topperworld
Data Structure and Algorithms

int numCols = matrix[0].length;


int nonZeroCount = 0;
// Count the number of non-zero elements
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++) {
if (matrix[i][j] != 0) {
nonZeroCount++;
}
}
}

int[][] compactMatrix = new int[nonZeroCount][3];


int compactRow = 0;
// Store non-zero elements in compact form (row, col,
value)
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++) {
if (matrix[i][j] != 0) {
compactMatrix[compactRow][0] = i;
compactMatrix[compactRow][1] = j;
compactMatrix[compactRow][2] = matrix[i][j];
compactRow++;
}
}
}
return compactMatrix;
}
public static void printMatrix(int[][] matrix) {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
System.out.print(matrix[i][j] + "\t");
}
System.out.println();
}
}
}

OUTPUT 1:-
Enter the number of rows: 3
Enter the number of columns: 4

©Topperworld
Data Structure and Algorithms

Enter the matrix elements:


0000
5000
0080
Original Matrix:
0 0 0 0
5 0 0 0
0 0 8 0
The given matrix is a sparse matrix.
Compact Form of the Matrix:
1 0 5
2 2 8

OUTPUT 2:-
Enter the number of rows: 2
Enter the number of columns: 2
Enter the matrix elements:
12
34
Original Matrix:
1 2
3 4
The given matrix is not sparse.

©Topperworld

You might also like