0% found this document useful (0 votes)
2 views

Data Structure Using C Notes

The document provides an introduction to data structures, defining them as organized collections of related data items and categorizing them into primitive and non-primitive types. It outlines operations on data structures, implementation phases, algorithm specifications, and performance analysis, including recursion concepts and examples. Additionally, it discusses arrays, their advantages, and classifications, emphasizing their role in storing homogeneous data types.

Uploaded by

nnagammahiremath
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

Data Structure Using C Notes

The document provides an introduction to data structures, defining them as organized collections of related data items and categorizing them into primitive and non-primitive types. It outlines operations on data structures, implementation phases, algorithm specifications, and performance analysis, including recursion concepts and examples. Additionally, it discusses arrays, their advantages, and classifications, emphasizing their role in storing homogeneous data types.

Uploaded by

nnagammahiremath
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 66

DATA STRUCTURES USING C

UNIT – 1: 1.1 Introduction to Data structures


Data structure deals with the composition of data to be manipulated by the program. This is done in
conjunction with the algorithm for the program. Data structures are commonly used in many
program designs. The study of data structures, therefore, rightly forms the central course of any
curriculum in computer science and engineering.
The following are list of various terms used in data structures
Data: Value or set values.
Data item: Single unit of values.
Group item: Data items that are divided into sub-items.
Elementary items: Data items that are not divided into sub-items.
Entity: Something that has certain attributes or properties which may have assigned values
Example: Attributes: Name Age Sex
Values: Abhishek 16 Male
Entity set: Entities with similar attributes
Example: All employees in an organization.
Information field: Meaningful or processed data.
Field: Single elementary unit of information representing an attribute or an entity.
Record: Collection of records of the entities in a given entity set.
1.1 Definition of Data Structure
Data structure is the logical or mathematical model of a particular organization of data.
OR
Data structure is an organized collection of a number of related data items that are treated as one by
the computer.
OR
A data structure is a logical method of representing data in memory.

1.2 Types of Data Structures


Data structures are classified as into two different types, namely;
1. Primitive data structures
2. Non-primitive data structures

1.2.1 Primitive data structures


The data structures are the pre-defined data types by programming languages, which can be directly
operated are called primitive data structures. These are used by the programmer during the creation
of new variables.
1
Example: int, float, char, double
1.2.2 Non-primitive data structures
The data structures are not pre-defined data types by programming languages, which cannot be
manipulated or operated directly called non-primitive data structures. They are created by the
programmer. Non-primitive data structures are classified as into two different types, namely;
i. Linear data structures
ii. Non-linear data structures.
These data structures are known as fundamental data structures or classic data structure.
i. Linear data structures
A data structure is said to be linear, if its elements form a sequence or linear list. The linear
data structures are arrays, linked-lists, stacks and queues.
ii. Non-linear data structures
A data structure is said to be non-linear, if its elements does not form a sequence. In other
words, they are stored randomly. The non-linear data structures are trees, graphs tables and
sets.

1.3 Operations on data structures


The data appearing in data structures are processed by means of certain operations. The following
operations can be performed on data structures:
1. Traversing: Accessing each element exactly once so that certain items in the element may be
processed. This accessing and processing is sometimes called visiting the element.
2. Searching: Finding the location of an element with a given value or finding the location of all
the elements which satisfy one or more conditions.
3. Inserting: Adding a new element to the data structure.
4. Deleting: Removing an element from the data structure.
5. Sorting: It refers to the operation of arranging the data in some given order, such as
increasing or decreasing with numerical data or alphabetically with character data.
6. Merging: Combining the records in two different sorted file into a sorted single file.

1.4 Implementation of Data Structures


The classic data structures are implemented in two phases:
Phase 1
Storage representation: Here we have to decide how a data structure can be stored in computer
memory. This storage representation, in general, is based on the use of other data structures.
Phase 2
Algorithms notation of various operations of the classic data structure: Function for
manipulating a data structure is expressed in terms of algorithms so that details of the operation can
be understood easily and reader can implement them with the help of any programming language

2
(preferably we use C/C++ programming because of their versatile features and modern
programming approaches).
1.4.1Algorithm Specification
The concept of algorithm is fundamental to computer science and plays a crucial role in developing
good and efficient programs. It is process or set of rules required to perform calculations or data
processing.
Definition: An algorithm is defined as step by step procedure to solve a given problem in finite
number of steps. It accepts a set of inputs and produces the desired output for the given problem.

Characteristics of an Algorithm
Input: It takes zero or more well-defined inputs.
Output: It should produce at least one or more well-defined outputs.
Definiteness: Each step must be clear, well-defined and precise.
Finiteness: The algorithm must terminate after finite number of steps.
Effectiveness: Each instruction must be simple enough to be carried out.
Independent: It should be independent of any programming language.

A good algorithm should be optimized in terms of time and space. The time and space it uses are
two major measures of the efficiency of an algorithm.

1.4.2 Performance Analysis


Performance analysis of an algorithm is done to understand how efficient that algorithm is compared
to another algorithm that solves the same computational problem. Two ways to evaluate
performance of an algorithm are;
1. Space requirement: It is related to memory resource needed by the algorithm to solve a
computational problem to completion. The program source code has many types of variables and
their memory requirements are different.
2. Time Complexity: It is the amount of time required to run the program to completion.

1.4.3 Performance Measurement


Performance measurement is the process used to assess the efficiency and effectiveness of
algorithms. It is a systematic approach.
The following metrics are used to evaluate the performance of an algorithm:
 The amount of space necessary to perform the algorithm’s task (Space Complexity). It
consists of both program and data space.
 The time necessary to accomplish the algorithm’s task (Time Complexity).
3
1.5 Recursion
The process in which a function calls itself is called recursion and the corresponding function is
called recursive function. In recursion, a function calls itself directly or indirectly.
A recursive function solves a particular problem by calling a copy of itself and solving smaller
sub-problems of the original problems. Many more recursive calls can be generated as and when
required. It is essential that we should provide a certain case in order to terminate this recursion
process.
Every recursive function has two components:
1. A base criteria (termination condition): The base criteria is usually the smallest input and it
is also the mechanism that stops the function from calling itself forever.
2. A recursive part: The recursive step is the set of all cases where a recursive call, or a function
call to itself, is made.
A recursive function with these two properties is said to be well-defined.
Example: Factorial Function
The product of the positive integers from 1 to n, inclusive, is called “n factorial” and its usually
denoted by n!.
n! = n x (n -1) x (n-2) x ………. x 3 x 2 x 1 or n! = n x ( n-1) !
It is also convention to define 0! = 1, so that the function is defined for all non-negative integers.
Thus we have,
0! =1 1! = 1 2! = 2 . 1 = 2 3! = 3 . 2 . 1 = 6 4! = 4 . 3 . 2 . 1 = 24 , and so on.

The recursive definition to obtain factorial of n is shown below


1 if n = 0
factorial (n) =
n * factorial(n-1) otherwise
We can compute 5! using the recursive definition, which requires eleven steps as shown below:
1. 5! = 5 * 4!
2. 4! = 4 * 3!
3. 3! = 3 * 2!
4. 2! = 2 * 1!
5. 1! = 1 * 0!
6. 0! = 1
7. 1! = 1 . 1 = 1
8. 2! = 2 . 1 = 2
9. 3! = 3 . 2 . 1 = 6
10. 4! = 4 . 3 . 2 . 1 = 24
11. 5! = 5 . 4 . 3 . 2 . 1 = 120
4
Syntax of the Recursion function
main( )
{
recursion( ); // function call
}
void recursion( )
{
recursion( ); // The recursive function calls itself inside the same function
}
In the above syntax, the main() function calls the recursion function only once. After that, the
recursion function calls itself up to the defined condition.
1.5.1 Types of Recursions
Recursive functions can be classified as follows;
1. Direct recursion
When a function calls itself within the same function repeatedly, it is called the direct recursion.
Structure of the direct recursion
funtion1( )
{
------------
function1( );
------------
}
In the above structure of the direct recursion, the outer funtion1( ) recursively calls the inner
function1( ), and this type of recursion is called the direct recursion.
/* C program to illustrate direct recursion */
#include <stdio.h>
main( )
{
int n, fact ;
printf(“Enter a positive number :”);
scanf(“%d”,&n);
fact = factorial(n);
printf(”\n Factorial of %d =%d”,n, fact);
}
int factorial(int n)
{
int f;
if ( n = = 0)
return 1;
else
f = n * factorial(n-1);
return f;
5
}
2. Indirect recursion
In this type there may be more than one function and they call one another in a circular manner.
Structure of the direct recursion
function1( )
{
------------
function2( );
}
function2( )
{
------------
function3( );
}
function3( )
{
------------
function1( );
}
In the above structure of the indirect recursion, function1( ) calls the function2( ), the function2( )
calls function3( ), and function3( ) calls back function1( ) in circular manner.
/* C program to illustrate indirect recursion */
#include <stdio.h>
int num = 1;
main ( )
{
odd( );
}
void odd ( )
{
if (num <= 10)
{
printf (" %d ", num + 1);
num++;
even( );
}
return;
}
void even ( )
{
if ( num <= 10)
{
printf (" %d ", num - 1);
num++;
odd( );
}
6
return;
}
1.5.2 Examples of Recursive functions
Using a recursive algorithm, certain problems can be solved quite easily. Some of the examples of
recursive functions are;
1. Fibonacci numbers
2. GCD of two numbers
3. Binomial co-efficient
4. Tower of Hanoi

1.
Example: Fibonacci sequence of 10 terms: 0 1 1 2 3 5 8 13 21 34
/* C program to generate N Fibonacci numbers using recursive
function */
#include <stdio.h>
int fibo(int n)
{
if ( n = = 0)
return 0;
else if ( n = = 1)
return 1;
else
Fibonacci Numbers
The Fibonacci sequence is a set of numbers that is generated by adding previous two numbers.
First two numbers are 0 and 1 respectively.
return (fibo(n - 1) + fibo(n - 2));
}
main( )
{
int i, n ;
printf(“Enter the number of terms :”);
scanf(“%d”,&n);
printf(“Fibonacci series \n”);
for(i=1; i<=n; i++)
printf(”%d \n” fibo(i));
}

7
2. GCD of two Numbers
The GCD of two non-zero integers a and b is greatest positive integer is d, such that d is a divisor
of both a and b.

/* C program to find the GCD of two numbers using recursive


function */
#include <stdio.h>
int gcd( int, int);
main( )
{
int n1, n2, G ;
printf(“Enter two positive numbers \n”);
scanf(“%d%d”,&n1, &n2);
G = gcd(n1, n2);
printf(”\n GCD of %d and %d =%d”, n, n2, G);
}
int gcd(int n1, int n2)
{
if ( n2 ! = 0)
return (gcd(n2, n1%n2));
else
return n1;
}

3. Binomial Co-efficient nCr:


Binomial co-efficient formula can be recursively defined a recursive
function.

/* C program to find Binomial co-efficient using


recursive function */
#include <stdio.h>
main( )
{
int n, c, ncr ;
printf(“Enter the values of n and r \n”);
scanf(“%d%d”,&n, &r);
ncr = fact(n) / fact(r) * fact(n-r);
printf(”\n ncr of %d and %d =%d”, n, c, ncr);
}
int fact(int n)

8
{
int i=1;
while(n!=0)
{
i= i*n;
n--;
}
Return i;
}

4. Tower of Hanoi
Tower of Hanoi is a mathematical puzzle where we have three rods and n disks. The objective of
the puzzle is to move the entire stack to another rod, obeying the following simple rules:
1. Only one disk can be moved at a time.
2. Each move consists of taking the upper disk from one of the stacks and placing it on top of
another stack i.e. a disk can only be moved if it is the uppermost disk on a stack.
3. No disk may be placed on top of a smaller disk.

Tower of Hanoi with 3 disks

Approach: An example with 3 disks :


Step 1 : Shift first disk from 'A' to 'C'.
Step 2 : Shift second disk from 'A' to 'B'.
Step 3 : Shift first disk from 'C' to 'B'.
Step 4 : Shift third disk from 'A' to 'C'.
Step 5 : Shift first disk from 'B' to 'A'.
9
Step 6 : Shift second disk from 'B' to 'C'.
Step 7 : Shift first disk from 'A' to 'C'.

1.5.4 Difference between Recursion and Iteration


Recursion Iteration

1. Recursion uses selection structure 1. Iteration uses repetition structure

2. It is process where a function calls itself 2. It is process where a set of instructions


repeatedly executed

3. Recursion is used in functions 3. Iterations are used in looping statements

4. Recursion terminates when a base case is 4. An iteration terminates when the loop
recognized condition fails
5. Used when code size needs to be small, and 5. Used when time complexity needs to be
time complexity is not an issue balanced against an expanded code size
6. Recursion is usually slower than
6. An iteration does not use the stack so it is
iteration due
faster than recursion
to the overhead of maintaining the stack
7. Recursion uses more memory than
7. Iteration consumes less memory
iteration

8. Recursion uses more time 8. Iteration takes less time

9. Recursion makes the program is very small 9. Iteration makes the program longer

10
UNIT – 2: Arrays
An array is defined as collection of homogeneous data item stored in consecutive memory locations.
Array is considered as linear data structure because it stores the elements of same data types.
Advantages of arrays are;
 Arrays store multiple data of similar types with the same name.
 It is helpful to store any type of data with a fixed size
 Accessing an element is very easy by using the index number.
 The search process can be applied to an array easily.

2.1 Types of Arrays


Arrays are classified into following categories;
1. One-dimensional arrays or linear arrays
2. Multi-dimensional arrays

2.2 One-dimensional arrays or Linear arrays


A one-dimensional array or a linear array is defined as a list of a finite number of homogeneous data
elements stored in successive memory locations, and are referenced respectively by an index called
subscript.
The number of elements is called the length or size of the array can be obtained by the formula.
Length = UB – LB + 1.
Where, UB is the largest index called the Upper Bound, LB is the smallest index, called the Lower
Bound of the array.

2.2.1 Declaration of Linear arrays


Linear arrays are declared in C as follows
data type array_name[size];
Where, data type may be built-in type such as int, float, char or double, array_name is a name of
the array that should be valid identifier name and size indicates number elements an array can hold,
must be enclosed in brackets.
Example: Let NUM be a 6-element linear array of integers, which can be declare as follows;
int NUM[6];
The array NUMBER is frequently pictured as
NUM[0]
NUM[1]
NUM[2]

11
NUM[3] NUM[0] NUM[1] NUM[2] NUM[3] NUM[4] NUM[5]
NUM[4]
NUM[5]
2.2.2 Initialization of Linear arrays
Initialization is process of assigning values to the elements of an array during declaration. Syntax for
initialization of a linear array is as follows;
data type array_name[size] = { element1, element2, ………,element n};
Example: int NUM[6] = { 57, 38, 98, 75, 25, 97}; will initialize the elements as follows;
57
NUM[0] Will assign the values to elements of the array NUM as follows;
38
NUM[1] NUM[0] = 57 NUM[1] = 38 NUM[2] = 98
98
NUM[2] NUM[3] = 75 NUM[4] = 25 NUM[5] = 75
75
NUM[3] 25
NUM[4]
97
NUM[5]

2.2.3 Operations on arrays


We can perform following operations on a linear array;
1. Traversing: Accessing and processing each element of the array exactly once.
2. Inserting: Adding a new element into the array.
3. Deleting: Removing an element from the array.
4. Sorting: Arranging the elements of an array in some given order.
5. Searching: Finding the location of an element in an array.
6. Merging: Combining the elements of two sorted arrays into a single array.

2.2.4 Arrays as Abstract data type (ADT)


A useful tool for specifying the logical properties of a data type is the abstract data type or ADT.
The term “abstract data type” (ADT) refers to the basic mathematical concept that defines the data
type.
Arrays are defined as ADT's because they are capable of holding contiguous elements in the same
order, and they permit the access for a specific element via index or position.

12
An element is stored in a given index and they can be retrieved at a later time by specifying the same
index. The Array (ADT) have one property, they store and retrieve elements using an index.
Each ADT description consists of two parts:
Data: This part describes the structure of the data used in the ADT in an informal way.
Operations: This part describes valid operations for this ADT, hence, it describes its interface.

2.2.5 Representation of Linear Arrays in memory


Let LA be a linear array stored in the memory of computer. Since the memory of the computer is
simply a sequence of addressed locations, as shown in the figure;
100
0
100
1
100
2
100
3
100
4
100
5
100
6
.
.
. Computer memory
.
Then we use the notation
LOC ( LA[K]) = address of the element LA[K] of the array LA.
The elements of LA are stored in successive memory cells, the computer does not keep track of the
address of every elements of LA, but it keep the track of only the address of the first element of LA
called, the base address of LA and denoted by
Base(LA)
Using this address Base(LA), the computer calculates the address of any element of LA by the
following formula:
LOC (LA[K] ) = Base(LA) + w(K – lower bound)
Where, w is the number of words per memory cell for the array LA.

2.2.6 Traversing Linear Arrays

13
Accessing and processing each element of the array exactly once. Let A be collection of data stored
in the memory of the computer. Suppose we want to print the content of each element of A, or
suppose we want to count the number of elements of A with a given property. This can be done by
traversing A, that is, by accessing and processing each element of A exactly once.

Traversing Algorithm
The following algorithm traverses a linear array LA with lower bound LB, and upper bound UB. It
traverses LA applying an operation PROCESS to each element of LA.

Algorithm: Traversing a Linear Array


Step 1: [Initialize counter.] Set K = LB.
Step 2: Repeat Steps 3 and 4 while K  LB.
Step 3: [Visit element.] Apply PROCESS to LA[K].
Step 4:[Increase counter.] Set K = K + 1.
[End of Step 2 loop.]
Step 5: Exit.
/*Program to perform traversing operation on a linear array */
#include<stdio.h>
main()
{
int i,count=0,n=6;
int a[6]={10, 6, 17, 24, 32};
printf("The array elements are: ");
for(i=0;i<n;i++)
{
printf("a[%d]= %d\n", i, a[i]);
count++;
}
printf(“Number of elements in the array=%d”,count);
}

2.2.7 Inserting and Deleting


Insertion is an operation of adding new element to the linear array, and Deletion is an operation of
removing an element from the linear array.
Inserting an element at the end of a linear array can be easily done if the memory allocated for the
array is large enough to accommodate the new element. On the other hand, suppose the element to
be inserted in the middle of the array. Then, on the average, half of the elements must be moved

14
downward to new locations to accommodate the new element and keep the order of the other
elements.
Similarly, deleting an element at the end of an array have no difficulties, but deleting and element
somewhere in the middle of the array would require that each subsequent element be moved one
location upward in order to fill up the array.

Insertion Algorithm
The following algorithm inserts a data element ITEM into the K th position in a linear array LA with
N elements.
Algorithm: INSERT(LA, N, K, ITEM)
Step 1: [Initialize the counter.] Set J = N.
Step 2: Repeat Steps 3 and 4 while J  N.
Step 3: [Move Jth element downward.]
Set LA[J + 1] = LA[J].
Step 4: [Decrease counter.]
Set J = J – 1.
[End of Step 2 loop.]
Step 5: [Insert element.]
Set LA[K] = ITEM.
Step 6: [Reset N.] Set N = N + 1.
Step 7: Exit.

/*Program to perform insertion operation on a linear array */


#include<stdio.h>
main()
{
static int a[6]={10, 26, 37, 54, 62};
int i,j,k,n=5,item;
printf("The array elements are: ");
for(i=0;i<n;i++)
printf("a[%d]= %d\n", i, a[i]);
j=n;
printf(“Enter the item to be inserted:”);
scanf(“%d”,&item);
printf(“Enter the position of the item:”);
scanf(“%d”,&k);
k = k-1;
while(j>=k)
{
a[j+1] = a[j];
j--;
15
}
a[k] = item;
n = n + 1;
printf("The array elements after insertion are: ");
for(i=0;i<n;i++)
printf("a[%d]= %d\n", i, a[i]);
}
Deletion Algorithm
The following algorithm deletes Kth element from a linear array LA with N elements and assigns it
to variable ITEM.
Algorithm: DELETE(LA, N, K, ITEM)
Step 1: Set ITEM = LA[K].
Step 2: Repeat for J = K to N – 1
[Move (J+1)st element upward.]
Set LA[J] = LA[J + 1].
[End of loop.]
Step 3: [Reset the number N of elements in LA.]
Set N = N – 1.
Step 4: Exit.

/*Program to perform deletion operation on a linear array */


#include<stdio.h>
main()
{
static int a[6]={10, 26, 37, 54, 62};
int i,j,k,n=5,item;
printf("The array elements are: ");
for(i=0;i<n;i++)
printf("a[%d]= %d\n", i, a[i]);
j=n;
printf(“Enter the position of the item:”);
scanf(“%d”,&k);
k = k-1;
item = a[k];
for(j=k; j<n-1; j++)
{
a[j] = a[j+1];
}
n = n - 1;
16
printf(“Deleted element from the array is:%d\n”,item);
printf("The array elements after insertion are: ");
for(i=0;i<n;i++)
printf("a[%d]= %d\n", i, a[i]);
}

2.2.8 Sorting
Sorting refers to the operation of arranging data in some given order, such as increasing or
decreasing, with numerical data or alphabetically, with character data. Sorting is a fundamental
operation and is an important concept that is extremely used in the field of computer science.
Usually sorting is frequently applied to a file of records.
A sort can be classified as being internal if the records that it is sorting are in main memory, or
external if some the records that it is sorting are in auxiliary storage. Usually sorting methods used
for internal sort.
Various sorting methods are;
i. Bubble Sort
ii. Selection Sort
iii. Quick Sort
iv. Insertion Sort
i. Bubble Sort
Bubble sort is also called as exchange sort. It is the simplest and most widely used sorting technique.
One of the characteristics of bubble sort is that it is easy to understand and program, and also it is
probably least efficient sorting method.
Suppose the list of numbers A[1], A[2], ………, A[N] is in memory. The bubble sort algorithm
works as follows:
Step 1: Compare A[1] and A[2] and arrange them in the desired order, so that A[1] < A[2].
Then compare A[2] and A[3] and arrange them so that A[2] < A[3]. Then compare
A[3] and A[4] and arrange them so that A[3] < A[4]. Continue until we compare
A[N – 1] with A[N] and arrange them so that A[N – 1] < A[N].
Here we observe that Step 1 involves n –1comparisons. (During Step 1, the largest element is
“bubbled up” to the nth position or “sinks” to the nth position.) When Step 1 is completed, A[N] will
contain the largest element.
Step 2: Repeat Step 1 with less comparison; that is, now we stop after we compare and
possibly rearrange A[ N –2] and A[N –1]. ( Step 2 involves N –2 comparisons and,
when Step 2 is completed, the second largest element will occupy A[N –1].)

Step 3: Repeat Step 1 with two fewer comparisons; that is, now we stop after we compare

17
and possibly rearrange A[ N –3] and A[N –2].
. ……………………………………………………………………………………….
. ………………………………………………………………………………………
Step N – 1: Compare A[1] and A[2] and arrange them so that A[1] < A[2].
After n – 1 steps, the list be sorted in increasing order.
The process of sequentially traversing through all or part of a list is frequently called a “pass” so
each of the above steps is called a pass. Accordingly, the bubble sort algorithm requires n – 1
passes, where n is the number of input items.
Example: Consider an array with the following elements
32, 51, 27, 85, 66, 23, 13, 57
We apply the bubble sort to sort the array in an ascending order.
Pass 1: We have the following comparisons:
a) Compare 32 and 51: Since 32 < 51, the list is not altered.

b) Compare 51 and 27: Since 51 > 27, interchange 51 and 27 as follows:


32, 27 , 51 , 85, 66, 23, 13, 57
c) Compare 51 and 85: Since 51 < 85, the list is not altered.

d) Compare 85 and 66: Since 85 > 66, interchange 85 and 66 as follows:

32, 27, 51, 66 , 85 , 23, 13, 57


e) Compare 85 and 23: Since 85 > 23, interchange 85 and 23 as follows:

32, 27, 51, 66, 23 , 85 , 13, 57


f) Compare 85 and 13: Since 85 > 13, interchange 85 and 13 as follows:

32, 27, 51, 66, 23, 13 , 85 , 57


g) Compare 85 and 57: Since 85 > 57, interchange 85 and 57 as follows:
32, 27, 51, 66, 23, 13, 57 , 85
At the end of first pass, the largest number 85, has moved to the last position. However, the rest of
the numbers are not sorted.
Pass 2: 27, 32, 51, 66, 23, 13, 57, 85

27, 32, 51, 23 , 66 , 13, 57, 85

27, 32, 51, 23, 13 , 66 , 57, 85

27, 32, 51, 23, 13, 57 , 66 , 85

18
At end of Pass 2, the second largest number, 66, has moved its way down to next-to-last position.
Pass 3: 27, 32, 23 , 51 , 13, 57 , 66 , 85
27, 32, 23, 13 , 51 , 57 , 66 , 85
Pass 4: 27, 23 , 32 , 13, 51, 57, 66 , 85

27, 23, 13 , 32 , 51, 57, 66 , 85


Pass 5: 23 , 27 , 13, 32, 51, 57, 66 , 85

23, 13 , 27 , 32, 51, 57, 66 , 85


Pass 6: 13 , 23 , 27, 32, 51, 57, 66 , 85
Pass 7: Finally, 13 is compared with 23. Since 13 < 23, no interchange takes place.
Since the list has 8 elements; it is sorted after the seventh pass.
A formal presentation of bubble sort is as shown in the following algorithm.

Algorithm: (Bubble Sort) BUBBLE (DATA, N)


Here DATA is an array with N element. This algorithm sorts the elements in
DATA.
Step 1: Repeat Steps 2 and 3 for K = 1 to N – 1.
Step 2: Set PTR = 1. [Initializes pass pointer PTR.]
Step 3: Repeat while PTR  N – K: [Executes pass]
a) If DATA[PTR] > DATA[PTR +1], then:
Interchange DATA[PTR] and DATA[PTR + 1].
[End of If structure.]
b) Set PTR = PTR + 1.
[End of inner loop.]
[End of Step 1 outer loop.]
Step 4: Exit.

ii. Selection Sort


Suppose an array A with n elements A[1], A[2], …….., A[N] is in memory. The selection sort
algorithm for sorting A works as follows. First find the smallest element in the list and put it in the
first position. Then find the second smallest element in the list and put it in second position. And so
on. More precisely:
Pass 1. Find the location LOC of the smallest in the list of N elements.
A[1], A[2], …….., A[N], and then interchange A[LOC] and A[1]. Then:
A[1] is sorted.
Pass 2: Find the location LOC of the smallest in the sublist of N –1 elements
A[2], A[3], …….., A[N], and then interchange A[LOC] and A[2]. Then:
19
A[1], A[2] is sorted, since A[1]  A[2].
Pass 3: Find the location LOC of the smallest in the sublist of N –2 elements
A[3], A[4], …….., A[N], and then interchange A[LOC] and A[3]. Then:
A[1], A[2], A[3] is sorted, since A[2]  A[3].
…… ……………………………………………………………………………..
…… ……………………………………………………………………………..
Pass N-1. Find the location LOC of the smaller of the elements A[N –1], A[N], and then
Interchange A[LOC] and A[N –1]. Then:
A[1], A[2], ………….., A[N] is sorted, since A[N–1]  A[N].

Thus, A is sorted after N–1 passes.

Example: Suppose A is an array with elements;


77 33 44 11 88 22 66 55
We apply Selection sort algorithm to sort the elements of A as follows;
Pass A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8]
K=1, LOC=4 77 33 44 11 88 22 66 55

K=2, LOC=6 11 33 44 77 88 22 66 55

K=3, LOC=6 11 22 44 77 88 33 66 55

K=4, LOC=6 11 22 33 77 88 44 66 55

K=5, LOC=8 11 22 33 44 88 77 66 55

K=6, LOC=7 11 22 33 44 55 77 66 88

K=7, LOC=7 11 22 33 44 55 66 77 88
Sorted 11 22 33 44 55 66 77 88

The Selection sort algorithm is divided into parts. The first past gives a procedure called MIN,
which find the location of smallest element, and the second part uses the procedure SELECTION,
which sorts the array.

Procedure: MIN(A, K, N, LOC)


This procedure finds the location LOC of the smallest element among A.
That is among A[K], A[K+1], ………., A[N].
Step 1: Set MIN = A[K] and LOC = K. [Initializes pointers.]
Step 2: Repeat for J = K + 1, K + 2, ………., N: 20
If MIN > A[J], then: Set MIN = A[J] and LOC = A[J] and LOC = J.
[End of loop.]
Step 3: Return.
Algorithm: (Selection Sort) SELECTION(A, N)
This algorithm sort the array A with N elements.
Step 1: Repeat Steps 2 and 3 for K = 1, 2, ……… N – 1:
Step 2: Call MIN(A, K, N ,LOC).
Step 3: [ Interchange A[K] and A[LOC].]
Set TEMP = A[K], A[K] = A[LOC] and A[LOC] = TEMP.
[End of Step 1 loop.]
Step 4: Exit

iii. Quick Sort


One useful application of stack is to sort a number of data using quick sort algorithm. Quick sort
algorithm is based on divide-and-conquer technique; it is also referred to as the partition exchange
sort. Principle behind the divide and conquer technique is divide a problem into a number of sub-
problems. Again, each sub-problem into number of smaller sub-problems and so on.
In case of quick sort, the list to be sorted is partitioned into two sub-lists so that sorting these two
sub-lists is the sorting of the main list; sorting the sub-list again following the same procedure
recursively.

Example: Let A is the following list of 12 numbers


44 , 33, 11, 55, 77, 90, 40, 60, 99, 22, 88, 66
The reduction step of quicksort algorithm find the final position of one the number; here we use the
first number 44. Beginning with last number 66, scan the list from right to left, comparing each
number with 44 and stopping at the first number less than 44; the number is 22. Interchange 44 and
22 to obtain the list.
22 , 33, 11, 55, 77, 90, 40, 60, 99, 44 , 88, 66
Beginning with 22, next scan the list in the opposite direction, from left to right, comparing each
number with 44 and stopping at the first number greater than 44; the number is 55. Interchange 44
and 55 to obtain the list.
22 , 33, 11, 44 , 77, 90, 40, 60, 99, 55 , 88, 66
Beginning this time with 55, now scan the list in the original direction, from right to left, until
meeting the first number less than 44; it is 40. Interchange 44 and 40 to obtain the list.
22, 33, 11, 40 , 77, 90, 44 , 60, 99, 55 , 88, 66
Beginning with 40, scan the list from left to right, the number greater than 44 is 77. Interchange 44
and 77 to obtain the list.
22, 33, 11, 40, 44 , 90, 77 , 60, 99, 55 , 88, 66

21
Beginning with 77, scan the list from right to left, seeking a number less than 44. We do not meet
such a number before meeting 44. This means all numbers have been scanned and compared with
44. All the numbers less than 44 on the left form one sublist, and all numbers greater than 44 on the
right side forms another sublist as shown below.
22, 33, 11, 40, 44 , 90, 77, 60, 99, 55 , 88, 66

Thus, 44 is correctly placed in its final position, and the task of sorting the original list A has now
been reduced to the task of sorting each of the above sublists.
The above reduction step is repeated with each sublist containing 2 or more elements. Since we can
process only one sublist at a time, we must be able to keep track of some sublists for future
processing. This is accomplished by using two tasks, called LOWER and UPPER, to temporarily
“hold” such sublists. This is, the addresses of the first and last elements of each sublist, called its
boundary values, are pushed onto the stacks LOWER and UPPER, respectively; and the reduction
step is applied to a sublist only after its boundary values are removed from the stacks.

Quick Sort Algorithm: The quicksort algorithm is divided into two parts. The first part gives a
procedure called QUICK, which executes the reduction step and the second part uses the procedure
sort the entire list.
Procedure: QUICK(A, N, BEG, END, LOC)
Step 1: [Initialize.] Set LEFT = BEG, RIGHT = END and LOC = BEG.
Step 2: [Scan from the right to left.]
a) Repeat while A[LOC]  A[RIGHT] and LOC  RIGHT:
RIGHT = RIGHT – 1.

b) If LOC = RIGHT, then: Return.


c) If A[LOC] > RIGHT, then:
i) [Interchange A[LOC] and A[RIGHT].]
TEMP = A[LOC], A[LOC] = A[RIGHT], A[RIGHT] = TEMP.
ii) Set LOC = RIGHT
iii) Go to Step 3.
Step 3: [Scan from left to right.]
a) Repeat while A[LEFT]  A[LOC] and LEFT  LOC:
LEFT = LEFT + 1.
[End of loop]
b) If LOC = LEFT, then: Return.
c) If A[LEFT] > A[LOC], then:
i) [Interchange A[LEFT] and A[LOC] .]
TEMP = A[LOC] , A[LOC] = A[LEFT], A[LEFT] = TEMP.
ii) Set LOC = LEFT.
iii) Go to Step 2.
Algorithm: (Quicksort) This algorithm sorts an array A with N elements
Step 1: [Initialize] TOP = NULL.
Step 2: [Push boundary values of A onto stacks when A has 2 or more elements.] 22
If N > 1, then: TOP = TOP + 1, LOWER[1] = 1, UPPER[1] = N.
Step 3: Repeat Steps 4 to 7 while TOP  NULL.
Step 4: [Pop sublist from stacks.]
iv. Insertion Sort
Suppose an array A with n elements a[1], a[2], ……., A[N] is in memory. The insertion sort
algorithm scans A from A[1] to A[N], inserting each element A[K] into its proper position in the
previously sorted subarray A[1], A[2], ……., A[K – 1]. That is:

Pass 1. A[1] by itself is trivially sorted.


Pass 2. A[2] is inserted either before or after A[1] so that: A[1], A[2] is sorted.
Pass 3. A[3] is inserted into its proper place in A[1], A[2], that is, before A[1], between
A[1] and A[2], or after A[2], so that: A[1], A[2], A[3] is sorted.
Pass 4. A[4] is inserted into its proper place in a[1], A[2], A[3] so that:
A[1], A[2], A[3], A[4] is sorted.
……………………………………………………………………………………………….
Pass N. A[N] is inserted into its proper place in A[1], A[2], ………., A[N – 1] so that:
A[1], A[2], A[3], ……….., A[N] is sorted.

Example: Suppose A is an array with elements;


77 33 44 11 88 22 66 55
We apply insertion sort algorithm to sort the elements of A as follows;

23
Pass A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8]
K=1 -∞ 77 33 44 11 88 22 66 55

K=2 -∞ 77 33 44 11 88 22 66 55

K=3 -∞ 33 77 44 11 88 22 66 55

K=4 -∞ 33 44 77 11 88 22 66 55

K=5 -∞ 11 33 44 77 88 22 66 55

K=6 -∞ 11 33 44 77 88 22 66 55

K=7 -∞ 11 22 33 44 77 88 66 55

K= 8 -∞ 11 22 33 44 66 77 88 55
Sorted -∞ 11 22 33 44 55 66 77 88

To implement insertion sort algorithm, a sentinel element A[0] = -∞ (or very small number) used.
The insertion sort algorithm scans A from A[1] to A[N], inserting each element A[K] into its proper
position in previously sorted sub array A[1], A[2], ……, A[ K-1].

This sorting algorithm is frequently used when n is small. For example, this algorithm is very
popular with bridge players when they are first sorting their cards.
Algorithm: (Insertion Sort) INSERTION(A, N).
This algorithm sorts the array A with N elements
Step 1: Set A[0] = –. [Initializes sentinel element.]
Step 2: Repeat Steps 3 to 5 for K = 2, 3, ………., N
Step 3: Set TEMP = A[K] and PTR = K – 1.
Step 4: Repeat while TEMP < A[PTR]:
a) Set A[PTR + 1 ] = A[PTR]. [Moves element forward.]
b) Set PTR = PTR – 1.
[End of loop.]
Step 5: Set A[PTR + 1] = TEMP. [ Inserts element in proper place.]
[End of step 2 loop]
Step 6: Return.

2.2.9 Searching

24
Searching refers to finding the location of the record with a given value, or finding the locations of
all records which satisfy one or more conditions. It is one of the fundamental operations in
computer science and it frequently applied to a file of records.
Let DATA be a collection of data elements in memory, and suppose a specific ITEM of information
is given. Searching refers to the operation of finding the location of LOC of ITEM in DATA, or
printing some message that ITEM does not appear there. The search is said to be successful if ITEM
does appear in DATA and unsuccessful otherwise.
There are many different searching algorithms. The algorithm that one chooses generally depends
on the way the information in DATA is organized. Two important searching algorithms are linear
search, and binary search.

Linear Search (Sequential Search)


Suppose DATA is a linear array with n elements. Let ITEM be element whose location in DATA to
be searched. The ITEM will be compared with element of DATA one by one. That is, first we test
whether DATA[1] = ITEM, and then we test whether DATA[2] = ITEM, and so on. This
method, traverses DATA sequentially to locate ITEM, is called linear search or sequential search.
To simplify the matter, we first assign ITEM to DATA[N+1], the position following the last element
of DATA. Then we update
LOC = N + 1
where, LOC denotes the location where ITEM first occurs in DATA, signifies the search is
unsuccessful. The purpose of this initial assignment is to avoid repeatedly testing whether or not we
have reached the end of the array DATA. This way, the search must eventually “succeed”.

A formal presentation of linear search is as shown in the following algorithm.


Algorithm: (Linear Search) LINEAR (DATA, N, ITEM, LOC)
Here DATA is a linear array with N elements, and ITEM is a given item of
information. This algorithm finds the location LOC of ITEM in DATA, or sets
LOC = 0 if the search is unsuccessful.
Step 1: [Insert ITEM at the end of DATA.] Set DATA [ N+1] = ITEM.
Step 2: [Initialize counter.] Set LOC = 1.
Step 3: [Search for ITEM]
Repeat while DATA [LOC]  ITEM:
Set LOC = LOC + 1.
[End of loop.]
Step 4: [Successful?] If LOC = N + 1, then: Set LOC = 0.
Step 5: Exit.

Binary Search

25
Suppose DATA is an array which is sorted in increasing numerical order or, equivalently,
alphabetically. Then there is an extremely efficient searching algorithm, called binary search, which
can be used find the location LOC of a given ITEM of information in DATA.
The binary search algorithm applied to the array DATA works as follows. During each stage of the
algorithm, the search for ITEM is reduced to a segment of elements of DATA:
DATA[BEG], DATA[BEG + 1], DATA[BEG + 2] …….. DATA[END]
The variables BEG and END denotes, respectively, the beginning and end location of the segment
under consideration. The algorithm compares ITEM with the middle element DATA[MID] of the
segment, where MID is obtained by
MID = INT ( ( BEG + END ) / 2 )
,

If DATA[MID] = ITEM, then the search is successful and we set LOC = MID. Otherwise a new
segment of DATA is obtained as follows:
i. If ITEM < DATA[MID], then ITEM can appear only in the left half of the segment:

DATA[BEG], DATA[BEG + 1], ………, DATA[MID –1]


So we reset END = MID – 1 and begin searching again.
ii. If ITEM > DATA[MID], then ITEM can appear only in the half of the segment:

DATA[MID + 1], DATA[MID + 2], ……….., DATA[END]


So we reset BEG = MID + 1 and begin searching again.
Initially, we begin with the entire array DATA; i.e., we begin with BEG = 1 and END = n, or, more
generally, with BEG = LB and END = UB.
(Where, LB and UB, denotes, respectively, the lower bound and upper bound of the DATA.)
If ITEM is not in DATA, then eventually we obtain
END < BEG
This condition signals that the search is unsuccessful, and in such a case we assign LOC= NULL.
Here NULL is a value that lies outside the set of indices of DATA.
A formal presentation of binary search is as shown in the following algorithm.
Algorithm: ( Binary Search) BINARY(DATA, LB, UB, ITEM, LOC)
Here DATA is a sorted array with lower bound LB and upper bound UB, and
ITEM is a given item of information. The variables BEG, END and MID denote,
respectively, the beginning, end and middle locations of a segment of elements
of DATA. This algorithm find the location LOC of ITEM in DATA or sets
LOC = NULL.
Step 1: [initialize segment variables]
Set BEG = LB, END = UB and MID = INT( ( BEG + END) / 2 )
Step 2: Repeat Steps 3 and 4 while BEG  END and DATA[Mid]  ITEM.
Step 3: If ITEM < DATA[MID], then:
Set END = MID – 1.
Else: 26
Set BEG = MID + 1.
Step 4: Set MID = INT( ( BEG + END) / 2 ).
[End of Step 2 loop.]
Example: Let DATA be the array with following sorted 13-elements:
DATA: 10, 15, 23, 30, 35, 38, 40, 45, 50, 55, 65, 77, 88
We apply the binary search to DATA for different values of ITEM.
a) Suppose ITEM = 35. The search for ITEM in the array DATA is as shown in figure(a), where
the values of DATA[BEG] and DATA[END] in each stage of the algorithm are indicated by
circles and the value of DATA[MID] by a square.
1. Initially, BEG = 1 and END = 13. Hence
MID = INT[(1 + 13) / 2] = 7 and so DATA[MID] = 40
2. Since 35 < 40, END has its value changed by END = MID – 1 = 6. Hence
MID = INT[(1 + 6) / 2] = 3 and so DATA[MID] = 23
3. Since 35 > 23, BEG has its value changed by BEG = MID + 1 = 4. Hence
MID = INT[(4 + 6) / 2] = 5 and so DATA[MID] = 35
We have found ITEM in location LOC = MID = 5.
1. 10 , 15, 23, 30, 35, 38, 40 , 45, 50, 55, 65, 77, 88

2. 10 , 15, 23 , 30, 35, 38 , 40, 45, 50, 55, 65, 77, 88


3. 10, 15, 23, 30 , 35 , 38 , 40, 45, 50, 55, 65, 77, 88 [Successful]

Figure(a) Binary search for ITEM = 35.


Comparison between Linear Search and Binary Search
Linear Search Binary Search
1. Linear search can be used with unsorted 1. Binary search can be used only with sorted
data. data.

2. It searches the given ITEM with each 2. It searches the given ITEM in the list, by
item of the list until a match occurs. reducing the elements of the list into segments.

3. Linear search is sequential. 3. Binary search is recursive.

4. It is one of the crudest search methods. 4. It is one the efficient search method.
27
2.3 Multi-Dimensional Arrays
Multi-dimensional arrays are classified into two-dimensional arrays, three-dimensional arrays and
so on N-dimensional arrays.

2.3.1 Two-Dimensional Arrays


A two-dimensional array is a collection of m x n data elements, such that each element is specified a
pair of integers J and K with the properties that
1Jm
1Kn
If the elements of two-dimensional array A has first subscript J and second subscript K then it will
be A[J,K]. Two-dimensional arrays are called matrices or matrix arrays.
2.3.2 Declaration of Two-Dimensional Arrays
A two-dimensional array can be declared in C as follows;
data type array_name [rows][columns];
where, rows number of elements to be processed under first subscript.
Columns number of elements to be processed under second subscript.
Examples: int marks[5][5];
float salary[5][5];

2.3.2 Initialization of Two-Dimensional Arrays


A two-dimensional array elements can be initialized at the time of declaration as follows;
data type array_name [rows][columns]={element1, element2,…… element2};
Examples: int matrix[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
will initialize the array matrix as follows;
matrix[0][0]=1 matrix[0][1]=2 matrix[0][3]=3
matrix[1][0]=4 matrix[1][1]=5 matrix[1][3]=6
matrix[2][0]= 7 matrix[2][1]=8 matrix[2][2]=9
2.3.2 Accessing Elements of Two-Dimensional Arrays
Elements in Two-Dimensional arrays are accessed using the row indexes and column indexes.
Example: int NUM[2][1];
The above example represents the element present in the third row and second column.
2.3.3 Representation of Two-Dimensional Arrays
Let A be a two-dimensional array 3x4 elements, then array A will represented in computer memory
in any one of the following two forms;
1. A column by column called column-major as shown in figure (a)
2. A row by row called row-major as shown in figure (b).

28
figure(a) figure(b)

2.3.4 Sparse Matrices


A matrix with a relatively high proportion of zero entries is called sparse matrix.
OR
A matrix that has the majority of its elements equal to zero is called sparse matrix.
OR
A sparse matrix can be defined as the matrix that has a greater number of zero elements than the
non-zero elements.

Uses of Sparse Matrix instead of simple matrix


 Storage: There are lesser non-zero elements than zeros and thus lesser memory can be used to
store only those elements.
 Computing time: Computing time can be saved by logically designing a data structure
traversing only non-zero elements.
Example:
0 0 30 4
0 0 57 0
0 0 0 08
0 2 6 00

UNIT – 3: Dynamic Memory Allocation


3.1 Static and Dynamic Memory Allocations
Memory allocation is the process of reserving a partial or complete portion of computer memory for
the execution of programs and processes. It is one of the important concepts in programming. The
allocation is done either before or at the time of program execution. Memory allocations are of two
types;
1. Static memory allocation
2. Dynamic memory allocation

29
3.1.1 Static Memory Allocation
The memory allocated during compile-time is called static memory allocation. The static memory is
allocated for the variables declared in a program by the compiler. This is done before program
execution. In static memory allocation, once the memory allocated, we cannot change its size.

3.1.2 Dynamic Memory Allocation


The memory allocated during run-time is called dynamic memory allocation. The programs are
allocated with memory at run-time. In dynamic memory allocation, we can change the memory size.
This allows reusing and releasing the memory when the user needs it.

3.1.3 Difference between Static and Dynamic Memory Allocation


Sl. No. Static Memory Allocation Dynamic Memory Allocation

1. The memory is allocated at the compile time The memory is allocated at the runtime
2. Static memory cannot be changed during Dynamic memory can be changed during
program execution program execution
3. In the static memory allocation, variables get In the Dynamic memory allocation,
allocated permanently, till the program variables get allocated only if your
executes or a function call finishes. program unit gets active
4. There is no memory re-usability in static There is memory re-usability and memory
memory allocation can be freed when not required
5. It saves running time as it is fast It is slower than static memory allocation
6. It is less efficient as compared to Dynamic It is more efficient as compared to the
memory allocation Static memory allocation
7. This memory allocation is simple This memory allocation is complicated
8. Static memory allocation allots memory from Dynamic memory allocation allots memory
the stack from the heap
9. Static memory allocation is preferred in an Dynamic memory allocation is preferred in
array the linked list

3.2 Dynamic Memory Allocation Functions


The concept of dynamic memory allocation enables the programmer to allocate the memory
during runtime. That is, the size of a data structure can be changed during program
execution.
C provides 4 library functions to facilitate dynamic memory allocation. These functions are
defined under <stdlib.h> header file. They are:
1. malloc( )
2. calloc( )
30
3. realloc( )
4. free( )

1. The malloc( ) function


The name "malloc" stands for memory allocation. In C, it is used to dynamically allocate a single
block of memory with the specified size. It returns a pointer of type void which can be cast into a
pointer of any form.
Syntax: ptr = (cast-type*) malloc(byte-size) ;
Example: ptr = (int *) malloc(10 * sizeof(int));
The above statement allocates 20 bytes of memory. It's because the size of int is 2 bytes. And, the
pointer ptr holds the address of the first byte in the allocated memory.

2. The calloc( ) function


The name "calloc" stands for contiguous allocation. In C, it is used to dynamically allocate the
specified number of blocks of memory of the specified type. It is very much similar to malloc( )
but has two different points and these are:
 It initializes each block with a default value ‘0’.
 It has two parameters or arguments as compare to malloc( ).
Syntax: ptr = (cast-type*) malloc(n, element-size) ;
Here, n is the number of elements and element-size is the size of each element.
Example: ptr = (float*) calloc(25, sizeof(float));

It allocates contiguous space in memory for 25 elements each with the size of the float.

3. The realloc( ) function


The “realloc” or “re-allocation” function in C is used to dynamically change the memory
allocation of a previously allocated memory. In other words, if memory is not sufficient for
malloc( ) or calloc( ), we can reallocate the memory by using realloc( ) function. In short, it changes
the memory size.
Syntax: ptr = realloc(ptr, newsize);
where, ptr is reallocated with new size 'newsize'.
Example: ptr = realloc (ptr, 40);

4. The free ( ) function


The “free” function in C is used to dynamically de-allocate the memory. The memory allocated
using functions malloc() and calloc() is not de-allocated on their own. Hence the free( ) method is
used, whenever the dynamic memory allocation takes place. It helps to reduce wastage of memory
by releasing or freeing it.
Syntax: free (ptr);

31
This statement frees the space allocated in the memory pointed by ptr.

3.3 Linked Lists


3.3.1 Introduction
Array is a data structure where elements are stored in consecutive memory locations. In order to
occupy the adjacent space, block of memory that is required for the array should be allocated
beforehand. Once memory is located it cannot be extended any more. This is why array is known
as static data structure. In contrast to this, linked list is called dynamic data structure where amount
of memory required can be varied during its use. In linked list, adjacency between the elements is
maintained by of links or pointers. A link or pointer actually is the address (memory location) of the
subsequent element. Thus, in a linked list, data (actual content) and link (to point to the next data)
both are required to be maintained.
3.3.2 Definition: A linked list, or one-way list, is a linear collection of data elements, called nodes,
where the linear order is given means of pointers. That is, each node is divided into two parts as
shown in the following figure(1).

Information Link
Figure (1)

The first part contains the information of the element, and the second part, called the link field or
nextpointer field, contains the address of the next node in the list.
The figure(2), is a schematic diagram of a linked list, with 6 nodes. Each node is pictured with 2
parts. The left part represents the information part of the node, which may contain an entire record
of data items. The right part represents the next pointer field of the node. The pointer of the last
node contains, a special value, called the null pointer, which is any invalid address. The null pointer
is denoted by x in the diagram. The linked list also contains a list pointer variable called START to
point the first node in the list.
START

Next pointer field of third node


Information part of third node
Figure (2)

Example:
A hospital ward contains 12 beds, of which 9 are occupied as shown in the figure. Suppose we want
an alphabetical listing of the patients; this may be given by the pointer field, called Next in the
figure. We use the variable START to point to the first patient. Hence START contains 5, since the
first patient, AAA, occupies bed 5. Also AAA’s pointer is equal to 3, since DDD, the next patient,

32
occupies bed 3; DDD’s pointer is 11, since FFF, the next patient, occupies bed 11; and so on. The
entry for the last patient (SSS) contains the null pointer, denoted by 0.

START

Bed Patient Next


Numbe
r 7
1 KKK
2 11
3 DDD 12
4 MMM 3
5 AAA
6 4
7 LLL 1
3.3.3 8 GGG 0 Advantages of Linked Lists
 9 SSS Dynamic data structure: A linked list is a dynamic
10 8 arrangement so it can grow and shrink at runtime by
11 FFF 9 allocating and deallocating memory. So there is no need
to 12 NNN give the initial size of the linked list.
 No memory wastage: In the Linked list, efficient memory utilization
can be achieved since the size of the linked list increase or decrease at run time so there is no
memory wastage and there is no need to pre-allocate the memory.
 Implementation: Linear data structures like stack and queues are often easily implemented
using a linked list.
 Insertion and Deletion Operations: Insertion and deletion operations are quite easier in the
linked list. There is no need to shift elements after the insertion or deletion of an element only
the address present in the next pointer needs to be updated.
3.3.4 Disadvantages of Linked Lists
 Memory usage: More memory is required in the linked list as compared to an array. Because
in a linked list, a pointer is also required to store the address of the next element and it requires
extra memory for itself.

3.4 Types of Linked Lists


Linked lists are classified as follows;
1. Singly linked list
2. Doubly linked list
3. Header linked list
4. Circular linked list
3.4.1 Singly linked list

33
It is the simplest type of linked list in which every node is divided into two parts called,
information field and next pointer field. The next pointer field means that the node stores the
address of the next node in the sequence. A single linked list allows the traversal of data only in
one way.

START

Next pointer field of third node


Information part of third node

3.4.2 Doubly linked list


A doubly linked list is a linear collection of data elements called nodes, where each node N is
divided into 3 parts;
i. An information field INFO which contains data of node N.
ii. A pointer field FORW(forward) which contains the location of next node in the list.
iii. A pointer field BACK(backward) which contains the location of preceding node in the list.

FIRST LAST
 BACK pointer field of Node N 
INFO field of Node N
FORW field of Node N

x x

Here, we observe that a NULL pointer appears in the FORW field in the last node, and for BACK
field it appears in the first field.
Advantages of Doubly Linked Lists
 Using doubly linked list is we can traverse the list in both directions.
 Insertion and deletion operations can be made very easily.
 Doubly linked lists are used to represent binary trees.

Disadvantages of Doubly Linked Lists


 Extra memory is required to store backward pointer as well as extra time is required to
change the pointer.

3.4.3 Header linked list


A header linked list is a linked list which always contains a special node called header node at the
beginning of the list. There are two types of header linked lists;
1. Grounded header linked list
2. Circular header linked list
34
1. Grounded Header Linked list
It is a header linked list whose last node contains a null pointer, called grounded header linked list.

2. Circular header linked list


It is header linked list whose last node points back to the first node instead of containing a null
pointer.
START

Header node

3.4.4 Circular linked list


A linked list whose last node points back to the first node instead of containing a null pointer is
called circular linked list.
START

Advantages of Circular Linked Lists


 In a circular linked list, every node is accessible from a given node. That is, from a given
node, a node can be reached by merely chaining the list.
 Concatenation and splitting operations are more efficient.
 Here, null pointers are not used and hence all the pointers contain valid addresses.

Disadvantages of Circular Linked Lists


 Since circular linked list do not have beginning and end nodes that may cost to get into an
infinite list during processing.
35
3.5 Representation of Singly Linked lists in memory
Let LIST be a linked list, then LIST will be maintained in memory using 2 arrays called, INFO and
LINK such that INFO[K] and LINK[K] contains the information part and the next pointer field of a
node of LIST respectively. The LIST also requires a variable name such as START, which contains
the location of the beginning of the list and it also contain invalid address in the last node indicating
the termination of the list.

Example: The following figure shows a linked list in memory where each node of the list contains a
single character
INFO LINK
START 1
9 2
3 O 6
4 T 0
5
6 K 11
7 X 10
8
9 N 3
10 I 4
11 E 7
12

We can obtain the actual list of characters as follows


START = 9, So INFO[9] = N is the first character
LINK[9] = 3, So INFO[3] = O is the second character
LINK[3] = 6, So INFO[6] = K is the third character
LINK[6] = 11, So INFO[11] = E is the fourth character
LINK[11] = 7, So INFO[7] = X is the fifth character
LINK[7] =10, So INFO[10] = I is the sixth character
LINK[10] = 4, So INFO[4] = T is the seventh character
LINK[4] = 0, the NULL value, so the list has ended.

3.6 Operations on Singly Linked Lists


3.6.1 Traversing a Linked List
Traversing refers to accessing each of the nodes of the linked list exactly once. Let LIST be linked
list in memory stored in linear arrays INFO and LINK with START pointing to the first element and
NULL indicating the end of the LIST. Traversing refers to processing each node exactly once. The

36
traversing algorithm uses a pointer variable PTR which points to the node that currently being
processed.
Accordingly, LINK[PTR] points to the next node to be processed. Thus assignment
PTR = LINK[PTR]
moves the pointer to the next node in the list, as shown in the following figure.
PTR

Traversing Algorithm: The details of the algorithm are as follows;


Initialize PTR to STRAT. Then process INFO[PTR], the information at the first node. Update PTR
by the assignment PTR = LINK[PTR], so that PTR points to the second node. Then process
INFO[PTR], the information at the second node. Again updated PTR by assignment
PTR = LINK[PTR], and then process INFO[PTR], the information at the third node. And so on.
Continue until PTR = NULL, which signals the end of the list.
Algorithm: Traversing a Linked List
Step 1: Set PTR = START [Initializes pointer PTR]
Step 2: Repeat steps 3 and 4 while PTR  NULL
Step 3: Apply PROCESS to INFO[PTR]
Step 4: Set PTR = LINK[PTR] [ PTR now points to the next node]
[End of step 2 loop]
Step 5: return
i. Procedure to print the information at each node of a linked list
Procedure: PRINT(INFO, LINK,START)
Step 1: Set PTR = START
Step 2: Repeat steps 3 and 4 while PTR  NULL
Step 3: Write: INFO[PTR]
Step 4: Set PTR = LINK[PTR] [Updates the pointer]
[End of step 2 loop]
Step 5: return

ii. The following procedure finds the number NUM of elements in a linked list
Procedure: COUNT(INFO, LINK,START,NUM)
Step 1: NUM = 0 [Initializes counter]
Step 2: Set PTR = START [Initializes pointer]
Step 3: Repeat steps 4 and 5 while PTR  NULL
Step 4: NUM = NUM + 1 [Increases NUM by 1]
Step 5: Set PTR = LINK[PTR] [Updates the pointer]
[End of step 3 loop] 37
Step 5: return
3.6.2 Searching in a Linked List
Searching refers to finding the location of the node in the linked list. There are two searching
methods;
i. Searching in unsorted linked list ii. Searching in sorted linked list.
i) LIST is unsorted
Let LIST be linked list in memory. If a specific ITEM of information is given. Searching refers to
find the location LOC of the node where ITEM first appears in LIST.
Suppose the data in LIST are not sorted. Then one searches for ITEM in LIST by traversing through
the list using a pointer variable PTR and comparing ITEM with the elements INFO[PTR] of each
node, one by one, of LIST. Before we update the pointer PTR by PTR = LINK[PTR] we require
two tests. First we have to check to see whether we have reached the end of the list. i.e. first we
check to see whether PTR = NULL. If not, then we check to see whether INFO[PTR] = ITEM.
Searching Algorithm (Unsorted)
The following algorithm find the location LOC of the node where the ITEM first appears in a linked
list called LIST or sets LOC = NULL.
Algorithm: SEARCH (INFO, LINK, START, ITEM, LOC)
Step 1: Set PTR = START
Step 2: Repeat step 3 while PTR  NULL
Step 3: If ITEM = INFO[PTR] then:
Set LOC = PTR and Exit
Else: Set PTR = LINK[PTR]. [PTR now points to the next node.]
[End of step 2 loop]
Step 4: [Search is unsuccessful?] Set LOC = NULL
Step 5: Exit

ii) LIST is sorted


Suppose the data in LIST are sorted. Again we search for ITEM in LIST by traversing the list using
a pointer variable PTR and comparing ITEM with the contents INFO[PTR] of each node, one by one
of LIST. However, we can stop once ITEM exceeds INFO[PTR].
Searching Algorithm (Sorted)
The following algorithm find the location LOC of the node where the ITEM first appears in a linked
list called LIST or sets LOC = NULL.
Algorithm: SEARCHSL (INFO, LINK, START, ITEM, LOC)
Step 1: Set PTR = START
Step 2: Repeat step 3 while PTR  NULL
Step 3: If ITEM < INFO[PTR] then:
Set PTR = LINK[PTR]. [PTR now points to the next node.]
Else if ITEM = INFO[PTR] then:
Set LOC = PTR and Exit [Search is successful]
Else: Set LOC = NULL, and exit. [ITEM now exceeds INFO[PTR]. ]
[End of If structure]
38
[End of step 2 loop]
Step 4: Set LOC = NULL
Step 5: Exit
3.6.3 Insertion into a Linked List
Let LIST be linked list with successive nodes A and B as shown in figure 1(a). Suppose a node N is
to be inserted into the list between nodes A and B. The schematic diagram of such an insertion
appears in figure 2(b). That is, node A now points to the new node N, and node N points to node B,
to which A previously pointed. Suppose list is in memory in the form
LIST(INFO, LINK, START, AVAIL).
START

Node A Node B
x

Figure 1(a) Before insertion


START

Node A Node B
x

Node N
Figure 2 (b) After insertion
The above figure does not take into account into that memory space for the new node N will come
from the AVAIL list. Specifically, for easier processing, the first node in the AVAIL list be used for
the new node N. Thus a more exact schematic diagram of such an insertion is that in figure 2.
Here we observe that three pointer fields are changed as follows:
1. The nextpointer field of node A now points to the new node N, to which AVAIL previously
pointed.
2. AVAIL now points to the second node in the free pool, to which node N previously pointed.
3. The nextpointer field of node N now points to node B, to which node A previously pointed.
START Data list

Node A Node B
x

AVAIL

39
Node N
x

Free-storage list
Insertion Algorithms
Algorithms which insert into linked lists come up in various situations. We can insert a node in two
different ways. The first one inserts a node at beginning of the list, and the second one inserts a node
the node with a given location. All the algorithms assume that the list is in memory in the form
LIST(INFO, LINK, START, AVAIL) and the variable ITEM contains the new information to be
added to the list.

Inserting at the Beginning of a list


Suppose we want to insert a new node into a linked list, then the easiest way to insert the node at the
beginning of the list. The following Algorithm does this.

Algorithm: INSFIRST (INFO, LINK, START, AVAIL, ITEM)


This algorithm inserts ITEM as the first node in the list
Step 1: [OVERFLOW?] If AVAIL = NULL, then: Write OVERFLOW, and Exit.
Step 2: [Remove first node from AVAIL list.]
Set NEW = AVAIL and AVAIL = LINK[AVAIL].
Step 3: Set INFO[NEW] = ITEM. [Copies new data into new node.]
Step 4: Set LINK[NEW] = START. [New node now points to original first node.]
Step 5: Set START = NEW. [Changes START so it points to the new node.]
Step 6: Exit.
Inserting after a Given Node
Suppose we are given the value of LOC where either LOC is the location of a node A in a linked
LIST or LOC = NULL. The following is an algorithm which inserts ITEM into LIST so that ITEM
follows node A or, when LOC = NULL, so that ITEM is the first node.
Let N denote the new node (whose location is NEW). If LOC = NULL, then N is inserted as the
first node in LIST. Otherwise, the node N point to node B (which originally followed node A), by
the assignment
LINK[NEW] = LINK[LOC]
and we let node A point to the new node N by the assignment
LINK[LOC] = NEW

Algorithm: INSLOC (INFO, LINK, START, AVAIL, LOC, ITEM)


This algorithm inserts ITEM so that ITEM follows the node with location LOC or
inserts ITEM as the first node when LOC = NULL.
Step 1: [OVERFLOW?] If AVAIL = NULL, then: Write OVERFLOW, and Exit.
Step 2: [Remove first node from AVAIL list.]
Set NEW = AVAIL and AVAIL = LINK[AVAIL].
Step 3: Set INFO[NEW] = ITEM. [Copies new data into new node.]
Step 4: If LOC = NULL, then: [Insert as first node.]
Set LINK[NEW] = START and START =NEW 40
Else: [Insert after node with location LOC.]
Set LINK[NEW] = LINK[LOC] and LINK[LOC] = NEW.
[End of If structure]
3.6.4 Deletion from a Linked List
Let LIST be linked list with a node N between nodes A and B as shown in figure 1(a). Suppose a
node N is to be deleted from the linked list. The schematic diagram of such a deletion appears in
figure 2(b). The deletion occurs as soon as the nextpointer field of node A is changed so that it node
N points to node B, to which A previously pointed. Suppose list is in memory in the form
LIST(INFO, LINK, START, AVAIL).

START

Node A Node N Node B


x

Figure 1(a) Before deletion


START

Node A Node N Node B


x

Figure 1 (b) After deletion


The above figure does not take into account the fact that, when a node N is deleted from the list, we
will immediately return its memory space to the AVAIL list. Specifically, for easier processing, it
will be returned to the beginning of AVAIL list. Thus a more exact schematic diagram of such a
deletion is as in figure 2.
Here we observe that three pointer fields are changed as follows:
1. The nextpointer field of node A now points to the new node B, where node N previously
pointed.
2. The nextpointer field of node N now points to the original first node in the free pool, where
AVAIL previously pointed.
3. AVAIL now points to the deleted node N.
START Data list

Node A Node N Node B


x

AVAIL
41
x

Free-storage list

Deletion Algorithms
Algorithms which delete nodes from linked lists come up in various situations. We can delete a
node in two different ways. The first one deletes the node following a given node, and the second
one deletes the node with a given ITEM of information. The algorithms assume that the linked list
is in memory in the form LIST (INFO, LINK, START, AVAIL).

Deleting the Node Following a Given Node


Let LIST be a linked list in memory. Suppose we are given the location LOC of a node N in LIST.
Furthermore, suppose we are given the location LOCP of the node preceding N or, when N is the
first node, we are given LOCP = NULL. The following algorithm deletes N from the list.

Algorithm: DEL (INFO, LINK, START, AVAIL, LOC, LOCP)


This algorithm deletes the node N with location LOC. LOCP is the location of
the node which precedes N or, when N is the first node, LOCP = NULL
Step 1: If LOCP = NULL, then:
Set START = LINK[START]. [Deletes first node.]
Else:
Set LINK[LOCP] = LINK[LOC]. [Deletes node N.]
[End of If structure]
Step 2: [Return deleted nod to the AVAIL list.]
Set LINK[LOC] = AVAIL and AVAIL = LOC.
Step 3: Exit.

Deleting the Node with a Given ITEM of Information.


Let LIST be a linked list in memory. Suppose we are given an ITEM of information and we want to
delete from the LIST the first node N which contains ITEM. (If ITEM is a key value, then only one
node can contain ITEM). Before we delete N from the list, we need to know the location of the node
preceding N. Accordingly, first we give a procedure which finds the location LOC node, we set
LOCP = NULL, and if ITEM does not appear in LIST, we set LOC = NULL.

Algorithm: DELETE (INFO, LINK, START, AVAIL, ITEM)


This algorithm deletes from a linked list the first node N which contain the given
ITEM of information
Step 1: Call FINDB (INFO, LINK, START, ITEM, LOC, LOCP)
Step 2: If LOC = NULL, then: Write: ITEM not in list, and Exit.
Step 3: [Delete node.]
If LOCP = NULL, then:
Set START = LINK[START]. [Deletes first node.]
Else: 42
Set LINK[LOCP] = LINK[LOC].
[End of If structure]
Step 4: [Return deleted node to the AVAIL list.]
3.7 Garbage Collection
In computer science, garbage collection is a form of automatic memory management. It is a dynamic
approach to automatic memory management and heap allocation that processes and identifies dead
memory blocks and reallocates storage for reuse. The primary purpose of garbage collection is to
reduce memory leaks. It is a feature that simplifies the programmer's job by reducing manual heap
allocation management.

The garbage collector (GC) manages the allocation and release of memory. The garbage collector
serves as an automatic memory manager. That means the programmers do not need to know how to
allocate and release memory or manage the lifetime of the objects that use the memory.
GC implementation requires three primary approaches, as follows:

 Mark-and-sweep: In process when memory runs out, the GC locates all accessible memory
and then reclaims available memory.

 Reference counting: Allocated objects contain a reference count of the referencing number.
When the memory count is zero, the object is garbage and is then destroyed. The freed
memory returns to the memory heap.

 Copy collection: There are two memory partitions. If the first partition is full, the GC locates
all accessible data structures and copies them to the second partition, compacting memory
after GC process and allowing continuous free memory.

43
Unit-4: Stacks and Queues
4.1 Stacks
Stack is one of the most useful concepts in computer science. Stacks are used whenever we want to
restrict insertions and deletions so that they can take place only from one end.
4.1.1 Definition: A stack is linear list of elements in which an element may be inserted or deleted
only at one end, called the top of the stack. This means, the elements are removed from a stack in
the reverse order of that in which they were inserted into the stack. Therefore, stacks are also called
LIFO (last-in-first-out) lists. Other names used for stacks are “Piles” and “Push-down lists”.
Examples of stacks are Stack of dishes, Stack of coins, Stack of folded towels etc.
Special terminology is used for two basic operations associated with stacks:
i. “Push” is the term used to insert an element into a stack.
ii. “Pop” is the term used to delete an element from a stack.
Note: These terms are used only with stacks, not with other data structures.
Example: Suppose the following 6 elements are pushed in order, onto an empty stack:
AAA, BBB, CCC, DDD, EEE, FFF
The following figure shows 3 ways of representing such a stack. For notational convenience, we
will frequently designate the stack by writing:
STACK: AAA, BBB, CCC, DDD, EEE, FFF
The right-most element is the top element and according to the property of stacks, insertions and
deletions can occur only at the top of the stack. This means EEE cannot be deleted before FFF is
deleted, DDD cannot be deleted before EEE and FFF are deleted, and so on. Consequently, the
elements may be popped (deleted) from the stack only in the reverse order of that in which they were
pushed (inserted) onto the stack.
1 AAA
2 BBB
TOP 3 CCC TOP
4 DDD
5 EEE
FFF
6 FFF
EEE 7
DDD 8
CCC
(a) (b)
BBB N-1
44
AAA N
AAA BBB CCC DDD EEE FFF
1 2 3 4 5 6 7 8 9 N-1 N

TOP
(c)
4.1.2 Representation and Primitive operations on Stack
Stacks may be represented in the computer in various ways, usually by means of one-way lists or a
linear array. More often a stack will be maintained by linear array.

Let STACK be a linear array, TOP be a pointer variable which contains the location of the top
element of the stack and MAXSTK is a variable, which gives the maximum number of elements that
can be held by the stack. The condition TOP = 0 or TOP = NULL will indicate that the stack is
empty.

An array representation of a stack is as shown in the following figure. Since TOP = 3, the stack has
3 elements, XXX, YYY, ZZZ and MAXSTK= 8, there is room for 5 more items in the stack.

XXX YYY ZZZ


1 2 3 4 5 6 7 8
TOP 3 MAXSTK 8

The primitive operations PUSH (adding) and POP (removing) can be performed as follows:
The operation of adding (pushing) an item onto a stack and the operation of removing (popping) an
item from a stack may be implemented, respectively, by the following procedures, called PUSH and
POP. In executing the procedure PUSH, one must first test whether there is room in the stack for the
new item; if not, then we have the condition known as overflow. Analogously, in executing the
procedure POP, one must first test whether there is an element in the stack to be deleted; if not, then
we have the condition known as underflow.

Procedure 1: PUSH (STACK, TOP, MAXSTK, ITEM)


This procedure pushes an ITEM onto a stack

1. [Stack already filled?]


If TOP = MAXSTK, then: Print: OVERFLOW, and Return
2. Set TOP = TOP + 1. [Increases TOP by 1]
3. Set STACK [TOP] = ITEM. [Inserts ITEM in new TOP position.]
4. Return

Procedure 2: POP (STACK, TOP, ITEM)


This procedure deletes the top element of STACK and assigns it to the variable
ITEM

1. [Stack has an item to be removed?]


If TOP = 0, then: Print: UNDERFLOW, and Return 45
2. Set ITEM = STACK [TOP]. [Assigns TOP element to ITEM]
3. Set TOP = TOP – 1. [Inserts ITEM in new TOP position.]
4. Return
4.1.3 Applications of Stack
Various applications of stack are known. A classical application deals with evaluation of arithmetic
expression. There are three notations to represent an arithmetic expression, namely, infix, prefix and
postfix. First, the infix expression will be converted into postfix expression and then to prefix
expression. The different applications of stack are:
1. Conversion of expressions
2. Evaluation of expression
3. Recursion.

4.1.4 Conversion of Expressions


An arithmetic expression is recursively defined as follows;
i) a is an arithmetic expression where a is any variable or numeric constant.
ii) If a and b are arithmetic expression then
a op b
is an arithmetic expression where op is any operator such as +, -, *, or / . An expression can either
be a parenthesized or un-parenthesized expression.

Infix, postfix and infix expressions


An expression with one operator and two operands such as a + b is a simple arithmetic expression.
This is the conventional way of writing an expression, and is called infix expression.
Any expression having an operator in between operands is called infix expression. The notation of
infix expression is
<operand> <operator> <operand>
Example: A + B, C–D, E*F, G/H, etc.

An expression where an operator follows the two operands is called postfix expression. The
notation of postfix expression is
<operand> <operand> <operator>
Example: AB+, CD–, EF*, GH/, etc.

An expression where an operator precedes the two operands is called prefix expression. The
notation of prefix expression is
<operator> <operand> <operand>
Example: +AB, – CD, *EF, /GH, etc.

We can convert expressions from one form to other. While evaluating or converting an expression
into other forms, one should know the hierarchy of operators and whether they are left associative or
right associative. Consider the infix expression;
46
((A+(B–C)*D)^E+F)
Here, parenthesis is having higher precedence, next comes the exponentiation represented as ^, then
multiplication or division whichever comes first from left to right and finally the addition and
subtraction whichever comes first from left to right.

4.1.5 Conversion from infix to postfix


We convert the given infix expression into its corresponding postfix expression as follows;
Infix Postfix
((A+(B–C)*D)^E+F)
( ( A + T1 * D ) ^ E + F ) where T1 = B – C B C–
( ( A + T2 ) ^ E + F ) where T2 = T1 * D T1 D *
( T3 ^ E + F ) where T3 = A + T2 A T2 +
( T4 + F ) where T4 = T3 ^ E T3 E ^
T5 where T5 = T4 + F T4 F +
Then substituting the corresponding postfix form in reverse we get
T5
T4 F +
T3 E ^ F +
A T2 + E ^ F +
A T1 D * + E ^ F +
A B C – D * + E ^ F + which is a postfix expression.

4.1.6 Algorithm for conversion of expression


The following algorithm is used for transforming infix expression into postfix expression.
Let Q be an arithmetic expression written infix notation. The operators +, -, *, / and ^ are formed
from left to right based their hierarchy. The algorithm transforms the infix expression Q into its
equivalent postfix expression P.
Algorithm: POLISH(Q,P)
Step 1: PUSH ‘(‘onto stack and add ‘)’ to the end of Q
Step 2: Scan Q from left to right and repeat steps 3 to 6 for each element of Q until the
stack is empty
Step 3: If an operand is encountered, add it to P.

Step 5: If an operator ⊗ is encountered then:


Step 4: If a left parenthesis encountered then PUSH it onto stack.

which has same precedence or higher precedence than ⊗.


a. Repeatedly POP from STACK and add to P, each operator(TOP of Stack)

b. Add ⊗ to STACK. 47
[ End of If structure]
Step 6: If a right parenthesis is encountered then:
a. Repeatedly POP from STACK and add to P each operator (on TOP of STACK)
Example: Consider the following arithmetic infix expression
Q: A + ( B * C – ( D * E ^ F ) + G ) * H
We simulate the algorithm to transfer Q into its equivalent Postfix expression P.
First we PUSH ‘(‘ onto the STACK then we add ‘)’ at the end of Q to obtain equivalent Postfix
expression P.
Sl. No. Symbol Scanned STACK Expression P
1. A ( A
2. + (+ A
3. ( (+( A
4. B (+( AB
5. * (+(* AB
6. C (+(* ABC
7. – (+(– ABC*
8. ( (+(–( ABC*
9. D (+(–( ABC*D
10. / (+(–(/ ABC*D
11. E (+(–(/ ABC*DE
12. ^ (+(–(/^ ABC*DE
13. F (+(–(/^ ABC*DEF
14. ) (+(– ABC*DEF^/
15. * (+(–* ABC*DEF^/
16. G (+(–* ABC*DEF^/G
17. ) (+ ABC*DEF^/G*–
18. * (+* ABC*DEF^/G*–
19. H (+* ABC*DEF^/G*–H
20. ) -- ABC*DEF^/G*–H*+

Here we observe that;


i. Each operand is simply added to P without changing the STACK.
ii. The subtraction operator (–) in row 7 sends * from STACK to P before it is pushed onto the
STACK
iii. ‘)’ (right parenthesis) sends ^ and / from STACK to P and it removes the ‘(‘ (left parenthesis)
48
from TOP of the STACK
iv. ‘)’ in row 20 sends * and + from STACK to P and then remove the ‘(‘ from TOP of the
STACK
After step 20, the STACK will become empty, and we obtain following equivalent postfix
expression;
P:ABC*DEF^/G*–H*+

4.1.7 Evaluation of Postfix Expressions


While evaluating an infix expression, it is required to scan from left to right repeatedly. The
problem becomes complex, if there are parenthesis in the expression because they change the order
of precedence. Repeated scanning from left to right can be avoided if the infix expression is
converted to its corresponding postfix or prefix expression. Evaluation of a postfix expression or
prefix expression is very simple.
The steps to be followed are:
1. Scan from left to right till an operator is encountered.
2. Scan backward to obtain immediate two left operands.
3. Perform the indicted operation.
4. Replace the operands and the operator by the result.
4.1.8 Algorithm for evaluating Postfix expression
Suppose P is an arithmetic expression in postfix notation, the following algorithm which uses a
STACK to hold operands and evaluates P.
Algorithm: POSTFIX(P)
Step 1: Add ‘)’ at the end of P
Step 2: Scan P from left to right and repeat steps 3 and 4 for each element of P until the
the sentinel ‘)’ is encountered.

Step 4: If an operator ⊗ is encountered then:


Step 3: If an operand is encountered, put it on stack.

a. Remove top two elements of STACK, where A is top element and B is

b. Evaluate B ⊗ A.
next-to-top element.

c. Place the result of ‘b’ back on STACK.


[ End of If structure]
[End of step 2 loop
Step 5: Set value equal to the TOP element of the STACK.
Step 6: Exit
Example: Consider the following arithmetic expression P in postfix notation;
P: 5, 6, 2, +, *, 12, 4, /, –
First we add ‘)’ to the expression P to obtain
P: 5, 6, 2, +, *, 12, 4, /, – )
Now we evaluate the given expression P as shown below.
Sl. No. Symbol Scanned STACK
1. 5 5
49
2. 6 5, 6
3. 2 5, 6, 2
4. + 5, 8
5. * 40
6. 12 40, 12
7. 4 40, 12, 4
8. / 40, 3
9. – 37
10. ) 37
4.2 QUEUES
4.2.1 Definition: A queue is a linear list of elements in which deletions can take place only at one
end, called the front, and insertions can take place only at the other end, called the rear.
Note: The terms “front” and “rear” are used in describing a linear data structure queue.
Queues are also called first-in-first-out (FIFO) lists. Since the first element in a queue will be the
first element out of the queue. In other words, the order in which elements enter a queue is the order
in which they leave. This contrasts with stacks, which are last-in-first-out (LIFO) lists.
Examples of a queue abound in the real world. A line at a bank or at a bus stop and a group of cars
waiting at a toll booth are all familiar examples of queues. An important example of a queue in
computer science occurs in a timesharing system, in which programs with the same priority form a
queue while waiting to be executed.
4.2.2 Example: The following figure(a) is a schematic diagram of a queue with 4 element, where
AAA is the front element and DDD is the rear element. The front and rear elements of the queue
are the first and the last elements of the list respectively.
i. Suppose an element is deleted from the queue then it must be AAA. The queue appears as
shown in figure(b), where BBB is the front element.
ii. Suppose new elements EEE and FFF are added to the queue one after the other. Then they
must be added at the rear of the queue as shown in figure(c). Now FFF is the rear element.
iii. Suppose another element is deleted from the queue, then it must be BBB, to yield the queue
as shown in figure(d). And so on.
In this data structure, EEE will be deleted before FFF because it has been placed in the queue before
FFF. However, EEE will have to wait until CCC and DDD are deleted.
AAA BBB CCC DDD
(a)
BBB CCC DDD
(b)
BBB CCC DDD EEE FFF
(c)
CCC DDD EEE FFF
(d)

50
4.2.3 Applications of Queues
Queues have the following applications
1. Queues are used in computer simulation of a real world situation.
2. They are also used in many ways by the operating system. The program that schedules and
allocates the resource of computer systems uses the concept of queues.
3. In a computer system network messages from one computer to another can be sent by using
queues by sorting them in queues.
4. Queues are used on time sharing system in which programs form a queue while waiting for
execution.
5. In a multi user system, the programs of higher priority are processed first and programs of lower
priority are processed next by forming a queue.
4.2.4 Representation of Queues
Queues may be represented in the computer in various ways, usually by means of one-way lists or
linear arrays. Usually a queue is maintained in a linear array. Let QUEUE be a linear array and
pointer variables FRONT and REAR, respectively, containing the location of the front element, and
the location of the rear element of the queue. The FRONT = NULL will indicate that the queue is
empty.
The following figure shows the way the array QUEUE with N elements will be stored in memory. It
also indicates the way elements will be deleted from the queue and the way new elements will be
added to the queue. Whenever an element is deleted from the queue, the value of FRONT is
increased by 1; this can be implemented by the assignment
FRONT = FRONT + 1
Similarly, whenever an element is added to the queue, the value of REAR is increased by 1; this can
be implemented by the assignment
REAR = REAR +1
This means that after N insertions, the rear element of the queue will occupy QUEUE[N] or, in other
words, eventually the queue will occupy the last past of the array. This occurs even though the
queue itself may not contain many elements.
QUEUE
FRONT: 1
REAR: 4
AAA BBB CCC DDD …..
1 2 3 4 5 6 7 ….. N
(a)
QUEUE
FRONT: 2
BBB CCC DDD …..
REAR: 4
1 2 3 4 5 6 7 ….. N
(b)
QUEUE
FRONT: 2
BBB CCC DDD EEE FFF …..
REAR: 6
1 2 3 4 5 6 7 ….. N
(c)
QUEUE

51
FRONT: 3
CCC DDD EEE FFF …..
REAR: 6
1 2 3 4 5 6 7 ….. N
(d)
Suppose we want to insert an element ITEM into a queue at the time the queue does occupy the last
part of the array, i.e., when REAR = N. One way to do this is to simply move the entire queue to the
beginning of the array, changing FRONT and REAR accordingly, and then inserting ITEM as
above. This procedure may be very expensive. The procedure we adopt is to assume that the array
QUEUE is circular, that is, that QUEUE[1] come after QUEUE[N] in the array. With this
assumption, we insert ITEM into the queue by assigning ITEM to QUEUE[1]. Specifically, instead
of increasing REAR to N +1, we reset REAR = 1 and then assign
QUEUE[REAR] = ITEM

Similarly, if FRONT = N and an element of QUEUE is deleted, we reset FRONT = 1 instead of


increasing FRONT to N +1.
Suppose that our queue contains only one element, i.e., suppose that
FRONT = REAR  NULL
and suppose that the element is deleted. Then we assign
FRONT = NULL and REAR = NULL
to indicate that the queue is empty.
4.2.5 Primitive Operations on a Queue
We can insert and delete data items into and from the queue. These two operations can be
performed by using following two procedures:
i) The QINSERT procedure, which inserts a data ITEM into a queue. The procedure will test the
overflow condition to check whether or not the queue is filled.
ii) The QDELETE procedure, which deletes the first element from a queue, assigning it to the
variable ITEM. The procedure will test the underflow condition to check whether or not the queue
is empty.
Procedure 1: QINSERT (QUEUE, N, FRONT, REAR, ITEM)
This procedure inserts an element ITEM into a queue.
1. [Queue already filled?]
If FRONT = 1 and REAR = N, or if FRONT = REAR + 1, then:
Write: OVERFLOW, and Return.
2. [Find new value of REAR]
If FRONT = NULL, then: [Queue initially empty]
Set FRONT = 1 and REAR = 1
Else if REAR = N, then:
Set REAR = 1.
Else: Set REAR = REAR + 1
[End of If structure]
3. Set QUEUE[REAR] = ITEM. [This inserts a new element.]
4. Return.

Procedure 2: QDELETE (QUEUE, N, FRONT, REAR, ITEM)


This procedure deletes an element from a queue and assigns it to the variable 52
ITEM .
1. [Queue already empty?]
If FRONT = NULL, then: Write: UNDERFLOW, and Return.
4.2.6 Various Queue Structures
There are several queue structures. They are;
1. Circular queues
2. Deque
3. Priority queues
1. Circular Queues
In an ordinary queue, as an item is inserted, the REAR pointer is incremented by 1. Once REAR
reaches QUEUE[N], we say the queue is full, even if some elements are deleted from queue. In other
words, suppose we want to insert an element ITEM into a queue at the time the queue does occupy
the last part of the array, i.e., when REAR = N. One way to do this is to simply move the entire
queue to the beginning of the array, changing FRONT and REAR accordingly, and then inserting
ITEM as above. This procedure may be very expensive. The procedure we adopt is to assume that
the array QUEUE is circular, that is, that QUEUE[1] come after QUEUE[N] in the array. With this
assumption, we insert ITEM into the queue by assigning ITEM to QUEUE[1]. Specifically, instead
of increasing REAR to N +1, we reset REAR = 1 and then assign
QUEUE[REAR] = ITEM
Similarly, if FRONT = N and an element of QUEUE is deleted, we reset FRONT = 1 instead of
increasing FRONT to N +1.
2. Deque
A deque ( pronounced either “deck” or “dequeue”) is a linear list in which elements can be added or
removed at either end but not in the middle. The term deque is a contraction of the name double-
ended queue.
There are two variations of a deque–namely, an input-restricted deque and an output-restricted
deque–which are intermediate between a deque and a queue. Specifically, an input-restricted deque
is a deque which allows insertions at only one end of the list but allows deletions at both ends of the
list; and an output-restricted deque is a deque which allows deletions at only one end of the list but
allows insertions at both ends of the list.
It is clear from the deque structure that it is a general representation of both stack and queue, or in
other words, a deque can be used a stack as well as a queue.

53
3. Priority Queues
A priority queue is a collection of elements such that each element has been assigned a priority and
such that the order in which elements are deleted and processed comes from the following rules:
1. An element of higher priority is processed before any element of lower priority.
2. Two elements with the same priority are processed according to the order in which they
were added to the queue.
In other words, the priority queue is a special type of data structure in which items can be inserted or
deleted based on the priority. The different type of priority queues are
i. Ascending priority queue
ii. Descending priority queue
In an ascending priority queue elements can be inserted in any order. But, while deleting an element
from the queue, remove only the smallest element first. In descending priority queue, also the
elements can be inserted in any order. But, while deleting an element from the queue, only the
largest element is deleted.

Unit 5: Trees
5.1 Basic Terminology of Trees
Arrays, Stacks, Queues and Linked Lists are called linear data structure, because the elements are
arranged in a linear fashion. These data structures and their relationships are invariably expressed
using single dimension. Another very useful data structure is tree, where elements appear in a non-
linear fashion, which require two-dimensional representation. A tree is called a nonlinear data
structure. This structure is mainly used to represent data containing a hierarchical relationship
between elements, for example, records, family trees, and tables of contents.
5.2 Definition: A Tree T is a set of nodes such that,
i) there is a specifically designated node called root, and
ii) remaining nodes are partitioned into disjoint set of nodes
Example:
A

B C D

G H I E F
This is a tree because, it has a set of nodes {A, B, C, D, E, F, G, H, I} with node A as root and three
disjoint sets {B, G, H, I}, {C, E, F}, and {D}. Each of these sets is a tree individually because, they
satisfy above properties.
5. 3 Degree of a node of a tree
Degree of a node of a tree is the number of subtrees having that node as a root, or it is a number of
decedents of nodes. If degree is zero then it is called a terminating node of a tree.

54
5.4 Uses of Tree
Following are the common uses of tree.
1. Tress can be used to store and manipulate the hierarchical data.
2. They are used to organize data for efficient insertion, deletion and searching.
2. Using trees we can easily search and sort with the standard traversal algorithms.
3. To manipulate stored lists of data.
4. Used as a workflow for composing digital images for visual effects.
5. A special tree called Trie is used to store the dictionary. It is a fast and efficient way for dynamic
spell checking.
6. Using Heap trees we can implement priority queues.
7. The B-tree and B+ tree structures are used to implement indexing in datatbases.
8. The tree data structures is also used to store the data in routing tables in the routers.
5.5 Binary Trees
5.5.1 Definition: A binary tree is a finite set of elements that is either empty or is partitioned into
three disjoint subsets. The first subset contains a single element called the root of the tree. The
other two subsets are themselves binary trees, called the left and right subtrees of the original tree.
A left or right subtree can be empty. Each element of a binary tree is called node of the tree.
In general, a binary tree T is defined as finite set element, called nodes, such that:
a) T is empty (called the null tree or empty tree), or
b) T contains a distinguished node R, called the root of T, and remaining nodes of T form an
ordered pair of disjoint binary trees T1 and T2.
Example: If T does contain a root R, then the two trees T 1 and T2 are called, respectively, the left
and right subtrees of R. If T1 is nonempty, then its root is called the left successor of R; similarly, if
T2 is nonempty, then its root is called the right successor of R.

A binary tree T is frequently presented by means of a diagram. Specifically, the diagram in the
following figure represents a binary tree T as follows.
i. T consists of 11 nodes, represented by the letters A through L, excluding I.
ii. The root of T is the node A at the top of the diagram.
iii. A left-downward slanted line from N indicates a right successor of N
Here we observe that:
a) B is a left successor and C is right successor of the node A.

55
b) The left subtree of the root A consists of the nodes B, D, E and F, and the right subtree of A
consists of the nodes C, G, H, J, K and L.
Any node N in a binary tree T has 0, 1 or 2 successor. The nodes A, B, C and H have two
successors, the nodes E and J have only one successor, and the nodes D, F, G, L and K have no
successors. The nodes with no successors are called terminal nodes.
A

B C

D E G H

F J K

L
5.5.2 Terminology
Terminology describing family relationships is frequently used to describe relationships between the
nodes of a tree T. Specifically, suppose N is a node in T with left successor S1 and right successor
S2. Then N is called the parent (or father) of S1and S2. Analogously, S1 is called the left child (or
son) of N, and S2 is called the right child (or son) of N. Furthermore, S1and S2 are said to be siblings
(or brothers). Every node N in a binary tree T, except the root, has a unique parent, called
predecessor of N.

Root: Root is a special node in a tree. The entire tree is referenced through it. It does not have a
parent.
Parent Node: Parent node is an immediate predecessor of a node.
56
Child Node: All immediate successors of a node are its children.
Siblings: Children of same parents, or nodes with the same parent are called Siblings
Edge: The line drawn from a node N of T to a successor is called an edge.
Path: A sequence of consecutive edges is called a path or it is a number of successive edges from
source node to destination node
Leaf and Branch: A terminal node is called a leaf, and path ending a leaf is called a branch.
Level Number: Each node in a binary tree T is assigned a level number, as follows:
The root R of the tree T is assigned the level number 0 and every other node is assigned a level
number which is 1 more than the level of number of its parent. Furthermore, those nodes with the
same level number are said to belong to the same generation.
Height of a tree: The depth (or height) of a tree T is the maximum number of nodes in a branch of
T. This turns out to be 1 more than the largest level number of T. The tree in the above figure has
depth 5.
Degree of a node: Degree of a node represents a number of children of a node.

5.5.3 Similar Binary trees


Binary trees T and T are said to be similar if they have the same structure or, in other words, if they
have the shape. The trees are said to be copies if they are similar and if they have the same contents
at corresponding nodes.
Example: Consider, the following four binary trees
A E A E

B F B F

C D G H C D G H
(a) (b) (c) (d)
In the above figure, the trees (a) and (c) and (d) are similar. In particular, (a) and (c) are copies of
each other, since they have same data at corresponding nodes.
The tree (b) is neither similar nor copy of tree (d) because, in a binary tree we distinguish between
left and right successor even when there is only one successor.

5.5.4 Complete Binary trees


A tree T is said to be complete, if all its levels, except possibly the last, have the maximum number
of possible nodes, and if all the nodes at the last level appear as left as possible.
Example: Consider, the following tree T with 25 nodes as shown in the following figure. The nodes
of complete binary tree T25 are labelled by the integers 1, 2, ……. , 25, from left to right,
and generation by generation.

57
5.5.5 Extended Binary trees or 2-tree
A binary tree T is said to be an extended binary tree or a 2-tree, if each node N has 0 or 2 children.
 The nodes with 2 children are called internal nodes
 The nodes with 0 children are called external nodes.
The internal nodes are represented by circles and the external nodes are represented by squares.
Example: Consider, a binary tree T as shown figure (a), the tree T may be converted into a 2-tree by
replacing each empty subtree by a new node as shown in figure (b).

fig (a)

fig(b)

5.5.6

Representing Binary Trees in Memory

58
A binary tree T can be represented in memory in two different ways. The first and usual way is
called the link representation of T, and the second way, which uses a single array, called the
sequential representation of T. The main requirement of any representation of T is that one should
have direct access to the root R of T and, given node N of T, one should have direct access to the
children of N.
5.5.7 Linked Representation of Binary Trees
Consider a binary tree T. T will be maintained in memory by means of a linked representation
which uses three parallel arrays; INFO, LEFT and RIGHT, and a pointer variable ROOT as follows.
First of all, each node N of T will correspond to a location K such that:
1. INFO[K] contains the data at the node N.
2. LEFT[K] contains the location of the left child of node N.
3. RIGHT[K] contains the location of the right child of node N.
Furthermore, ROOT will contain the location of the root R of T. If any subtree is empty, then the
corresponding pointer will contain the null value; if the tree T itself is empty, then ROOT will
contain the null value.

Example: Consider a binary tree T consists of 11 nodes, represented by the letters A through L,
excluding I.

B C

D E G H

F J K

ROOT

B C

x D x E x x G x H

x F x J x x K x

x L x

59
INFO LEFT RIGHT
ROOT 1 K 0 0
5 2 C 3 6
3 G 0 0
AVAIL 4 14
8 5 A 10 2
6 H 17 1
7 L 0 0
8 9
9 4
10 B 18 13
11 19
12 F 0 0
13 E 12 0
14 15
15 16
16 11
17 J 7 0
18 D 0 0
19 20
20 0

5.5.8 Traversing Binary Trees


There are three standard ways of traversing a binary tree T with root R. These three traversals,
called preorder, inorder and postorder, are as follows:
Preorder: 1. Process the root R.
2. Traverse the left subtree of R in preorder.
3. Traverse the right subtree of R in preorder.

Inorder: 1. Traverse the left subtree of R in inorder.


2. Process the root R.
3. Traverse the right subtree of R in inorder.

Postorder: 1. Traverse the left subtree of R in postorder.


2. Traverse the right subtree of R in postorder.
3. Process the root R.

We observe that each traversal operation contains the same three steps, and that the left subtree of R
is always traversed before the right subtree. The difference between these traversals is the time at
which the root R is processed. Specifically, in the “pre” traversal, the root R is processed before the
subtrees are traversed; in the “in” traversal, the root R is processed between the traversals of the
subtrees; and in the “post” traversal, the root R is processed after the subtrees are traversed.
These traversals are sometimes called, respectively, the node-left-right (NLR) traversal, the left-
node-right (LNR) traversal and the left-right-node (LNR) traversal.
60
Example: Consider the binary tree T as shown in the following figure. Here we observe that A is
the root, that its left subtree L T consists of nodes B, D and E and that its right subtree R T consists of
nodes C and F.

B C
LT RT

D E F

i. Preorder traversing
The preorder traversal of T process A, traverses LT and traverses RT. However, the preorder
traversal of LT processes the root B and then D and E, and the preorder traversal of R T processes the
root C and then F. Hence ABDECF is the preorder traversal of T.

ii. Inorder traversing


The inorder traversal of T traverses LT, processes A and traverses RT. However, the inorder traversal
of LT processes D, B and then E, and the inorder traversal of R T processes C and then F. Hence
DBEACF is the inorder traversal of T.

iii. Postorder traversing


The postorder traversal of T traverses L T, traverses RT, and processes A. However, the postorder
traversal of LT, processes D, E and then B, and the postorder traversal of R T, processes F and then C.
Accordingly, DEBFCA is the postorder traversal of T.

5.5.9 Formation or Construction of Binary tree from its traversals

61
Sometimes it is required construct a binary tree its traversals are known. From a single traversal, it
is not possible to construct a unique binary tree. However, if two traversals are known then the
corresponding tree be drawn uniquely. The basic principle for constructing a binary tree are stated
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 the right sub-trees of
the root node can be identified
 The same technique can be applied repeatedly to form sub-trees.
Note: To construct a binary tree it is essential to have two traversals, out of which one should be
inorder traversal and another may be preorder or postorder.

Example 1: Construct a binary tree from the following traversal


Inorder : a1, a2, a3, a4, a5, a6, a7, a8, a9
Postorder: a1, a3, a5, a4, a2, a8, a7, a9, a6
To construct the binary tree, following steps need to be followed.
1. From the postorder traversal, it is clear that a6 is the node.
2. In inorder traversal, the nodes are on the left side of a 6 belongs to left sub-tree and the nodes on right
side of a6 belongs to the right sub-tree.
Inorder : a1, a2, a3, a4, a5, a6 , a7, a8, a9 (LNR)
Postorder: a1, a3, a5, a4, a2, a8, a7, a9, a6 (LRN)
3. Now we scan postorder traversal from right to left to get root of left subtree (except a7, a8, a9)
the first element we find is a2.
4. In inorder traversal, node a1 on the left side of a2 belongs to left sub-tree and the nodes a 3, a4, a5 on
right side of a2 belongs to the right sub-tree.
Inorder : a1, a2 , a3, a4, a5, a6 , a7, a8, a9 (LNR)
Postorder: a1, a3, a5, a4, a2, a8, a7, a9, a6 (LRN)
5. Again we scan postorder traversal from right to left from a2, the first element we find is a4.
6. In inorder traversal, the node a3 on the left side of a4 belongs to left sub-tree and the node a 5 on right
side of a4 belongs to the right sub-tree (now left sub-tree is completed).
Inorder : a1, a2 , a3, a4 , a5, a6 , a7, a8, a9 (LNR)
Postorder: a1, a3, a5, a4, a2, a8, a7, a9, a6 (LRN)
7. Now we scan postorder traversal from a6 right to left to get root of right subtree (in a7, a8, a9)
the first element we find is a9.
8. In inorder traversal, node a7 and a8 on the left side of a9 belongs to left sub-tree and there is no nodes
on right of a9. The nodes a3, a4, a5 on right side of a2 belongs to the right sub-tree.
Inorder : a1, a2 , a3, a4, a5, a6 , a7, a8, a9 (LNR)
Postorder: a1, a3, a5, a4, a2, a8, a7, a9, a6 (LRN)
9. Finally, we scan postorder traversal from a9 right to left to get root of right subtree (in a7, a8)
the first element we find is a7.
10. In inorder traversal, node a8 on the right side of a7 belongs to right sub-tree and there is no nodes on
left of a7.
62
Inorder : a1, a2 , a3, a4, a5, a6 , a7 , a8, a9 (LNR)
Postorder: a1, a3, a5, a4, a2, a8, a7, a9, a6 (LRN)
a6

a1, a2, a3, a4, a5 a7, a8, a9


a2 a9

a3, a4, a5
a1 a4 a7

a3 a5 a8

Example 2: Construct a binary tree from the following traversal


Inorder : n1 n2 n3 n4 n5 n6 n7 n8 n9
Postorder: n1 n3 n5 n4 n2 n8 n7 n9 n6
To construct the binary tree, following steps need to be followed.
1. From the postorder traversal, it is clear that n6 is the node.
2. In inorder traversal, the nodes are on the left side of n 6 belongs to left sub-tree and the nodes on right
side of a6 belongs to the right sub-tree.
3. Now the same problem reduces to form sub-trees and the same procedure can be applied repeatedly.
Following figure illustrate this procedure.
n1 n2 n3 n4 n5 n6 n7 n8 n9 (In)
n1 n3 n5 n4 n2 n8 n7 n9 n6 (Post)

(In) n1 n2 n3 n4 n5 n7 n8 n9 (In)
(Post) n1 n3 n5 n4 n2 n8 n7 n9 (Post)

n1 (In) n3 n4 n5 n7 n8 (In)
(Post) n3 n5 n4 n8 n7 (Post)

n3 n5 n8

(a) Construction by sub-trees partition


n6

n2 n9
63
n1 n4 n7

n3 n5 n8

(b) Final binary tree

Example 3: Construct a binary tree from the following traversal


Inorder : 5, 1, 3, 9, 6, 8, 4, 2, 7 ( LNR)
Preorder: 6, 1, 5, 9, 3, 4, 8, 7, 2 ( NLR)
To construct the binary tree, following steps need to be followed.
1. From the preorder traversal, it is clear that 6 is the node.
2. In inorder traversal, the nodes 5, 1, 3, 9 on the left side of 6 belongs to left sub-tree and the nodes 8,
4, 2, 7 on right side of 6 belongs to the right sub-tree.
Inorder: 5, 1, 3, 9, 6 , 8, 4, 2, 7
Preorder: 6, 1, 5, 9, 3, 4, 8, 7, 2
3. From the preorder traversal, it is clear that 1 is the node (left sub-tree of root node 6).
4. In inorder traversal, the node 5 on the left side of 1 belongs to left sub-tree and the nodes 3, 9 on
right side of 1 belongs to the right sub-tree.
Inorder : 5, 1 , 3, 9, 6 , 8, 4, 2, 7
Preorder: 6, 1, 5, 9, 3, 4, 8, 7, 2
5. Now we scan the preorder traversal from right to left(in 9,3), it is clear that 9 is the node.
6. In inorder traversal, the node 3 on the left side of 9 belongs to left sub-tree and no nodes on right
side of 9, which means that the right sub-tree is empty (now left sub-tree is completed).
Inorder : 5, 1, 3, 9 , 6, 8, 4, 2, 7
Preorder: 6, 1, 5, 9, 3, 4, 8, 7, 2
7. Now we scan preorder traversal right to left from 4, we find 4 as the node(right sub-tree of 6).
8. In inorder traversal, the node 8 on the left side of 4 belongs to left sub-tree and the nodes 2, 7 on
right side of 4 belongs to right sub-tree.
Inorder : 5, 1, 3, 9 , 6, 8, 4 , 2, 7
Preorder: 6, 1, 5, 9, 3, 4, 8, 7, 2
9. Finally we scan preorder traversal right to left from 7, we find 7 as the node.
10. In inorder traversal, the node 2 on the left side of 7 belongs to left sub-tree and no nodes on right
side of 7, which means that the right sub-tree is empty.
Inorder : 5, 1, 3, 9 , 6, 8, 4 , 2, 7
Preorder: 6, 1, 5, 9, 3, 4, 8, 7, 2
6

5, 1, 3, 9 8, 4, 2, 7
1 4

64
3, 9 2, 7
5 9 8 7

3 2
Example 5: Construct a binary tree from the following traversal
Inorder : E A C K F H D B G
Preorder: F A E K C D H G B
To construct the binary tree, following steps need to be followed.
1. From the preorder traversal, it is clear that F is the node.
2. In inorder traversal, the nodes are on the left side of F belongs to left sub-tree and the nodes on right
side of F belongs to the right sub-tree.
3. Now the same problem reduces to form sub-trees and the same procedure can be applied repeatedly.
Following figure illustrate this procedure.
E A C K F H D B G (In)
F A E K C D H G B (Pre)

(In) E A C K H D B G (In)
(Pre) A E K C D H G B (Pre)

E (In) C K H B G (In)
(Pre) K C G B (Pre)

C B

(a) Construction by sub-trees partition


F

A D

E K H G

C B
(b) Final binary tree
5.6 Expression tree
An expression tree is a binary tree which stores an arithmetic expression. The leaves of an expression are
operands, such as constants or variable names, and all internal nodes are the operators.

65
5.7 Binary Search Trees (BST)
A binary tree T is called a binary search tree or binary sorted tree, if each node N of T has the following
property;
The value at N is greater than every value in the left subtree of N and is less than every value in the right
subtree of N.

5.8 Heap Trees


Suppose H is complete binary tree, it will be termed as
heap tree, if it satisfies the following properties:
i. For each node N in H, the value at N is greater than or equal to the value of each of the children on N.
ii. Or, in other words, N has a value which is greater than or equal to the value of every successor of N.

66

You might also like