Data Structures and Algorithms
Data Structures and Algorithms
ALGORITHMS
Bharathidasan University
Centre for Distance and Online Education
Chairman:
Dr. M. Selvam
Vice-Chancellor
Bharathidasan University
Tiruchirappalli-620 024
Tamil Nadu
Co-Chairman:
Dr. G. Gopinath
Registrar
Bharathidasan University
Tiruchirappalli-620 024
Tamil Nadu
Course Co-Ordinator:
Dr. A. Edward William Benjamin
Director-Centre for Distance and Online Education
Bharathidasan University
Tiruchirappalli-620 024
Tamil Nadu
The Syllabus is Revised from 2021-22 onwards
Author:
Reviewer
Ms. N. Vijayalakshmi, Asst. Professor, Dept. of Computer Application Sirmashi India Gandhi College, Trichy
Dr. S. Chellammal, Asst Professor, Dept of Computer Science, CDOE,
Bharathidasan University, Trichy
Authors
Rohit Khurana, CEO, ITL Education Solutions Ltd.
Units (1-4, 6-14)
R Subburaj, Former Senior Director, Department of Information Technology, Government of India
Unit (5)
Information contained in this book has been published by VIKAS® Publishing House Pvt. Ltd. and has
been obtained by its Authors from sources believed to be reliable and are correct to the best of their
knowledge. However, the Publisher, its Authors shall in no event be liable for any errors, omissions
or damages arising out of use of this information and specifically disclaim any implied warranties or
merchantability or fitness for any particular use.
BLOCK I: INTRODUCTION
UNIT 1: Introduction to Data Structure: Types of Data Structure , Primitive Unit 1: Introduction to
Data Types Data Structure
Algorithms: Time and Space Complexity of Algorithms (Pages 1-20)
UNIT 6: List: Merging Lists, Linked List, Single Linked List, Double Linked Unit 6: Lists
List, Header Linked List (Pages 90-98)
UNIT 7: Operation on Linked List: Insertion and Deletion of Linked List Unit 7: Operation on Linked Lists
(Pages 99-118)
UNIT 8: Traversal: Traversing a Linked List, Representation of Linked List. Unit 8: Traversal
(Pages 119-124)
UNIT 10: Binary Tree Operations / Applications : Traversing Binary Trees, Unit 10: Binary Tree
Binary Search Tree Operations/
Applications
(Pages 134-156)
UNIT 11: Operations on Binary Tree: Insertion and Deletion Operations, Unit 11: Operations on
Hashing Techniques. Binary Tree
(Pages 157-175)
BLOCK IV: SEARCHINGTECHNIQUES
UNIT 12: Searching: Introduction, Searching, Linear Search, Binary Search Unit 12: Searching
(Pages 176-191)
BLOCK V: SORTINGTECHNIQUES
UNIT 13: Sorting: Bubble Sort, Insertion Sort, Radix Sort Unit 13: Sorting
(Pages 192-205);
UNIT 14: Other Sorting Techniques: Selection Sort, Quick Sort, Tree Sort. Unit 14: Other Sorting
Techniques
(Pages 206-218)
CONTENTS
INTRODUCTION
BLOCK I: INTRODUCTION
UNIT 1 INTRODUCTION TO DATA STRUCTURE 1-20
1.0 Introduction
1.1 Objectives
1.2 Primitive and Composite Data Types
1.3 Abstract Data Types
1.4 Data Structures
1.4.1 Linear Data Structures
1.4.2 Non-Linear Data Structures
1.5 Operations on Data Structures
1.6 Algorithms
1.7 Algorithm Design Techniques
1.7.1 Brute Force Algorithm
1.7.2 Divide and Conquer
1.7.3 Dynamic Programming
1.7.4 Greedy Algorithm
1.8 Time and Space Complexity of Algorithms
1.9 Big O Notation
1.10 Recurrences
1.11 Answers to Check Your Progress Questions
1.12 Summary
1.13 Key Words
1.14 Self Assessment Questions and Exercises
1.15 Further Readings
1.16 Learning Outcomes
Self-Instructional
Material
Introduction to Data
Structure
BLOCK - I
INTRODUCTION
NOTES
UNIT 1 INTRODUCTION TO DATA
STRUCTURE
Structure
1.0 Introduction
1.1 Objectives
1.2 Primitive and Composite Data Types
1.3 Abstract Data Types
1.4 Data Structures
1.4.1 Linear Data Structures
1.4.2 Non-Linear Data Structures
1.5 Operations on Data Structures
1.6 Algorithms
1.7 Algorithm Design Techniques
1.7.1 Brute Force Algorithm
1.7.2 Divide and Conquer
1.7.3 Dynamic Programming
1.7.4 Greedy Algorithm
1.8 Time and Space Complexity of Algorithms
1.9 Big O Notation
1.10 Recurrences
1.11 Answers to Check Your Progress Questions
1.12 Summary
1.13 Key Words
1.14 Self Assessment Questions and Exercises
1.15 Further Readings
1.16 Learning Outcomes
1.0 INTRODUCTION
A data structure is a specialized format for organizing and storing data. Some
general data structure types include the array, file, record, table, tree, and so on.
Any data structure is designed to organize data to suit a specific purpose so that it
can be accessed and worked with in appropriate ways. In this unit, you will learn
about data types, algorithms and complexities associated with them.
1.1 OBJECTIVES
Self-Instructional
2 Material
operations on integers that are associated with them like addition, subtraction, Introduction to Data
Structure
division, multiplication, modulus, etc. However, we do not know how these
operations are actually performed on integers. We only know the syntax of how to
perform these operations in some programming language. For example, C language
defines +, –, /, *, % to perform some basic arithmetic operations on integers. NOTES
The basic idea of ADT is that the implementation of the set of operations
are written once in the program and the part of program which needs to perform
an operation on ADT accomplishes this by invoking the required operation. If
there is a need to change the implementation details of an ADT, the change will be
completely transparent to the programs using it. The data structures, namely, linked
lists, stacks, and queues are some examples of ADTs.
The logical or mathematical model used to organize the data in main memory is
called a data structure. Various data structures are available, each having certain
special features. These features should be kept in mind while choosing a data
structure for a particular situation. Generally, the choice of a data structure depends
on its simplicityand effectiveness in processingof data. In addition, we also consider
how well it represents the actual relationship of the data in the real world. Data
structures are divided into two categories, namely, linear data structure and
non-linear data structure.
1.4.1 Linear Data Structures
A linear data structure is one in which its elements form a sequence. It means each
element in the structure has a unique predecessor and a unique successor. An
array is the simplest linear data structure. Various other linear data structures are
linked into lists, stacks, and queues.
Arrays
Afinite collection of homogenous elements is termed as an array. Here, the word
‘homogenous’ indicates that the data type of all the elements in the collection
should be same, that is, int or char or float or any other built-in or user-defined
data type. However, an array cannot have elements of two or more data types
together.
Self-Instructional
Material 3
Introduction to Data The elements of an array are always stored in a contiguous memorylocations
Structure
irrespective of the array size. The elements of an array can be referred to by using
one or more indices or subscripts. An index or a subscript is a positive integer
value which indicates the position of a particular element in the array. If the number
NOTES of subscripts required to access any particular element of an array is one, then it is
called a, single-dimensional array. Otherwise, it is a multi-dimensional array.
A multi-dimensional array can be a two-dimensional array or even more.
Consider a single-dimensional array Arr with size n, where n is the
maximum number of elements that Arr can store. Mathematically, the elements
of Arr are denoted as Arr1, Arr2, Arr3,…, Arrn. In different
programming languages, array elements are denoted by different notations such
as by parenthesis notation or by bracket notation. Table 1.1 shows the notation of
elements of a single-dimensional array Arr with size n in different programming
languages as follows:
Table 1.1 Different Notations of a Single-dimensional Array
Note that in the languages, BASIC, PASCAL, and FORTRAN, the smallest
subscript value is 1 and the largest subscript value is n. On the other hand, in
languages like C, C++ and Java, the smallest subscript value is 0 and the largest
subscript value is n-1. In general, the smallest subscript value that is used to
access an array element is the lower bound (Lb) and the largest subscript value
that is used is upper bound (Ub).
In two-dimensional arrays, the elements can be viewed as arranged in the
form of rows and columns (matrix form). To access an element of a two-
dimensional array, two subscripts are used—first one represents the row number
and second one represents the column number. For example, consider a two-
dimensional array Arr with size m*n, where m and n represent the number of
rows and columns, respectively. Mathematically, the array Arr is denoted as
Arrij, where i and j indicate the row numbers and the column number with
i<=m and j<=n. Table 1.2 shows the notation of elements of a two-dimensional
arrayArr in different programming languages as follows:
Self-Instructional
4 Material
Table 1.2 Different Notations of Two-dimensional Array Introduction to Data
Structure
S. Number Notation Programming
Language(s)
1 Arr(i, j) with BASIC and
0<i<=m and 0<j<=n FORTRAN NOTES
2 Arr[i, j] with PASCAL
0<i<=m and 0<j<=n
3 Arr[i][j] with C, C++ and Java
0<=i<m and 0<=j<n
Linked lists
Another commonly used linear data structure is a linked list. Alinked list is a linear
collection of similar data elements, called nodes, with each node containing some
data and pointer(s) pointing to other node(s) in the list. Nodes of a linked list are
not constrained to be at contiguous memory locations; instead they can be stored
anywhere in the memory. The linear order of the list is maintained by the pointer
field(s) in each node.
Depending on the pointer field(s) in each node, linked lists can be of different
types. If each node of a linked list contains only one pointer and it points to the next
node, then it is called a linear linked list or singly linked list. In such type of lists, the
pointer field in the last node contains NULL. However, if the pointer in the last node
is modified to point to the first node of the list, then it is called a circular linked list.
In addition to the pointer to the next node, each node of a linked list can also
contain a pointer to its previous node. This type of a linked list is called doubly
linked list. Figure 1.1 shows a singly, circular, and doubly linked list with five
nodes each as follows:
Start
Top
‘O’
‘L’
‘L’
‘E’
‘H’
Self-Instructional
6 Material
unique the predecessor and a unique successor. Trees and graphs are the two Introduction to Data
Structure
data structures which come under this category. These data structures have been
discussed in the subsequent paragraphs.
Trees NOTES
Many-a-times, we observe a hierarchical relationship between various data
elements. This hierarchical relationship between data elements can be easily
represented using a non-linear data structure called trees. Atree consists of multiple
nodes, with each node containing zero, one or more pointers to other nodes called
child nodes. Each node of a tree has exactly one parent except a special node at
the top of the tree called a root node. An example tree with A as the root of the
tree is shown in Figure 1.4 as follows:
A Root
B C
D F G
E
In this tree, the root node has two child nodes B and C. In turn, the node B has
three child nodes D, E and F, and the node C has one child G. The nodes D, E, F,
and G have no child. The nodes without any child node are called external nodes
or leaf nodes, whereas, the nodes having one or more child nodes are called
internal nodes.
Graphs
Formally, a graph G(V, E) consists of a pair of two non-empty sets V and E,
where V is a set of vertices or nodes and E is a set of edges. The graph is used to
represent the non-hierarchical relationship among pairs of data elements. The data
elements become the vertices of the graph and the relationship is shown by edges
between the two vertices. For example, assume four places W, X, Y, and Z such
that
There exists some path from X to Y, X to W, Y, to W, Y to Z, and Z to W.
There is no direct path from X to Z.
We can simply represent this situation using a graph where the places W, X, Y,
and Z are represented as the nodes of the graph and a path from one place to
another place is represented by an edge between them (see Figure 1.5).
Self-Instructional
Material 7
Introduction to Data
Structure
W Y Z
NOTES
It is clear from Figure 1.5, that each node can have links with multiple other nodes.
This analogy suggests a that it is similar to a tree, however, unlike trees, there is no
root node in a graph. Further, graphs show relationships which may be non-
hierarchical in nature. It means there is no parent and child relationship. But, a tree
can be considered as a variant or a special type of graph.
1.6 ALGORITHMS
In general, a problem may be defined as a state of mind of living beings to which
they are not satisfied. Out of these problems, some of them can be solved with the
use of computers.Asolution to anysolvable problem may be defined as a sequence
of steps which when followed with the available (or allowed) resources lead to the
satisfactory situation. A description of such a sequence of steps in some specific
notation is called an algorithm.
Formally, an algorithm refers to a finite set of steps, when followed, solves
a particular problem. Here, the word ‘finite’ means that the algorithm must terminate
after performing a finite number of steps. An algorithm that goes on performing a
set of steps infinitely is not of any use. Other than finiteness, an algorithm must
have the following characteristics:
• It must take some input values supplied externally.
• It must produce some result or output.
• It must be definite, which means that all the steps in the algorithm must
be clear and unambiguous.
• It must be effective, which means each step in the algorithm must be
simple and basic so that any person can carry out these steps easily and
effectively by using a pen and paper.
There are various techniques which can be used for designing algorithms. Some
commonly used algorithm design techniques have been discussed in this section.
1.7.1 Brute Force Algorithm
Brute force is a general technique which is used for finding solutions to various
problems. In this technique, all possible candidates for the solution are listed and
then examined to check whether each candidate satisfies the problem. For example,
Self-Instructional
Material 9
Introduction to Data to find the factors of a natural number n, it will determine the number of integers
Structure
from 1 to n and then check all possible combinations of integers from 1 to n, that
will form a product (equivalent to number n) when multiplied together.
There are various algorithms where brute force technique can be applied;
NOTES
some of which are selection sort, pattern matching in strings, knapsack problem,
and travelling salesman problem. Let us discuss how this technique is used in
pattern matching. Pattern matching is the process of determining whether a given
pattern of string (say, P) occurs in another string (say, S) or not, provided the
length of string P is not greater than that of S. In other words, pattern matching
determines whether or not P is a sub-string of S. Using this algorithm, the string S
is scanned character by character. Starting from the first character, each character
of S is compared with the first character of P. When the match for the first character
is found, the next character from the pattern string P is compared with the character
adjacent to the searched character in string S. This process continues till the
complete pattern string is found. If the next character does not match, string S is
searched again for other occurrences of the first character and also the subsequent
characters of the pattern string P in the similar manner. This process continues until
a match is found or the end of pattern string P is reached. If a match is found, this
algorithm returns the position in S where the pattern string P occurs. For example,
consider a pattern string P=“ways” that is to be searched in string S = “hard
work always pays”, then this algorithm will return 13 as result.
The main advantage of brute force is that it is simple to implement. The
algorithm will definitely find a solution if it exists, since it examines all possible
solutions to a problem. However, the execution time of this algorithm is directly
proportional to the number of solutions, that is, it increases rapidlywith an increase
in the size of the problem. Therefore, it is used in situations where the size of the
problem is small or when some problem-specific heuristics are available that can
be used to limit the number of possible solutions to a controllable size. It is also
used as a baseline (an imaginary standard by which things are measured or
compared) method to develop heuristics for other search algorithms.
1.7.2 Divide and Conquer
The divide and conquer technique is one of the widely used technique is to develop
algorithms will for problems which can be divided into sub-problems (smaller in
size but similar to the actual problem) so that they can be solved efficiently. The
technique follows a top-down approach. To solve the problem, it recursively divides
the problem into a number of sub-problems, to the extent where they cannot be
sub-divided any further into more sub-problems. It then solves the sub-problems
to find solutions that are then combined together to form a solution to the actual
problem.
Some of the algorithms based on this technique are sorting, multiplying large
numbers, syntactic analysis, etc. For example, consider the merge sort algorithm
Self-Instructional
10 Material
that uses the divide and conquer technique. The algorithm is composed of steps, Introduction to Data
Structure
which are as follows:
Step 1: Divide the n-element list, into two sub-lists of n/2 elements each, such that
both the sub-lists hold half of the element in the list.
NOTES
Step 2: Recursively sort the sub-lists using merge sort.
Step 3: Merge the sorted sub-lists to generate the sorted list.
Note that the merging of sub-lists starts, only when the length of sorted sub-
lists (through recursive application) reach to 1. At this point, two sub-lists each of
length 1 are merged (combined) by placing all the elements of the list in a sorted
order.
1.7.3 Dynamic Programming
Dynamic programming is a technique that is generallyused for solving optimization
problems where the best (optimal) solution out of the available possible solutions
is to be found. One example of such a problem is the shortest path problem where,
if a person in city X has to reach city Z there would be many possible routes to
reach the city Z. The aim is to select the shortest route from all the available routes
so as to reach the destination in minimum possible time. Note that in the given
problem, all possible routes represent different solutions to the problem.
Usingdynamicprogramming, when the problemis solved, there is a possibility
that sub-problems of the same type may arise. The basic idea behind the technique
is that it stores the solutions to such sub-problems. This helps in repeated calculation
and hence, improves the efficiencyof the algorithm. The algorithms that are designed
using this technique consist of three steps, which are as follows:
• Dividing the problem into simpler sub-problems: The problem is
divided into sub-problems, such that each sub-problem has a similar
structure to the original problem.
• Finding optimal solutions to sub-problems: The solution to an original
problem is computed by combining the solutions of the sub-problems.
Therefore, for finding optimal solution to the original problem, the
solutions to sub-problems should also be optimal.
• Storing solutions to overlapping sub-problems: The identified sub-
problems consist of either unrelated sub-problems (each having an
independent solution) or common sub-problems (having similar optimal
solution). The solutions to these sub-problems are stored in a table. So,
while finding optimal solutions, if any overlapping (recurring) sub-
problems are found, the solutions stored in the table can be used. This
increases the efficiency of the dynamic programming algorithm.
Note that dynamic programming applies a bottom-up approach to solve
the problem. That is, it first finds a solution to the simplest sub-instances of the
problem and then solves the more complex instances, using the results of earlier
Self-Instructional
Material 11
Introduction to Data computed (sub) instances. Some of the well-known optimization problems where
Structure
the dynamic programming technique is used are knapsack problem, problem of
making change, shortest path problem, and chained matrix multiplication problem.
Size of Input (n) f(n) f(n2) f(n3) f(2n) f(log2n) f(n log2n)
1 1 1 1 2 0 0
5 5 25 125 32 2.3 11.6
10 10 100 1000 1024 3.3 33.2
20 20 400 8000 1048576 4.3 86.4
50 50 2500 125000 1125899906842624 5.6 282.2
From Table 1.3, it is clear that the function log2n is the slowest growing function
and the function 2n is the fastest growing function. One can observe that the function
2n does not have much difference in the values with other functions when the size
of the input is small. However, as the input size grows, there becomes a huge
difference. To verify whether a function will grow faster or slower than the other
function, we have some asymptotic or mathematical notations, which are as follows:
• Big Omega W(f):Afunction f(n) is W(g(n)), if there exists positive
values k and c such that f(n)>= c*g(n), for all n>=k. This
notation defines a lower bound for a function f(n).
• Big Theta (f): Afunction f(n) is (g(n)), if there exists positive values k, c1,
and c2 such that c1*g(n)<=f(n)<=c2*g(n), for all n>=k. This
notation defines both a lower bound as well as an upper bound for a function
f(n).
• Big Oh O(f): A function f(n) is O(g(n)), if there exists positive
values k and c such that f(n)<=c*g(n), for all n>=k. This notation
defines an upper bound for a function f(n).
• Little oh o(f): A function f(n) is o(g(n), if f(n) is O(g(n))
and f(n) is not W(g(n)) (that means, there exists no positive values k
and c such that f(n)>=c*g(n), for all n>=k.)
While comparing any two algorithms, the algorithm whose equation (that relates
to the number of operations to the size of the input) grows slowly than the other, is
considered better. It means that we are interested in finding that algorithm (out of
the two) whose equation is in the Big Oh of another one. Such algorithm will
definitely perform better than the other when the input size is large. To understand
this, suppose the equation for the first and second algorithms are f(n) = 14n2
+ 8n and g(n) = 5n3+3 respectively. In order to find which algorithm
Self-Instructional
14 Material
works better, the values of f(n) and g(n) are computed for some sample Introduction to Data
Structure
values of n, which is shown in Table 1.4 as follows:
Table 1.4 Values of f(n) and g(n) for Sample Values of n
1.10 RECURRENCES
Recurrence can be described as is an equation or inequality that defines a function
in terms of its own values. It is used to express the complexity of algorithms. For
example, the recurrence for the merge-sort algorithm can be expressed as follows:
f(n) = (1) if n = 1
2f(n / 2) + (n) if n > 1
1. Primitive data types are the data types provided by a programming language.
2. The basic idea of ADT is that the implementation of the set of operations
are written once in the program and the part of program which needs to
perform an operation on ADT.
3. Data structures are divided into two categories, namely linear data structure
and non-linear data structure.
4. A linear data structure is one in which its elements form a sequence. It
means each element in the structure has a unique predecessor and a unique
successor.
5. A stack is a linear list of data elements in which the addition of a new element
or the deletion of an element occurs only at one end.
6. A queue is a linear data structure in which the addition or insertion of a new
element occurs at one end, called ‘Rear’, and deletion of an element occurs
at other end, called ‘Front’.
1.12 SUMMARY
• Each programming language provides various data types and each data
type is represented differently within the computer’s memory.
• The memory requirement of a data type determines the permissible range
of values for that data type.
• The data types can be classified into several categories, including primitive
data types and composite data types.
• The data types provided by a programming language are known as primitive
data types or in-built data types.
Self-Instructional
Material 17
Introduction to Data • In addition to primitive and composite data types, programming languages
Structure
allow the user to define new data types (or user-defined data types) as per
his requirements.
• Generally, handlingsmallproblemsismucheasierthanhandlingcomparatively
NOTES
larger problems.
• The size of each module is kept as small as possible and if required, other
modules are invoked from it.
• Second, a well-designed modular program has modules independent of
each other’s, implementation, which will make the program easilymodifiable.
• An abstract data type (ADT) is an extension of a modular design in a way
that the set of operations of an ADT are defined at a formal, logical level,
and nowhere in ADT’s definition, it is mentioned how these operations are
implemented.
• The basic idea of ADT is that the implementation of the set of operations
are written once in the program and the part of program which needs to
perform an operation on ADT accomplishes this by invoking the required
operation.
• If there is a need to change the implementation details of an ADT, the change
will be completely transparent to the programs using it.
• The logical or mathematical model used to organize the data in main memory
is called a data structure.
• These features should be kept in mind while choosing a data structure for a
particular situation.
• The choice of a data structure depends on its simplicity and effectiveness in
processing of data.
• Data structures are divided into two categories, namely, linear data structure
and non-linear data structure.
• A linear data structure is one in which its elements form a sequence. It
means each element in the structure has a unique predecessor and a unique
successor.
• Afinite collection of homogenous elements is termed as an array.
• The elements of an arrayare always stored in a contiguous memorylocations
irrespective of the array size.
• A stack is a linear list of data elements in which the addition of a new
element or the deletion of an element occurs only at one end.
• A queue is a linear data structure in which the addition or insertion of a new
element occurs at one end, called ‘Rear’, and deletion of an element occurs
at other end, called ‘Front’.
• A tree consists of multiple nodes, with each node containing zero, one or
Self-Instructional more pointers to other nodes called child nodes.
18 Material
Introduction to Data
1.13 KEY WORDS Structure
• Traversing: It means accessing all the data elements one by one to process
all or some of them. NOTES
• Substitution method: In this method, a reasonable guess for the solution is
made and it is proved through mathematical induction.
• Recursion tree: In this method, recurrences are represented as a tree
whose nodes indicate the cost that is incurred at the various levels of
recursion.
• Searching: It is the process of finding the location of a given data element
in the data structure.
• Insertion: It means adding a new data element in the data structure. Anew
element can be inserted anywhere in the structure, such as in the beginning,
in the end, or in the middle.
• Deletion: It means removing any existing data element from the data
structure.
• Sorting: It is the process of arranging all the elements of a data structure in
a logical order such as ascending or descending order.
• Merging: It is the process of combining the elements of two sorted data
structures into a single sorted data structure.
Short-Answer Questions
1. Write a short note on abstract data types.
2. Write some points of differences between linear and non-linear data
structures.
3. What are the different operations on data structures?
Long-Answer Questions
1. “The data types provided bya programming language are known as primitive
data types or in-built data types. Different programming languages provide
different set of primitive data types.” Discuss in detail.
2. “If there is a need to change the implementation details of an ADT, the
change will be completely transparent to the programs using it.” Explain.
3. Write a detailed note on Algorithm Design Techniques.
4. What do you mean by time and space complexity of algorithms?
Self-Instructional
Material 19
Introduction to Data
Structure 1.15 FURTHER READINGS
Self-Instructional
20 Material
Arrays
UNIT 2 ARRAYS
Structure NOTES
2.0 Introduction
2.1 Objectives
2.2 Arrays (Ordered Lists)
2.2.1 Single-Dimensional Arrays
2.2.2 Multi-Dimensional Arrays
2.3 Representation of an Array
2.3.1 Memory Representation of a Single-Dimensional Array
2.3.2 Memory Representation of a Two-Dimensional Array
2.4 Answers to Check Your Progress Questions
2.5 Summary
2.6 Key Words
2.7 Self Assessment Questions and Exercises
2.8 Further Readings
2.9 Learning Outcomes
2.0 INTRODUCTION
An Array is a collection of variables that belong to the same data type. You can
also store groups of data of the same data type within an array. An Array might
belong to any of the data types. It is in fact a data structure which can store a
fixed-size collection of elements of the same data type. An array can also store a
collection of data, and can be called a collection of variables of the same kind. The
simplest type of a data structure is a linear array, which is also called a one-
dimensional array. In computer science, an array type is a data type that is meant
to describe a collection of elements. In this unit, you will learn about the arrays and
its kinds.
2.1 OBJECTIVES
Array is one of the data types that can be used for storing a list of elements. When
programmers want to store a list of elements under a single variable name, but still
want to access and manipulate an individual element of the list, then arrays are Self-Instructional
Material 21
Arrays used. Arrays can be defined as a fixed-size sequence of elements of the same data
type. These elements are stored at contiguous memory locations and can be
accessed sequentially or randomly. The programmer can access a particular element
of an array by using one or more indices or subscripts. If only one subscript is
NOTES used then the array is known as a single-dimensional array. If more than one
subscript is used then the array is known as a multi-dimensional array.
2.2.1 Single-Dimensional Arrays
A single-dimensional array is defined as an array in which onlyone subscript value
is used to access its elements. It is the simplest form of an array. Generally, a single
dimensional array is denoted as follows:
array_name[L:U]
where,
array_name = the name of the array
L = the lower bound of the array
U = the upper bound of the array
Before using an array in a program, it needs to be declared. The syntax of declaring
a single-dimensional array in C is as follows:
data_type array_name[size];
where,
data_type = data type of elements to be stored in array
array_name = name of the array
size = the size of the array indicating that the lower bound of the
array is 0 and the upper bound is size-1. Hence, the value of the
subscript ranges from 0 to size-1.
For example, in the statement int abc[5], an integer array of five elements is
declared and the array elements are indexed from 0 to 4. Once the compiler reads
a single-dimensional array declaration, it allocates a specific amount of memory
for the array. Memory is allocated to the array at the compile-time before the
program is executed.
Initializing and accessing single-dimensional array
An array can be initialized in two ways. It can be done by declaring and initializing
it simultaneously or by accepting elements of the already declared array from the
user. Once an array is declared and initialized, the elements stored in it can be
accessed any time. These elements can be accessed by using a combination of the
name of an array and subscript value.
Example 2.1: Aprogram to illustrate the initialization of two arrays and display
their elements is as follows:
#include<stdio.h>
Self-Instructional #include<conio.h>
22 Material
#define MAX 5 Arrays
void main()
{
int A[MAX]={1,2,3,4,5};
NOTES
int B[MAX], i;
clrscr();
printf(“Enter the elements of array B:\n”);
for (i=0;i<MAX;i++)
{
printf(“Enter the element: “);
scanf(“%d”, &B[i]);
}
printf(“Elements of array A: \n”);
for (i=0;i<MAX;i++)
printf(“%d\t”, A[i]);
printf(“\nElements of array B: \n”);
for (i=0;i<MAX;i++)
printf(“%d\t”, B[i]);
getch();
}
The output of the program is as follows:
Enter the elements of array b:
Enter a value: 6
Enter a value: 7
Enter a value: 8
Enter a value: 9
Enter a value: 10
Elements of array a:
1 2 3 4 5
Elements of array b:
6 7 8 9 10
In this example, an array Ais declared and initialized simultaneouslyand the elements
for the array B are accepted from the user, then the elements of both the arrays
are displayed.
Once an array is declared and initialized, various operations such as
traversing, searching, insertion, deletion, sorting, and merging can be performed
on an array. To perform any operation on an array, the elements of the array need
to be accessed. The process of accessing each element of an array is known as
traversal. Generally, the traversal of an array is performed from the element at
position 0 to element at position size-1.
Self-Instructional
Material 23
Arrays
Algorithm 2.1 Traversing an Array
traverse (ARR, size)
1. Set i = 0, sum = 0
2. Print “The elements of the array are: ”
3. While i < size //size indicates number of elements in the array
NOTES Print ARR[i]
Set sum = sum + ARR[i]
Set i = i + 1
End While
4. Print “Sum of elements of an array: ”, sum
5. End
/*Function prototype*/
void traverse(int [], int);
void main()
{
int ARR[MAX];
int i, size;
clrscr();
printf(“Enter the number of elements in array:\n”);
scanf(“%d”, &size);
printf(“Enter the elements of the array:\n”);
for (i=0;i<size;i++)
{
scanf(“%d”, &ARR[i]);
}
traverse(ARR, size);
getch();
}
Self-Instructional
24 Material
printf(“%d “, ARR[i]); Arrays
sum+=ARR[i];
}
printf(“\nSum of elements of an array: %d”, sum);
NOTES
}
The output of the program is as follows:
Enter the number of elements in array: 5
Enter the elements of the array:
12 23 34 45 56
The elements of the array are:
12 23 34 45 56
Sum of elements of an array: 170
2.2.2 Multi-Dimensional Arrays
Multi-dimensional arrays can be described as ‘arrays of arrays’.Amulti-dimensional
array of dimension n is a collection of elements, which are accessed with the help
of nsubscript values. Most of the high-level languages, including C, support arrays
with more than one dimension. However, the maximum limit of an arraydimension
is compiler dependent.
The syntax of declaring a multi-dimensional array in C is as follows:
element_type array_name[a][b][c] ..............[n];
where,
element_type = the data type of array
array_name = name of the array
[a][b][c] ............. [n] = array subscripts
The arrays of three or more dimensions are not often used because of their huge
memory requirements and the complexity involved in their manipulation. Hence,
only two-dimensional and three-dimensional arrays have been discussed in brief
in this unit.
Two-dimensional arrays
A two-dimensional array is one in which two subscript values are used to access
an array element. They are useful when the elements being processed are to be
arranged in rows and columns (matrix form).
Generally, a two-dimensional array is represented as as follows:
A[Lr : Ur, Lc : Uc]
where,
Lr and Lc = the lower bounds of a row and column, respectively
Ur and Uc = the upper bounds of a row and column, respectively
Self-Instructional
Material 25
Arrays The number of rows in a two-dimensional array can be calculated by using the
formula (Ur-Lr+1) and the number of columns can be calculated by using the
formula (Uc-Lc+1).
Like a single-dimensional array, a two-dimensional array also needs to be
NOTES declared first. The syntax of declaring a two-dimensional array in C is as follows:
data_type array_name
[row_size][column_size];
For example, in the statement int a[3][3], an integer array of three rows
and three columns is declared. Once a compiler reads a two-dimensional array
declaration, it allocates a specific amount of memory for this array.
Initializing and accessing two-dimensional arrays
A two-dimensional arraycan be initialized in two ways just like a single-dimensional
array, i.e., by declaring and initializing the array simultaneously and by accepting
array elements from the user.
Once a two-dimensional array is declared and initialized, the array elements
can be accessed anytime. Same as one-dimensional arrays, two-dimensional array
elements can also be accessed by using a combination of the name of the array
and subscript values. The only difference is that instead of one subscript value,
two subscript values are used. The first subscript indicates the row number and
the second subscript indicates the column number of a two-dimensional arrays.
Algorithm 2.2 Traversing a Two-Dimensional Array
traverse(ARR, m, n)
Self-Instructional
26 Material
int ARR[MAX][MAX], i, j, m, n; Arrays
clrscr();
printf(“Enter the number of rows and columns of a
matrix A: “);
scanf(“%d%d”, &m, &n); NOTES
printf(“Enter the elements of matrix A: \n”);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
scanf(“%d”, &ARR[i][j]);
traverse(ARR, m, n);
getch();
}
/*Function to find sum of elements of the matrix*/
void traverse(int ARR[][MAX], int m, int n)
{
int i, j, sum=0;
printf(“Matrix A is: “);
for(i=0;i<m;i++)
{
printf(“\n”);
for(j=0;j<n;j++)
{
printf(“%d “, ARR[i][j]);
sum=sum+ARR[i][j];
}
}
printf(“\nSum of elements of a matrix is: %d”, sum);
}
The output of the program is as follows:
Enter the number of rows and columns of a matrix A: 3 3
Enter the elements of matrix A:
1 2 3
4 5 6
7 8 9
Matrix A is:
1 2 3
4 5 6
7 8 9
Sum of elements of a matrix is: 45
Self-Instructional
Material 27
Arrays Three-dimensional arrays
A three-dimensional array is defined as an array in which three subscript values
are used to access an individual array element. The three-dimensional array can
NOTES be declared as follows:
int A[3][3][3];
Algorithm 2.3 Traversing a Three-Dimensional Array
traverse(ARR)
/*Function prototype*/
void traverse(int [][MAX][MAX]);
void main()
{
int ARR[MAX][MAX][MAX], i, j, k;
clrscr();
printf(“Enter the elements of an array A(3x3x3):\n”);
for(i=0;i<MAX;i++)
for(j=0;j<MAX;j++)
for(k=0;k<MAX;k++)
scanf(“%d”, &ARR[i][j][k]);
traverse(ARR);
getch();
}
Self-Instructional
28 Material
Arrays
Self-Instructional
Material 29
Arrays
Subscript values
0 1 2 3 4
Example 2.5: Calculate the address of the fourth element of a floating point
array A[10] implemented in C. The base address of the array is 1000.
Solution: Here,
Base = 1000 Size = 4 (size of a float variable)
I = 3 L = 0 (in C)
Substituting these values in the formula Array[I] = Base + (I-L)*Size,
the required address can be calculated as follows :
Address of A[3] = 1000 + (3-0) * 4
= 1000 + 12
= 1012
Self-Instructional
30 Material
Example 2.6: Calculate the address of the element at the position –2 of an integer Arrays
array A[-4 .. 4]. The base address of the array is 2000. Also, calculate the
length of the array.
Solution: Here,
Base = 2000 Size = 2 (size of an integer variable)
I = –2 L = –4 NOTES
Substituting these values in the formula Array[I] = Base + (I-L)*Size,
the required address can be calculated as follows:
Address of A[-2] = 2000 + (–2–(–4)) * 2
= 2000+ (–2+4)*2
= 2000 + 4
= 2004
The length of the array is calculated by the formula U-L+1.
Here, U=4 and L=–4.
Hence, Length = 4–(–4)+1 = 9
Thus, the array contains 9 elements.
Self-Instructional
Material 31
Arrays Address calculation in a two-dimensional array
The address of any element of a two-dimensional array stored in the row-major
order can be calculated using the following formula:
NOTES A[I,J] = Base + Size*(c*(I-Lr) + (J-Lc))
where,
A = name of an array
I, J = position of the element whose address has to be calculated
Base = base address of the two-dimensional array
Size = size of an individual elements of the array
C = number of columns in each row
Lr = lower bound of rows
Lc = lower bound of columns
To understand the concept of calculation of an address in a two-dimensional array
in the row-major order, a few examples have been provided here.
Example 2.7: If a two-dimensional array C[5 .. 10, -5 .. 9] is stored in a row-major
order, calculate the address of C[8,-2] if the base address is 10 and each array element
requires 2 bytes of memory space.
Solution: Here,
I=8 J = –2 Base = 10 Size = 2
Lr = 5 Ur = 10 Lc = –5 Uc = 9
c = (Uc-Lc+1) = (9–(–5)+1) = 9+5+1 = 15
Substituting these values in the formula A[I,J] = Base + Size*(c*(I-Lr)+(J-Lc)), the
required address can be calculated as follows:
Address of C[8,-2] = 10 + 2*(15*(8–5)+(–2–(–5))
= 10 + 2*(15*3+3)
= 10 + 2*48
= 10 + 96
= 106
Example 2.8: The two-dimensional array A[5][10] is stored in the memory using a row-
major order. Calculate the address of the element A[2][3] if the base address is 150 and each
element requires 4 bytes of memory space.
Solution: Here (assuming array is represented in C),
I=2 J=3 Base = 150 Size = 4
Lr = 0 Ur = 4 Lc = 0 Uc = 9
c = (Uc-Lc+1) = (9-0+1) = 10
Substituting these values in the formula A[I,J] = Base + Size*(c*(I-Lr)+(J-Lc)), the
required address can be calculated as follows:
Address of A[2][3] = 150 + 4*(10*(2–0)+(3–0))
= 150 + 4*23
= 150 + 92
= 242
Self-Instructional
32 Material
where, Arrays
Example 2.10: The two-dimensional array A[5][10] is stored in memory using the
column-major order. Calculate the address of the element A[2][3] if the base address is 150
and each element requires 4 bytes of memory space.
Solution: Here (assuming array represented in C),
I=2 J=3 Base = 150 Size = 4
Lr = 0 Ur = 4 Lc = 0 Uc = 9
r = (Ur-Lr+1) = (4–0+1) = 5
Substituting these values in the formula A[I,J] = Base + Size*((I-Lr)+r*(J-Lc)), the
required address can be calculated as follows:
Address of A[2][3] = 150 + 4*((2–0)+5*(3–0))
= 150 + 4*17
= 150 + 68
= 218
Self-Instructional
Material 33
Arrays
2.4 ANSWERS TO CHECK YOUR PROGRESS
QUESTIONS
2.5 SUMMARY
• Array is one of the data types that can be used for storing a list of elements.
• Arrays can be defined as a fixed-size sequence of elements of the same
data type.
• The programmer can access a particular element of an array by using one
or more indices or subscripts.
• If only one subscript is used then the array is known as a single-dimensional
array.
• A single-dimensional array is defined as an array in which onlyone subscript
value is used to access its elements.
• Once an array is declared and initialized, various operations such as
traversing, searching, insertion, deletion, sorting, and merging can be
performed on an array.
• To perform any operation on an array, the elements of the array need to be
accessed.
• The process of accessing each element of an array is known as traversal.
• Multi-dimensional arrays can be described as ‘arrays of arrays’.A multi-
dimensional array of dimension n is a collection of elements, which are
accessed with the help of n subscript values.
• Most of the high-level languages, including C, support arrays with more
than one dimension.
• All the elements in an array are always stored next to each other.
• Each element in a single-dimensional array is associated with a unique
subscript value, starting from 0 to size-1.
Self-Instructional
34 Material
• Two-dimensional arrays are represented in a linear form to enable the storage Arrays
of elements in the contiguous memory locations.
• There are two ways in which a two- dimensional array can be represented
in the linear form which are row-major order and column-major order.
NOTES
• In a row-major order representation of a two-dimensional array, first the
elements of the first row are stored sequentially in the memory, then the
elements of the second row are stored sequentially, and so on.
Short-Answer Questions
1. Write a short note on single dimensional arrays.
2. Write in brief about multi-dimensional arrays
3. What do you mean bymemoryrepresentation of a single-dimensional arrays?
4. Describe the memory representation of a two-dimensional array.
Long-Answer Questions
1. “Once an array is declared and initialized, various operations such as
traversing, searching, insertion, deletion, sorting, and merging can be
performed on an array.” Discuss. Also explain how can an operation be
performed on an array?
2. Write a program to illustrate the traversal of an array.
3. “Multi-dimensional arrays can be described as ‘arrays of arrays’. A multi-
dimensional array of dimension n is a collection of elements, which are
accessed with the help of n subscript values. “ Discuss.
4. “A two-dimensional array is one in which two subscript values are used to
access an array element.” Discuss two-dimensional arrays in detail.
5. Write a program to illustrate the traversal of a matrix (two-dimensional array)
and finding the sum of its elements.
Self-Instructional
Material 35
Arrays
2.8 FURTHER READINGS
Self-Instructional
36 Material
Stack
BLOCK - II
LINEAR DATA STRUCTURE
NOTES
UNIT 3 STACK
Structure
3.0 Introduction
3.1 Objectives
3.2 Stack Related Terms and Operations on Stack
3.3 Answers to Check Your Progress Questions
3.4 Summary
3.5 Key Words
3.6 Self Assessment Questions and Exercises
3.7 Further Readings
3.8 Learning Outcomes
3.0 INTRODUCTION
A stack is a linear data structure in which an element can be added or removed
only at one end called the top of the stack. In the terminology related to stacks,
the insert and delete operations are known as PUSH and POP operations
respectively. The last element added to the stack is the first element to be removed,
that is, the elements are removed in the opposite order in which they are added to
the stack. Hence, a stack works on the principle of last in first out, and is also
known as a last-in-first out (LIFO) list. In this unit, you will learn about the stack
organisation and operations on stack.
3.1 OBJECTIVES
Top = –1
2
Top = 1
1 1 NOTES
Top = 0
(a) Stack after pushing the element 1 (b) Stack after pushing the element 2
3
Top = 2
2
2
Top = 1 1
1
Top = 0
(d) Stack after popping the element 3 (e) Stack after popping the element 2
Empty
stack
2
Top = 1
Fig. 3.2 Various States of Stack after Push and Pop Operations
To implement a stack as an array in C language, the following structure named
Stack needs to be defined as follows:
struct stack
{
int item[MAX]; /*MAX is the maximum size of the
array*/
int Top;
Self-Instructional
Material 39
Stack Algorithm 3.1 Push Operation on Stack
push(s, element) //s is a pointer to stack
clrscr();
printf(“\n\tMain Menu”);
printf(“\n1. Push”);
NOTES
printf(“\n2. Pop”);
printf(“\n3. Exit\n”);
printf(“\nEnter your choice: “);
scanf(“%d”, &choice);
switch(choice)
{
case 1: printf(“\nEnter the value to be inserted:
“);
scanf(“%d”, &value);
push(&s, value);
getch();
break;
case 2: value=pop(&s);
if (value==0)
printf(“\nUnderflow: Stack is empty!”);
else
printf(“\nPopped item is: %d”, value);
getch();
break;
case 3: exit();
default: printf(“\nInvalid choice!”);
}
}while(1);
}
void createstack(stk *s)
{
s->Top=-1;
}
void push(stk *s, int element)
{
if (isfull(s))
{
printf(“\nOverflow: Stack is full!”);
return;
}
s->Top++;
Self-Instructional
Material 41
Stack s- >item[s->Top]=element;
printf(“\nValue is pushed onto the stack...”);
}
int pop(stk *s)
NOTES
{
int popped;
if (isempty(s))
return 0;
popped=s->item[s->Top];
s->Top—;
return popped;
}
int isempty(stk *s)
{
if (s->Top==-1)
return True;
else return False;
}
int isfull(stk *s)
{
if (s->Top==MAX-1)
return True;
else return False;
}
The output of the program is as follows:
Main Menu
1. Push
2. Pop
3. Exit
Enter your choice: 1
Enter the value to be inserted: 23
Value is pushed onto the stack...
Main Menu
1. Push
2. Pop
3. Exit
Enter your choice: 1
Enter the value to be inserted: 35
Value is pushed onto the stack...
Main Menu
Self-Instructional 1. Push
42 Material
2. Pop Stack
3. Exit
Enter your choice: 1
Enter the value to be inserted: 40
NOTES
Value is pushed onto the stack...
Main Menu
1. Push
2. Pop
3. Exit
Enter your choice: 2
Popped item is: 40
Main Menu
1. Push
2. Pop
3. Exit
Enter your choice: 2
Popped item is: 35
Main Menu
1. Push
2. Pop
3. Exit
Enter your choice: 2
Popped item is: 23
Main Menu
1. Push
2. Pop
3. Exit
Enter your choice: 2
Underflow: Stack is empty!
Main Menu
1. Push
2. Pop
3. Exit
Enter your choice: 3
Self-Instructional
Material 43
Stack
3.3 ANSWERS TO CHECK YOUR PROGRESS
QUESTIONS
3.4 SUMMARY
• A stack can be organized (represented) in the memory either as an array or
as a singly-linked list.
• Though array representation is a simple technique, it provides less flexibility
and is not very efficient with respect to memory utilization.
• When a stack is organized as an array, a variable named Top is used to
point to the top element of the stack.
• An array representation of a stack is static, but linked list representation is
dynamic in nature
• When a stack is organized as an array, a variable named Top is used to
point to the top element of the stack. Initially, the value of Top is set as -1 to
indicate an empty stack.
• Overflow occurs when a stack is full and there is no space for a new element
and an attempt is made to push a new element.
• When a stack is organized as an array, a variable named Top is used to
point to the top element of the stack.
• Similarly, before removing the top element from the stack, it is necessary to
check the condition of underflow.
• To POP (or remove) an element from a stack, the element at the top of the
stack is assigned to a local variable and then Top is decremented by one.
• Overflow: It occurs when a stack is full and there is no space for a new
element and an attempt is made to push a new element.
• Stack: It is an abstract data type that serves as a collection of elements,
with two principal operations: push, which adds an element to the collection,
and pop, which removes the most recently added element that was not yet
removed.
Self-Instructional
44 Material
Stack
3.6 SELF ASSESSMENT QUESTIONS AND
EXERCISES
1. What is a stack?
2. How is a stack organized?
3. What do you mean by overflow in a stack?
Long-Answer Questions
1. Write a program to implement a stack as an array.
2. How can you insert elements in a stack? Explain.
3. Write a note on the operations on stack.
Self-Instructional
Material 45
Representation of Stack
UNIT 4 REPRESENTATION OF
STACK
NOTES
Structure
4.0 Introduction
4.1 Objectives
4.2 Application and Implementation of Stack
4.2.1 Converting Infix Notation to Postfix and Prefix or Polish Notations
4.3 Answers to Check Your Progress Questions
4.4 Summary
4.5 Key Words
4.6 Self Assessment Questions and Exercises
4.7 Further Readings
4.8 Learning Outcomes
4.0 INTRODUCTION
In the previous unit, you have learnt about stacks. This unit will teach you about
representation of stacks.A stack is an abstract data type and it serves as a collection
of elements, with two primary principal operations: push, and pop. Push adds an
element to the collection and pop removes the most recently added element. As
you go through this unit, you will be able to discuss the application and
implementation of stacks.
4.1 OBJECTIVES
Stacks are used where the last-in-first-out principle is required like reversing strings,
checking whether the arithmetic expression is properly parenthesized, converting
infix notation to postfix and prefix notations, evaluating postfix expressions,
implementing recursion and function calls, etc. This section discusses some of
these applications.
Self-Instructional
46 Material
Reversing Strings Representation of Stack
Once all the letters are stored in a stack, they are popped one by one. Since the
letter at the top of the stack is E, it is the first letter to be popped. The subsequent
POP operations take out the letters S, R, E, and so on. Thus, the resultant string is
the reverse of original one as shown in Figure 4.1.
Algorithm 4.1 String Reversal Using Stack
reversal(s, str)
1. Set i = 0
2. While(i < length_of_str)
Push str[i] onto the stack
Set i = i + 1
End While
3. Set i = 0
4. While(i < length_of_str)
Pop the top element of the stack and store it in str[i]
Set i = i + 1
End While
5. Print “The reversed string is: ”, str
6. End
Example 4.1: The following is a program to reverse a given string using stacks:
#include<stdio.h>
#include<conio.h>
#include<string.h>
#define MAX 101
typedef struct stack
Self-Instructional
Material 47
Representation of Stack {
char item[MAX];
int Top;
}stk;
NOTES
/*Function prototypes*/
void createstack(stk *);
void reversal(stk *, char *);
void push(stk *, char);
char pop(stk *);
void main()
{
stk s;
char str[MAX];
int i;
createstack(&s);
clrscr();
do
{
printf(“Enter any string (max %d characters): “,
MAX-1);
for(i=0;i<MAX;i++)
{
scanf(“%c”, &str[i]);
if(str[i]==’\n’)
break;
}
str[i]=’\0';
}while(strlen(str)==0);
reversal(&s, str);
getch();
}
/*Function definitions*/
void createstack(stk *s)
{
s->Top=-1;
}
void reversal(stk *s, char *str)
{
int i;
for (i=0;i<strlen(str);i++)
Self-Instructional
48 Material
push(s, str[i]); Representation of Stack
for(i=0;i<strlen(str);i++)
str[i]=pop(s);
printf(“\nThe reversed string is: %s”, str);
NOTES
}
void push(stk *s, char item)
{
s->Top++;
s->item[s->Top]=item;
}
char pop(stk *s)
{
char popped;
popped=s->item[s->Top];
s->Top—;
return popped;
}
The output of the program is as follows:
Enter any string (max 100 characters): Hello World
The reversed string is: dlroW olleH
4.2.1 Converting Infix Notation to Postfix and Prefix or Polish Notations
Another important application of stacks is the conversion of expressions from infix
notation to postfix and prefix notations. The general way of writing arithmetic
expressions is known as infix notation where the binary operator is placed between
two operands on which it operates. For simplicity, expressions containing unary
operators have been ignored. For example, the expressions ‘a+b’ and ‘(a–c)*d’,
‘[(a+b)*(d/f)–f]’ are in infix notation. The order of evaluation of these expressions
depends on the parentheses and the precedence of operators. For example, the
order of evaluation of the expression ‘(a+b)*c’ is different from that of ‘a+(b*c)’.
As a result, it is difficult to evaluate an expression in an infix notation. Thus, the
arithmetic expressions in the infix notation are converted to another notation which
can be easily evaluated by a computer system to produce a correct result.
A Polish mathematician Jan Lukasiewicz suggested two alternative notations
to represent an arithmetic expression. In these notations, the operators can be
written either before or after the operands on which they operate. The notation in
which an operator occurs before its operands is known as the prefix notation
(also known as Polish notation). For example, the expressions ‘+ab’ and ‘*–
acd’ are in prefix notation. On the other hand, the notation in which an operator
occurs after its operands is known as the postfix notation (also known as
Reverse Polish or suffix notation). For example, the expressions ‘ab+’ and
‘ac–d*’ are in postfix notation.
Self-Instructional
Material 49
Representation of Stack A characteristic feature of prefix and postfix notations is that the order of
evaluation of expression is determined bythe position of the operator and operands
in the expression. That is, the operations are performed in the order in which the
operators are encountered in the expression. Hence, parentheses are not required
NOTES for the prefix and postfix notations. Moreover, while evaluating the expression,
the precedence of operators is insignificant. As a result, they are compiled faster
than the expressions in infix notation. Note that the expressions in an infix notation
can be converted to both prefix and postfix notations. The subsequent sections
will discuss both the types of conversions.
Conversion of infix to postfix notation
To convert an arithmetic expression from an infix notation to a postfix notation, the
precedence and associativity rules of operators should always kept in mind. The
operators of the same precedence are evaluated from left to right. This conversion
can be performed either manually (without using stacks) or by using stacks.
Following are the steps for converting the expression manually:
(i) The actual order of evaluation of the expression in infix notation is determined.
This is done by inserting parentheses in the expression according to the
precedence and associativity of operators.
(ii) The expression in the innermost parentheses is converted into postfix notation
by placing the operator after the operands on which it operates.
(iii) Step 2 is repeated until the entire expression is converted into a postfix
notation.
For example, to convert the expression ‘a+b*c’ into an equivalent postfix
notation, the steps will be as follows:
(i) Since the precedence of * is higher than +, the expression b*c has to be
evaluated first. Hence, the expression is written as follows:
(a+(b*c))
(ii) The expression in the innermost parentheses, that is, b*c is converted
into its postfix notation. Hence, it is written as bc*. The expression now
becomes as follows:
(a+bc*)
(iii) Now the operator + has to be placed after its operands. The two operands
for + operator are a and the expression bc*. The expression now becomes
as follows:
(abc*+)
Hence, the equivalent postfix expression will be as follows:
abc*+
When expressions are complex, manual conversion becomes difficult. On
the other hand, the conversion of an infix expression into a postfix expression is
simple when it is implemented through stacks. In this method, the infix expression
Self-Instructional
50 Material
is read from left to right and a stack is used to temporarily store the operators and Representation of Stack
the left parenthesis. The order in which the operators are pushed on to and popped
from the stack depends on the precedence of operators and the occurrence of
parentheses in the infix expression. The operands in the infix expression are not
pushed on to the stack, rather they are directly placed in the postfix expression. NOTES
Note that the operands maintain the same order as in the original infix notation.
Algorithm 4.2 Infix to Postfix Conversion
infixtopostfix(s, infix, postfix)
1. Set i = 0
2. While (i < number_of_symbols_in_infix)
If infix[i] is a whitespace or comma
Set i = i + 1 and go to step 2
If infix[i] is an operand, add it to postfix
Else If infix[i] = ‘(’, push it onto the stack
Else If infix[i] is an operator, follow these steps:
i. For each operator on the top of stack whose precedence is greater
than or equal to the precedence of the current operator, pop the
operator from stack and add it to postfix
ii. Push the current operator onto the stack
Else If infix[i] = ‘)’, follow these steps:
i. Pop each operator from top of the stack and add it to postfix
until ‘(’ is encountered in the stack
ii. Remove ‘(’ from the stack and do not add it to postfix
End If
Set i = i + 1
End While
3. End
For example, consider the conversion of the following infix expression to a postfix
expression:
a-(b+c)*d/f
Initially, a left parenthesis ‘(’ is pushed onto the stack and the infix expression is
appended with a right parenthesis, ‘)’. The initial state of the stack, infix expression
and postfix expression are shown in Figure 4.2.
a - ( b + c ) * d / f )
Infix
Postfix
Stack
Fig. 4.2 Initial State of the Stack, Infix Expression, and Postfix Expression
infix is read from left to right and the following steps are performed:
1. The operand a is encountered, which is directly put to postfix.
2. The operator – is pushed on to the stack.
Self-Instructional
Material 51
Representation of Stack 3. The left parenthesis ‘(’ is pushed onto the stack.
4. The next element is b, which being an operand is directly put to postfix.
5. +, being an operator, is pushed onto the stack.
NOTES 6. Next, c is put to postfix.
7. The next element is the right parenthesis ‘)’ and hence, the operators at the
top of the stack are popped until ‘(’ is encountered in the stack. Till then,
the only operator in the stack above the ‘(’ is +, which is popped and put
to postfix. ‘(’ is popped and removed from the stack, as shown in
Figure 4.3(a). Figure 4.3(b) shows the current position of stack.
Stack
Stack status
a b c
Postfix
a - ( b + c * ) d / f )
+
( Infix
-
( Push to stack Pop + from stack -
and remove (
(
Fig. 4.3 Intermediate States of Postfix and Infix Expressions and the Stack
8. Then, the next element * is an operator and hence, it is pushed onto the
stack.
9. Then, d is put to postfix.
10. The next element is /. Since the precedence of / is same as the precedence
of *, the operator * is popped from the stack and / is pushed onto the
stack, as shown in Figure 4.4.
11. The operand f is directly put to postfix after which, ‘)’ is encountered.
12. On reaching ‘)’, the operators in stack before the next ‘(’ is reached and
popped. Hence, / and – are popped and put to postfix as shown in
Figure 4.4.
Self-Instructional
52 Material
13. ‘(’ is removed from the stack. Since the stack is empty, the algorithm is Representation of Stack
NOTES
Self-Instructional
Material 53
Representation of Stack Algorithm 4.3 Infix to Prefix Conversion
infixtoprefix(s, infix, prefix)
1. Set i = 0
2. While (i < number_of_symbols_in_infix)
NOTES If infix[i] is a whitespace or comma
Set i = i + 1 go to step 2
If infix[i] is an operand, add it to prefix
Else If infix[i] = ‘)’, push it onto the stack
Else If infix[i] is an operator, follow these steps:
i. For each operator on the top of stack whose precedence is greater
than or equal to the precedence of the current operator, pop the
operator from stack and add it to prefix
ii. Push the current operator onto the stack
Else If infix[i] = ‘(’, follow these steps:
i. Pop each operator from top of the stack and add it to prefix until
‘)’ is encountered in the stack
ii. Remove ‘)’ from the stack and do not add it to prefix
End If
Set i = i + 1
End While
3. Reverse the prefix expression
4. End
For example, consider the conversion of the following infix expression to a prefix
expression:
a-(b+c)*d/f
1. Set i = 0, RES=0.0
2. While (i < number_of_characters_in_postfix)
If postfix[i] is a whitespace or comma
Set i = i + 1 and continue
If postfix[i] is an operand, push it onto the stack
If postfix[i] is an operator, follow these steps:
i. Pop the top element from stack and store it in operand2
ii. Pop the next top element from stack and store it in operand1
iii. Evaluate operand2 op operand1, and store the result in
RES (op is the current operator)
iv. Push RES back to stack
End If
Set i = i + 1
End While
3. Pop the top element and store it in RES
4. Return RES
5. End
For example, consider the evaluation of the following postfix expression using
stacks:
abc+d*f/-
where,
a=6
b=3
c=6
d=5
f=9
After substituting the values of a, b, c, d and f, the postfix expression becomes
as follows:
636+5*9/-
The following are the steps performed to evaluate an expression:
1. The expression to be evaluated is read from left to right and each element is
checked to find out if it is an operand or an operator.
2. First element is 6, which being an operand is pushed onto the stack.
Self-Instructional
Material 55
Representation of Stack 3. Similarly, the operands 3 and 6 are pushed onto the stack.
4. Next element is +, which is an operator. Hence, the element at the top of
stack 6 and the next top element 3 are popped from the stack, as shown in
Figure 4.5.
NOTES
8. Expression 9*5 is evaluated and the result, that is 45, is pushed to the
Self-Instructional
back of the stack.
56 Material
9. Next element in the postfix expression is 9, which is pushed onto the stack. Representation of Stack
10. Next element is the operator /. Therefore, the two operands from the top
of the stack, that is 9 and 45, are popped from the stack and the operation
45/9 is performed. Result 5 is again pushed to the stack.
NOTES
11. Next element in the expression is –. Hence, 5 and 6 are popped from the
stack and the operation 6–5 is performed. The resulting value, that is 1, is
pushed to the stack (see Figure 4.7).
Self-Instructional
Material 57
Representation of Stack Multi-stacks
So far, programs containing a single stack have been discussed in the unit. If two
or more stacks are needed in a program, then it can be accomplished in two
NOTES ways. One way is to have a separate array for each stack in the program. This
approach has a disadvantage—if one stack needs to store larger number of
elements than the specified size and the other stack has lesser number of elements—
it is not possible to store the elements of first stack in the second stack, in spite of
the vacant space. This problem can be solved by another way, that is, by having a
single array of sufficient size to hold two or more stacks. The two stacks can be
represented efficiently in the same array, provided, one stack grows from left to
right and other grows from right to left.Also, the memoryis utilized more efficiently
in this case.
For example, consider an array stack[MAX] to hold two stacks,
stack1 and stack2. Two top variables Top1 and Top2 are required to
represent the top of the two stacks. Initially, to represent the empty stacks, Top1
is set as ‘-1’ and Top2 is set as MAX. In this case, the condition of overflow
occurs when the combined size of both the stacks exceed MAX. For this, variable
count is used that keeps track of the number of elements stored in the array.
Initially, count is set to ‘0’. Overflow occurs when the value of count exceeds
the value of MAX and an attempt is made to insert a new element.
To PUSH an element in stack1, Top1 is incremented by 1 and the
element is inserted in that position. On the other hand, to PUSH an element in
stack2, Top2 is decremented by 1 and the element is inserted in that position.
To POP an element from stack1, the element at the position indicated by Top1
is assigned to a local variable and then Top1 is decremented by 1. On the other
hand, to POP an element from stack2, the element at the position indicated by
Top2 is assigned to a local variable and then Top2 is incremented by 1. Figure
4.9 shows an array of size MAX to hold two stacks stack1 and stack2,
where stack1 grows from left to right and stack2 grows from right to left.
0 1 2 … … MAX-3 MAX-2 MAX-1
stack1 stack2
To represent two stacks in the same array, the following structure called multi-
stack needs to be defined in C language:
struct multistack
{
int item[MAX];
int Top1, Top2;
int count;
int sno; /*sno indicates the stack number (1 or
Self-Instructional
58 Material
2)*/ Representation of Stack
};
Algorithm 4.5 PUSH Operation on Multi-Stack
push(s, element) //s is a pointer to multi-stack
NOTES
1. If (s->count == MAX)
Print “Overflow: Stack is full!” and go to step 4
End If
2. If(s->sno == 1) //if element is to be inserted in stack1
Set s->Top1 = s->Top1 + 1
Set s->item[s->Top1] = element
Print “Value is pushed onto stack1...”
Set s->count = s->count + 1
End If
3. If(s->sno == 2)
Set s->Top2 = s->Top2 – 1
Set s->item[s->Top2] = element
Print “Value is pushed onto stack2...”
Set s->count = s->count + 1
End If
4. End
1. If(s->sno == 1)
If (s->Top1 == -1)
Print “Underflow! Stack1 is empty”
Return 0 and go to step 4
Else
Set popped = s->item[s->Top1]
Set s->Top1 = s->Top1 - 1
Set s->count = s->count - 1
End If
End If
2. If(s->sno == 2)
If (s->Top2 == MAX)
Print “Underflow! Stack2 is empty”
Return 0 and go to step 4
Else
Set popped = s->item[s->Top2]
Set s->Top2 = s->Top2 + 1
Set s->count = s->count - 1
End If
End If
3. Return popped
4. End
else if(s.sno==2)
printf(“\nUnderflow: Stack2 is
empty!”);
} NOTES
else
printf(“\nPopped element is: %d”, value);
getch();
break;
case 3: exit();
default: printf(“\nInvalid choice!”);
}
}while(1);
}
/*Function definitions*/
void createstack(mstk *s)
{
s->Top1=-1;
s->Top2=MAX;
s->count=0;
}
void push(mstk *s, int item)
{
if (isfull(s))
{
printf(“\nOverflow: Stack is full!”);
return;
}
if(s->sno==1)
{
s->Top1++;
s->item[s->Top1]=item;
printf(“\nValue is pushed onto stack1...”);
s->count++;
}
if(s->sno==2)
{
s->Top2—;
s->item[s->Top2]=item;
printf(“\nValue is pushed onto stack2...”);
Self-Instructional
Material 61
Representation of Stack s->count++;
}
}
int pop(mstk *s)
NOTES
{
int popped;
if (isempty(s))
return 0;
if(s->sno==1)
{
popped=s->item[s->Top1];
s->Top1—;
s->count—;
}
if(s->sno==2)
{
popped=s->item[s->Top2];
s->Top2++;
s->count—;
}
return popped;
}
int isempty(mstk *s)
{
int r;
if(s->sno==1)
{
if (s->Top1==-1)
r=True;
else
r=False;
}
if(s->sno==2)
{
if (s->Top2==MAX)
r=True;
else
r=False;
}
return r;
Self-Instructional
62 Material
} Representation of Stack
Self-Instructional
64 Material
Representation of Stack
4.3 ANSWERS TO CHECK YOUR PROGRESS
QUESTIONS
1. A characteristic feature of prefix and postfix notations is that the order of NOTES
evaluation of expression is determined by the position of the operator and
operands in the expression.
2. Stacks are used where the last-in-first-out principle is required like reversing
strings.
3. During evaluation, a stack is used to store the intermediate results of
evaluation.
4.4 SUMMARY
• Stacks are used where the last-in-first-out principle is required like reversing
strings.
• A simple application of stacks is reversing strings. To reverse a string, the
characters of a string are pushed onto a stack one by one as the string is
read from left to right.
• Once all the characters of the string are pushed onto the stack, they are
popped one by one.
• Since the character last pushed in comes out first, subsequent POP operations
result in reversal of the string.
• The general way of writing arithmetic expressions is known as infix notation
where the binary operator is placed between two operands on which it
operates.
• A characteristic feature of prefix and postfix notations is that the order of
evaluation of expression is determined by the position of the operator and
operands in the expression.
• To convert an arithmetic expression from an infix notation to a postfix
notation, the precedence and associativity rules of operators should always
kept in mind.
• The conversion of an infix expression to a prefix expression is similar to the
conversion of infix to postfix expression.
• In a computer system, when an arithmetic expression in an infix notation
needs to be evaluated, it is first converted into its postfix notation.
• Evaluation of postfix expressions is also implemented through stacks.
Self-Instructional
Material 65
Representation of Stack • Since the postfix expression is evaluated in the order of appearance of
operators, parentheses are not required in the postfix expression.
• During evaluation, a stack is used to store the intermediate results of
evaluation.
NOTES
• Since an operator appears after its operands in a postfix expression, the
expression is evaluated from left to right.
• If the element is an operand, it is pushed onto the stack.
• If two or more stacks are needed in a program, then it can be accomplished
in two ways.
Short-Answer Questions
1. Write the algorithm for reversing a string.
2. Write a short note on stacks.
3. Discuss the application of stacks.
Long-Answer Questions
1. What do you mean by implementation of stack? Discuss in detail.
2. Write a program to reverse a given string using stacks.
3. Write a detailed note on Conversion of infix to postfix notation.
4. Write a program to convert an expression from infix notation to postfix
notation.
Self-Instructional
66 Material
Preiss, Bruno. 2008. Data Structures and Algorithms with Object-Oriented Representation of Stack
Self-Instructional
Material 67
Queues
UNIT 5 QUEUES
NOTES Structure
5.0 Introduction
5.1 Objectives
5.2 Queues
5.3 Representation of Queues
5.4 Circular Queue and Deque
5.5 Priority Queue
5.6 Applications of Queues
5.7 Answers to Check Your Progress Questions
5.8 Summary
5.9 Key Words
5.10 Self Assessment Questions and Exercises
5.11 Further Readings
5.12 Learning Outcomes
5.0 INTRODUCTION
In this unit, you will learn about the queues, their representation and applications.
A Queue is an abstract data structure which is somewhat similar to Stacks. But
unlike stacks, a queue is open at both its ends. One end of a queue is always used
to insert data (called enqueue) and the other is used to remove data (called
dequeue). Queue follows the basic and simple First-In-First-Out methodology,
which means that the data item stored first will be accessed first.
5.1 OBJECTIVES
5.2 QUEUES
A queue is a linear data structure in which a new element is inserted at one end
and an element is deleted from the other end. The end of the queue from which the
Self-Instructional
68 Material
element is deleted is known as the Front and the end at which a new element is Queues
Deletion Insertion
NOTES
Front Rear
The following are the basic operations that can be performed on queues:
• Insert Operation: To insert an element at the rear of the queue
• Delete Operation: To delete an element from the front of the queue
Before inserting a new element in the queue, it is necessary to check whether there
is space for the new element. If no space is available, the queue is said to be in the
condition of overflow. Similarly, before deleting an element from the queue, it is
necessary to check whether there is an element in the queue. If there is no element
in the queue, the queue is said to be in the condition of underflow.
Self-Instructional
Material 69
Queues insert an element in the queue, Rear is incremented by one and the element is
inserted at that position.
Similarly, before we delete an element from a queue, it is necessary to test
NOTES the condition of underflow. Aqueue is in the condition of underflow (empty) when
the value of Front is –1. If a queue is not empty, the delete operation can be
performed. To delete an element from a queue, the element referred by Front is
assigned to a local variable and then Front is incremented by one.
The total number of elements in a queue at a given point of time can be calculated
from the values of Rear and Front given as follows:
Number of elements = Rear – Front + 1
To understand the implementation of a queue as an array in detail, consider
a queue stored in the memory as an array named Queue that has MAX as its
maximum number of elements. Rear and Front store the indices of the rear
and front elements of Queue. Initially, Rear and Front are set to –1 to indicate
an empty queue (refer Figure 5.2(a)).
Whenever a new element has to be inserted in a queue, Rearis incremented
by one and the element is stored at Queue[Rear]. Suppose an element 9 is to
be inserted in the queue. In this case, the rear is incremented from –1 to 0 and the
element is stored at Queue[0]. Since it is the first element to be inserted, Front
is also incremented by one to make it to refer to the first element of the queue
(refer Figure 5.2(b)). For subsequent insertions, the value of Rear is incremented
by one and the element is stored at Queue[Rear]. However, Front remains
unchanged (refer Figure 5.2(c)). Observe that the front and rear elements of the
queue are the first and last elements of the list, respectively.
Whenever, an element is to be deleted from a queue, Frontis incremented
by one. Suppose that an element is to be deleted from Queue. Then, here it must
be 9. It is because the deletion is always made at the front end of a queue. Deletion
of the first element results in the queue as shown in Figure 5.2(d). Similarly, deletion
of the second element results in the queue as shown in Figure 5.2(e). Observe that
after deleting the second element from the queue, the values of Rear and Front
are equal. Here, it is apparent that when values of Front and Rear are equal
other than –1, there is only one element in the queue. When this only element of
the queue is deleted, both Rear and Front are again made equal to –1 to
indicate an empty queue.
Further, suppose that some more elements are inserted and Rear reaches the
maximum size of the array (refer Figure 5.2(f)). This means that the queue is full
and no more elements can be inserted in it even though the space is vacant on the
left of the Front.
Self-Instructional
70 Material
0 1 2 3 4 … …. MAX-1 Queues
0 1 2 3 4 … …. MAX-1
Front=0 Rear=0
0 1 2 3 4 … …. MAX-1
9 5 3 …. .
Front=0 Rear=2
0 1 2 3 4 … …. MAX-1
5 3 …. ….
Front=1
Rear=2
0 1 2 3 4 … …. MAX-1
3 …. ….
Front=2 Rear=2
0 1 2 3 4 … …. MAX-1
3 8 2 …. …. 7
Front=2 Rear=MAX – 1
(f ) Queue having Vacant Space though Rear = MAX – 1
Fig. 5.2 Various States of a Queue after the Insert and Delete Operations
Self-Instructional
Material 71
Queues To implement a queue as an array in the C language, the following structure named
queue is used:
struct queue
{
int item[MAX];
NOTES int Front;
int Rear;
};
deleted from the memory. Figure 5.3 shows the various states of a queue after the
insert and delete operations.
Note: Since the memory is allocated dynamically, a linked queue reaches the overflow
condition when no more free memory space is available to be dynamically allocated. NOTES
Fig. 5.3 Various states of a Linked Queue after the Insert and Delete Operations
Self-Instructional
Material 73
Queues Algorithm 5.3 Insert Operation on a Linked Queue
qinsert(q, val) //val is the value to be inserted
1. Allocate memory for nptr //nptr is a pointer to the new node to be inserted
2. If nptr = NULL // checking for queue overflow
Print “Overflow: Memory not allocated!” and go to step 6
End If
NOTES 3. Set nptr->info = val
4. Set nptr->next = NULL
5. If Front = NULL //check if queue is empty
Set q->Rear = q->Front = nptr //rear and front are made to point to new
//node
Else
Set q->Rear->next = nptr
Set q->Rear = nptr //Rear is made to point to new node
End If
6. End
1. If Front = NULL
Print “Underflow: Queue is empty!”
Return 0 and go to step 7
End if
2. Set del_val = q->Front->info //del_val is the element pointed by the Front
3. Set temp = q->Front //temp is the temporary pointer to Front
4. If q->Front = q->Rear //checking if there is one element in the queue
Set q->Front = q->Rear = NULL
Else
Set q->Front = q->Front->next //making Front point to next node
End If
5. De-allocate temp //de-allocating memory
6. Return del_val
7. End
of the queue, provided it is free. The circular queue is full onlywhen all the locations
in the array are occupied. Acircular queue is shown in Figure 5.4.
NOTES
NOTES
(f ) Queue Full
Self-Instructional
76 Material
Queues
NOTES
(g) Front is Reset to Zero
Fig. 5.5 Various States of a Circular Queue after the Insert and Delete Operations
The total number of elements in a circular queue at anypoint of time can be calculated
from the current values of the rear and front indices of the queue. In case, Front
< Rear, the total number of elements = Rear – Front + 1. For instance,
in Figure 5.6(a), Front = 3 and Rear = 7. Hence, the total number of
elements in CQueue at this point of time is 7 – 3 + 1 = 5. In case, Front >
Rear, the total number of elements = Max + (Rear – Front) + 1. For
instance, in Figure 5.6(b), Front = 3 and Rear = 0. Hence, the total
number of elements in CQueue is 8 + (0 – 3) + 1.
(a)
(a)
(b)
I
(b)
Fig. 5.6 Number of Elements in a Circular Queue
Self-Instructional
Material 77
Queues Algorithm 5.5 Insert Operation on a Circular Queue
qinsert(q, val)
1. If q->Front = -1
Print “Underflow: Queue is empty!”
Return 0 and go to step 5
End If
2. Set del_val = q->CQueue[q->Front] //del_val is the value to be deleted
3. If q->Front = q->Rear // check if there is one element in the queue
Set q->Front = q->Rear = -1
Else
If q->Front = MAX-1
Set q->Front = 0
Else
Set q->Front = q->Front +1
End If
End If
4. Return del_val
5. End
Deque
A deque (short form of double-ended queue) is a linear list in which elements can
be inserted or deleted at either end but not in the middle. That is, elements can be
inserted/deleted to/from the rear end or the front end. Figure 5.7 shows the
representation of a deque.
Insertion Insertion
Deletion
Deletion
Front Rear
Self-Instructional
78 Material
Like a queue, a deque can be represented as an array or a singly linked list. Here, Queues
Self-Instructional
Material 79
Queues Algorithm 5.9 Delete Operation in the Beginning of a Deque
qdelete_beg(q)
1. If q->Front = -1
Print “Underflow: Queue is empty!”
Return 0 and go to step 5
NOTES End If
2. Set del_val = q->DQueue[q->Front]
3. If q->Front = q->Rear
Set q->Front = q->Rear = -1
Else
Set q->Front = q->Front + 1End
If
4. Return del_val
5. End
1. If q->Front = -1
Print “Underflow: DeQueue is empty!”
Return 0 and go to step 5
End If
2. Set del_val = q->DQueue[q->Rear]
3. If q->Front = q->Rear
Set q->Front = q->Rear = -1
Else
Set q->Rear = q->Rear – 1
If q->Rear = -1
Set q->Front = -1
End If
End If
4. Return del_val
5. End
Deletion
Deletion
Front Rear
Self-Instructional
80 Material
• Output Restricted Deque: It allows deletion of elements only at one end Queues
but insertion can be done at both ends refer Figure 5.9.
Insertion
Insertion NOTES
Deletion
Front Rear
A priority queue is a type of queue in which each element is assigned a priority and
the elements are added or removed according to that priority. While implementing
a priority queue, the following two rules are applied:
• The element with higher priority is processed before any element of lower
priority.
• The elements with the same priority are processed according to the order in
which they were added to the queue.
A priority queue can be represented in many ways. Here, we will discuss
the implementation of a priority queue using multiple queues.
In the multiple queue representation of a priority queue, a separate queue
for each priority is maintained. Each queue is implemented as a circular array and
has its own two variables, Front and Rear (refer Figure 5.10). The element
with the given priority number is inserted in the corresponding queue. Similarly,
whenever an element is to be deleted from the queue, it must be the element from
the highest priority queue. Note that lower priority number indicates higher priority.
Self-Instructional
Material 81
Queues Priority 1
2 5 6 5
(a)
Priority 2
4 3 9 1
Front2 Rear2
(b)
Priority 3
4 1 7
Front2 Rear2
(c)
……….
Priority n
4 3 9 1
Front n Rear n
(d)
If the size of each queue is the same, then instead of multiple one-dimensional
arrays, a single two-dimensional array can be used where the row number shows
the priority and the column number shows the position of the element within the
queue. In addition, two arrays to keep track of the front and rear positions of each
queue corresponding to each row are maintained (refer Figure 5.11).
Self-Instructional
82 Material
1 2 3 4 5 Queues
1 2 ............................ n
1 4 8 5 2
Front 2 2 3
2 9
3 NOTES
1 2 ............................ n 4
Rear 5 2 .. 4 n 3
7
1. Set flag = 0, i = 0
2. While i <= MAX-1
If NOT (q->Front[prno]) = -1 //check if not empty
Set flag = 1
Set del_val = q->CQueue[i][q->Front[i]]
If q->Front[i] = q->Rear[i]
Set q->Front[i] = q->Rear[i] = -1
Else If q->Front[i] = MAX-1
Set q->Front[i] = 0
Else
Set q->Front[i] = q->Front[i] + 1
End If
End If
Break //jump out of the while loop
End If
Set i = i +1
End While
3. If flag = 0
Return 0 and go to step 4
Else
Return del_val
End If
4. End
Self-Instructional
Material 83
Queues
5.6 APPLICATIONS OF QUEUES
into multiple queues (refer Figure 5.12). The processes are assigned to the respective
queues. The higher priority processes are executed before the lower priority
processes. For example, no batch process can run unless all the system processes
and interactive processes are executed. If a batch process is running and a system NOTES
process enters the queue, then batch process would be preempted to execute this
system process.
System Processes
Medium priority
Interactive Processes
Lowest priority
Batch Processes
In this algorithm, the processes of a lower priority may starve if the number of
processes in a higher-priority queue is high. Starvation can be prevented by two
ways. One way is to time-slice between the queues, that is, each queue gets a
certain interval of time. Another way is using a multi-level feedback queue
algorithm. In this algorithm, processes are not assigned permanently to a queue;
instead, they are allowed to move between the queues. If a process uses too
much CPU time, it is moved to lower priority. Similarly, a process that has been
waiting for too long in a lower-priorityqueue is moved to the higher-priority queue.
To implement multiple programming environments, a priorityqueue using multiple
queues can be used.
Round Robin Algorithm
The Round Robin algorithm is one of the CPU scheduling algorithms designed for
time-sharing systems. In this algorithm, the CPU is allocated to a process for a
small time interval called time quantum (generally from 10 to 100 milliseconds).
Whenever a new process enters, it is inserted at the end of the ready queue. The
CPU scheduler picks the first process from the ready queue and processes it until
the time quantum elapses. Then, the CPU switches to the next process in the
queue and the first process is inserted at the end of the queue if it has not been
finished. If the process is finished before the time quantum, the process itself releases
the CPU voluntarily and the process gets deleted from the ready queue. This
process continues until all the processes are finished. When a process is finished,
it is deleted from the queue. To implement the Round Robin algorithm, a circular
queue can be used.
Suppose there are n processes, such as P1, P2,…, Pn served by the CPU. Different
processes require different execution time. Suppose, sequence of processes arrivals
is arranged according to their subscripts, i.e., P1 comes first, then P2. Therefore, Pi
comes after Pi 1 where 1< i n. Round Robin algorithm first decides a small unit of
Self-Instructional
Material 85
Queues time called time quantum or time slice represented by τ. A time quantum generally
starts from 10 to 100 milliseconds. CPU starts services from P1.Then, P1 gets CPU
for τ instant of time; afterwards CPU switches to process P2 and so on. Now,
during time-sharing, if a process finishes its execution before the finding of its time
NOTES quantum, the process then simply releases the CPU and the next process waiting
will get the CPU immediately. When CPU reaches the end of time quantum of Pn it
returns to P1 and the same process will be repeated. For an illustration, consider
Table 5.1 for the set of processes.
Table 5.1 Table for Process and Burst Time
Process Burst Time
P1 7
P2 18
P3 5
The total required CPU time keeps 30 units for burst time as summarized in Table
5.1 and depicted in Figure 5.13.
Self-Instructional
86 Material
3. A priority queue is a type of queue in which each element is assigned a Queues
priority and the elements are added or removed according to that priority.
4. Simulation is the process of modelling a real-life situation through a computer
program.
NOTES
5.8 SUMMARY
Self-Instructional
Material 87
Queues • In the multiple queue representation of a priority queue, a separate queue
for each priority is maintained.
• If the size of each queue is the same, then instead of multiple one-dimensional
arrays, a single two-dimensional array can be used where the row number
NOTES shows the priority and the column number shows the position of the element
within the queue.
• One of the most useful applications of a queue is in simulation.
• Simulation is the process of modelling a real-life situation through a computer
program.
• If the simulation is accurate, the result of the program represents the behaviour
of the actual system accurately.
• To implement a multiprogramming environment, a multi-level queue
scheduling algorithm is used.
• If a batch process is running and a system process enters the queue, then
batch process would be preempted to execute this system process.
• To implement multiple programming environments, a priority queue using
multiple queues can be used.
• The advantage of Round Robin algorithm is in reducing the average turn-
around time.
Short-Answer Questions
1. What are queues?
2. Write a short note about representation of queues.
3. What is a circular queue?
4. List few basic operations performed on queues.
Self-Instructional
88 Material
Long-Answer Questions Queues
Self-Instructional
Material 89
Lists
UNIT 6 LISTS
NOTES Structure
6.0 Introduction
6.1 Objectives
6.2 Linked List
6.3 Singly-Linked Lists
6.4 Circular Linked Lists
6.5 Doubly-Linked Lists
6.6 Merging Lists and Header Linked List
6.7 Answers to Check Your Progress Questions
6.8 Summary
6.9 Key Words
6.10 Self Assessment Questions and Exercises
6.11 Further Readings
6.12 Learning Outcomes
6.0 INTRODUCTION
A list or sequence is an abstract data type that represents a countable number of
ordered values, where the same value may occur more than once. A linked list is
a sequence of data structures, which are held together by links. A Linked List is a
sequence of links which contains items. Each link contains a connection to another
link. A Linked list is the second most-used data structure after an array.
6.1 OBJECTIVES
A dynamic data structure is one in which the memory for elements is allocated
dynamically during run-time. The successive elements of a dynamic data structure
need not be stored in contiguous memorylocations but they are still linked together
by means of some linkages or references. Whenever a new element is inserted,
Self-Instructional
90 Material
the memory for the same is allocated dynamically and is linked to the data structure. Lists
The elements can be inserted as the long as memory is available. Thus there is no
upper limit on the number of elements in the data structure. Similarly, whenever an
element is deleted from the data structure, memory is de-allocated so that it can
be reused in the future. Linked list is an example of a dynamic data structure. It has NOTES
been explained in this section.
Linked List
A linked list is a linear collection of homogeneous elements called nodes.
Successive nodes of a linked list need not occupy adjacent memory locations.
The linear order between nodes is maintained by means of pointers. In linked
lists, insertion or deletion of nodes do not require shifting of existing nodes as in the
case of arrays; they can be inserted or deleted merely by adjusting the pointers or
links.
Depending on the number of pointers in a node or the purpose for which
the pointers are maintained, a linked list can be classified into various types such
as singly-linked list, circular-linked list and doubly-linked list. The unit will discuss
these types in detail in the subsequent sections.
A singly-linked list is also known as a linear linked list. In it, each node consists of
two fields, viz. ‘info’ and ‘next’, as shown in Figure 6.1. The ‘info’ field contains
the data and the ‘next’ field contains the address of memory location where the
subsequent node is stored. The last node of the singly-linked list contains NULLin
its ‘next’ field which indicates the end of the list.
Note: The data stored in the ‘info’ field may be a single data item of any data type
or a complete record representing a student, or an employee, or any other entity.
In this unit, however, it is assumed that the ‘info’ field contains an integer data.
A linked list contains a list pointer variable ‘Start’ that stores the address of
the first node of the list. In case, the ‘Start’ node contains NULL, the list is called
an empty list or a null list. Since each node of the list contains only a single
pointer pointing to the next node, not to the previous node—allowing traversing in
Self-Instructional
Material 91
Lists only one direction—hence, it is also referred to as a one-way list. Figure 6.2
shows a singly-linked list with four nodes.
NOTES
Operations
A number of operations can be performed on singly-linked lists. These operations
include traversing, searching, inserting and deleting nodes, reversing, sorting, and
merging linked lists. Before implementing these operations, it is important to
understand how the node of a linked list is created.
Creating a node means defining its structure, allocating memory to it, and its
initialization. As discussed earlier, the node of a linked list consists of data and a
pointer to the next node. To define a node containing an integer data and a pointer
to next node in C language, a self-referential structure can be used whose definition
is as follows:
typedef struct node
{
int info; /*to store integer type data*/
struct node *next; /*to store a pointer to next
node*/
}Node;
Node *nptr; /*nptr is a pointer to node*/
After declaring a pointer nptr to new node, the memory needs to be allocated
dynamically to it. If the memoryis allocated successfully (means no overflow), the
node is initialized. The info field is initialized with a valid value and the next
field is initialized with NULL.
Algorithm 6.1 Creation of a Node
create_node()
Now, the linked list can be formed by creating several nodes of type Node and
inserting them either in the beginning or at the end or at a specified position in the
list.
Self-Instructional
92 Material
Lists
NOTES
A linear linked list, in which the next field of the last node points back to the first
node instead of containing NULL, is termed as a circular linked list. The main
advantage of a circular linked list over a linear linked list is that bystarting with any
node in the list, its predecessor nodes can be reached. This is because when a
circular linked list is traversed, starting with a particular node, the same node is
reached at the end. Figure 6.3 shows an example of a circular linked list.
All the operations that can be performed on linear linked lists can be easily
performed on circular linked lists but with some modifications. Some of these
operations have been discussed in this section.
Note: The process of creating a node of a circular linked list is same as that of linear
linked list.
Traversing
A circular linked list can be traversed in the same way as a linear linked list, except
the condition for checking the end of list. Acircular linked list is traversed until a
node in the list is reached at, which contains address of the first node in its next
field rather than NULL as in case of a linear linked list.
Algorithm 6.2 Traversing a Circular Linked List
display(Start)
1. If Start = NULL
Print “List is empty!!” and go to step 4
End If
2. Set temp = Start //initialising temp with Start
3. Do
Print temp->info //displaying value of each node
Set temp = temp->next
While temp != Start
4. End
Self-Instructional
Material 93
Lists
6.5 DOUBLY-LINKED LISTS
In a singly-linked list, each node contains a pointer to the next node and it has no
NOTES information about its previous node. Thus, one can traverse only in one direction,
i.e., from beginning to end. However, sometimes it is required to traverse in the
backward direction, i.e., from end to beginning. This can be implemented by
maintaining an additional pointer in each node of the list that points to the previous
node. Such type of a linked list is called doubly-linked list.
Each node of a doubly-linked list consists of three fields—prev, info, a
and next (see Figure 6.4). The info field contains the data, the prev field
contains the address of the previous node, and the next field contains the address
of the next node.
of overflow, the node is initialized. The info field is initialized with a valid value
and the prev and next fields are initialized with NULL.
Algorithm 6.3 Creating a Node of a Doubly Linked List NOTES
create_node()
It must be brought to notice that all the operations that are performed on singly-
linked lists can also be performed on doubly-linked lists. In the subsequent sections,
only insertion and deletion operations on doubly-linked lists have been discussed.
Insertion
Merging Lists
NOTES
Merge lists or algorithms are a familyof algorithms that take multiple sorted lists as
a medium of input and in turn produce a single list as an output. This output contains
all the elements of the inputs lists in a neatly sorted out order. These algorithms are
then used as subroutines in various sorting algorithms, which most
famously merge sort.
Header Linked List
A header linked list is a linked list that contains a special note at the front of the list.
This special node is called a headed node and it does not contain any actual data
item that is included in the list but generally contains some useful information about
the entire linked list.
6.8 SUMMARY
Self-Instructional
96 Material
• In linked lists, insertion or deletion of nodes do not require shifting of existing Lists
nodes as in the case of arrays; they can be inserted or deleted merely by
adjusting the pointers or links.
• Depending on the number of pointers in a node or the purpose for which
the pointers are maintained, a linked list can be classified into various types NOTES
such as singly-linked list, circular-linked list and doubly-linked list.
• As memory is allocated dynamically to the linked list, a new node can be
inserted anytime in the list.
• While creating a linked list or inserting an element into a linked list, if a
request for a new node arrives, the memory manager searches through the
free- storage list for the block of desired size
• A number of operations can be performed on singly-linked lists. These
operations include traversing, searching, inserting and deleting nodes,
reversing, sorting, and merging linked lists. Creating a node means defining
its structure, allocating memory to it, and its initialization.
• A linear linked list, in which the next field of the last node points back to the
first node instead of containing NULL, is termed as a circular linked list.
• The main advantage of a circular linked list over a linear linked list is that by
starting with any node in the list, its predecessor nodes can be reached.
• A circular linked list can be traversed in the same way as a linear linked list,
except the condition for checking the end of list.
• In a singly-linked list, each node contains a pointer to the next node and it
has no information about its previous node. Thus, one can traverse only in
one direction, i.e., from beginning to end.
Short-Answer Questions
1. What is a linked list?
2. Explain singly-linked list.
3. What do you mean by doubly-linked list?
4. Differentiate between merging list and header linked list.
Self-Instructional
Material 97
Lists Long Answer Questions
1. “A dynamic data structure is one in which the memory for elements is
allocated dynamically during run-time.” Explain.
NOTES 2. “The last node of the singly-linked list contains NULL in its ‘next’ field
which indicates the end of the list.” Explain with examples.
3. “A number of operations can be performed on singly-linked lists.” Elabotrate.
4. “All the operations that are performed on singly- linked lists can also be
performed on doubly-linked lists.” Explain.
Self-Instructional
98 Material
Operation on Linked Lists
7.0 INTRODUCTION
In the previous unit you have studied about lists. Now that you have got an
understanding of the basic concepts behind linked list and their types, its time to
dive into the common operations that can be performed. This unit will basically
discuss the insertion and deletion operations on the linked lists.
7.1 OBJECTIVES
To insert a node in the beginning of a list, the next field of the new node (pointed
to by nptr) is made to point to the existing first node and the Start pointer is
modified to point to the new node as shown in Figure 7.1.
Self-Instructional
Material 99
Operation on Linked Lists
NOTES
Insertion at end
To insert a node at the end of a linked list, the list is traversed up to the last node
and the next field of this node is modified to point to the new node. However, if
the linked list is initially empty then the new node becomes the first node and
Start points to it. Figure 7.2(a) shows a linked list with a pointer variable
temp pointing to its first node and Figure 7.2(b) shows temp pointing to the last
node and the next field of last node pointing to the new node.
(a)
Self-Instructional
100 Material
Operation on Linked Lists
NOTES
(b)
Deletion
Like insertion, nodes can be deleted from the linked list at any point of time and
from any position. Whenever a node is deleted, the memory occupied by the node
is de-allocated. It must be noted that while performing deletions, the immediate
predecessor of the node to be deleted must be keep track of. Thus, two temporary
pointer variables are used (except in case of deletion from beginning), while
traversing the list.
Note: A situation where the user tries to delete a node from an empty linked list is
termed as underflow.
Self-Instructional
102 Material
Operation on Linked Lists
NOTES
Self-Instructional
Material 103
Operation on Linked Lists Algorithm 7.5 Deletion from the End
delete_end(Start)
Self-Instructional
104 Material
Algorithm 7.6 Deletion from a Specified Position Operation on Linked Lists
delete_pos(Start)
Searching
Searching a value for example item in a linked list means finding the position of
a node, which stores item as its value. If item is found in the list, the search is
successful and the position of that node is displayed. However, if item is not
found till the end of list, then search is unsuccessful and an appropriate message is
displayed. It must be noted that the linked list may be in a sorted or an unsorted
order. Therefore, two search algorithms are discussed, one for sorted and another
for an unsorted linked list.
Note: Only linear search can be performed on linked lists.
1. If Start = NULL
Print “List is empty!!” and go to step 7
End If
2. Set ptr = Start //ptr pointing to the first node
3. Set pos = 1
4. Read item //item is the value to be searched
5. While ptr != NULL //traversing up to the last node
If item = ptr->info
Print “Value found at position”, pos and go to step 7
Else
Set ptr = ptr->next //moving ptr to point to next node Set
pos = pos + 1
End If
End While
6. Print “Value not found” //search unsuccessful
7. End
Self-Instructional
Material 105
Operation on Linked Lists Searching in a sorted list
The process of searching an item in a sorted (ascending order) linked list is similar
to that of an unsorted linked list. However, while comparing, once the value of any
NOTES node exceeds item (the value to be searched), the search is stopped immediately.
In such a case, the list is not required to be traversed completely.
Algorithm 7.8 Searching in a Sorted List
search_sort(Start)
1. If Start = NULL
Print “List is empty!!” and go to step 7
End If
2. Set ptr = Start //ptr pointing to the first node
3. Set pos = 1
4. Read item
5. While ptr->next != NULL //traversing up to the last node
If item < ptr->info //comparing item with the value of current
node
Print “Value not found” and go to step 7
Else If item = ptr->info
Print “Value found at position”, pos and go to step 7
Else
Set ptr = ptr->next //moving ptr to point to next node
Set pos = pos + 1
End If
End While
6. Print “Value not found” //search unsuccessful
7. End
Reversing
To reverse a singly-linked list, the list is traversed up to the last node and links of
the nodes are reversed such that the first node of the list becomes the last node
and the last node becomes the first. For this, three pointer variables like save,
ptr and temp are used. Initially, temp points to Start and both ptr and
save point to NULL. While traversing the list, temp points to the current node,
ptr points to the node previously pointed to by temp and save points to the
node previously pointed to by ptr. The links between the nodes are reversed by
making the next field of the node pointed to by ptr to point to the node
pointed to by save. At the end of traversing, temp points to NULL, ptr points
to last node, and save points to the second last node of the list. Then Start is
made to point to the node pointed to by ptr in order to make the last node as the
first node of the list. Figure 7.7 shows the process of reversing a linked list.
(a)
Self-Instructional
106 Material
Operation on Linked Lists
NOTES
(b)
(c)
(d)
(e)
(f)
Fig. 7.7 Reversal of a Linked List
Self-Instructional
Material 107
Operation on Linked Lists Algorithm 7.9 Reversing a Singly-Linked List
reverse(Start)
The following program shows the searching and reversing operations on a singly-
linked list. It must be noted that to simplify a program the linked list is built by
creating nodes and inserting them at the end of a list.
(a)
(b)
Fig. 7.8 Insertion in the Beginning
Self-Instructional
108 Material
Algorithm 7.10 Insertion in the Beginning Operation on Linked Lists
insert_beg(Start)
1. If Start = NULL
Print “Underflow: List is empty!” and go to step 8
End If
2. Set temp = Start
3. Set ptr = temp
4. While ptr->next != Start //traversing up to the last node
Set ptr = ptr->next
End While
5. Set Start = Start->next //Start pointing to the next node
6. Set ptr->next = Start //last node pointing to new first node
7. Deallocate temp //deallocating memory
8. End
Self-Instructional
110 Material
field of save is made to point to Start and the memory occupied by the last Operation on Linked Lists
node, i.e., pointed to by temp is de-allocated. Figure 7.11 shows the deletion of
a node from the end of a circular linked list.
NOTES
Note: The process of deleting a node from a specified position in a circular linked list
is same as that of a singly-linked list.
To insert a new node in the beginning of a doubly-linked list, a pointer, for example
nptr to new node is created. The next field of the new node is made to point
to the existing first node and prev field of the existing first node (that has become
the second node now) is made to point to the new node. After that, Start is
modified to point to the new node. Figure 7.12 shows the insertion of node in the
beginning of a doubly-linked list.
Self-Instructional
Material 111
Operation on Linked Lists
NOTES
Self-Instructional
112 Material
Operation on Linked Lists
Algorithm 7.15 Insertion at the End
insert_end(Start)
Self-Instructional
Material 113
Operation on Linked Lists Algorithm 7.16 Insertion at a Specified Position
insert_pos(Start)
Deletion
To delete a node from the beginning of a doubly-linked list, a pointer variable, for
example, temp is used to point to the first node. Then Start is modified to point
to the next node and the prev field of this node is made to point to NULL. After
that, the memory occupied by the node pointed to by temp is de-allocated. Figure
7.15 shows the deletion of a node from the beginning of a doubly-linked list.
1. If Start = NULL
Print “Underflow: List is empty!” and go to step 6
End If
2. Set temp = Start //temp points to the node to be deleted
3. Set Start = Start->next //making Start to point to next node
4. Set Start->prev = NULL
5. Deallocate temp //de-allocating memory
6. End
Note: The process of deleting node from the end of a doubly-linked list is same as that
of singly-linked list.
Self-Instructional
114 Material
Deletion from a specified position Operation on Linked Lists
To delete a node from a position, for example, pos, as specified by the user, the
list is traversed up to the position pos, using pointer variables temp and
save. At the end of traversing, temp points to the node at pos position and NOTES
save points to the node at pos-1 position. For simplicity, another pointer
variable ptr is used to point to the node at pos+1 position. Then the next
field of the node at pos-1 position (pointed to by save) is made to point to the
node at pos+1 position (pointed to by ptr). In addition, the field prev of the
node at pos+1, position (pointed to by ptr) is made to point to the node at
pos-1 position (pointed to by save). After that, the memory occupied by the
node pointed to by temp is de-allocated. Figure 7.16 shows the deletion of a
node at the third position from a doubly-linked list.
1. If Start = NULL
Print “Underflow: List is empty!” and go to step 8
End If
2. Set temp = Start
3. Read pos
4. Call count_node(temp) //counting total number of nodes in count
variable
5. If pos > count OR pos = 0
Print “Invalid position!” and go to step 6
End If
6. If pos = 1
Set Start = Start->next //deleting the first node
Start->prev = NULL
Else
Set i = 1
While i < pos //traversing up to the node at pos
position
Set save = temp //save pointing to the node at pos-1
position
Set temp = temp->next //making temp to point to next node
Set i = i + 1
End While
Set ptr = temp->next
Set save->next = ptr
Set ptr->prev = save
End If
7. Deallocate temp //de-allocating memory
8. End
Note: A doubly-linked list, in which the next field of the last node points to the first
node instead of ‘NULL’, is termed as a doubly circular linked list.
Self-Instructional
Material 115
Operation on Linked Lists
NOTES
7.6 SUMMARY
• To insert a node at the end of a linked list, the list is traversed up to the last
node and the next field of this node is modified to point to the new node.
• To insert a node at a position pos as specified by the user, the list is traversed
up to pos-1 position
• Like insertion, nodes can be deleted from the linked list at any point of time
and from any position.
• Whenever a node is deleted, the memory occupied by the node is de-
allocated.
• It must be noted that while performing deletions, the immediate predecessor
of the node to be deleted must be keep track of.
• To delete a node from the beginning of a linked list, the address of the first
node is stored in a temporary pointer variable temp and Start is modified to
point to the second node in the linked list.
• To delete a node from the end of a linked list, the list is traversed up to the
last node.
• To delete a node from a position pos as specified by the user, the list is
traversed up to pos position using pointer variables temp and save.
Self-Instructional
116 Material
• Searching a value for example item in a linked list means finding the position Operation on Linked Lists
of a node, which stores item as its value. If item is found in the list, the
search is successful and the position of that node is displayed.
• To reverse a singly-linked list, the list is traversed up to the last node and
links of the nodes are reversed such that the first node of the list becomes NOTES
the last node and the last node becomes the first.
• The links between the nodes are reversed by making the next field of the
node pointed to by ptr to point to the node pointed to by save.
• To delete a node from the beginning of a circular linked list, Start is modified
to point to the second node and field next of the last node is made to point
to the new first node.
• Pointer ptr is used for traversing the list and at the end of traversing, it stores
the address of the last node.
• To delete a node from the end of a circular linked list, two pointer variables
save and temp are used.
• To insert a new node in the beginning of a doubly-linked list, a pointer, for
example nptr to new node is created.
Short-Answer Questions
1. What are lists?
2. Write an algorithm to insert a node at the end in linked lists.
3. Write an algorithm to delete a node in the linked list?
Long-Answer Questions
1. Write a detailed note on insertion and deletion of operations in linked list.
2. What do you mean by insertion and deletion in circular linked list? Explain
in detail.
3. Write a detailed report on insertion and deletion in doubly-linked lists.
Self-Instructional
Material 117
Operation on Linked Lists
7.9 FURTHER READINGS
Self-Instructional
118 Material
Traversal
UNIT 8 TRAVERSAL
Structure NOTES
8.0 Introduction
8.1 Objectives
8.2 Traversing Linked Lists
8.3 Representation of Linked List
8.4 Answers to Check Your Progress Questions
8.5 Summary
8.6 Key Words
8.7 Self Assessment Questions and Exercises
8.8 Further Readings
8.9 Learning Outcomes
8.0 INTRODUCTION
In the previous unit, you have learnt about the insertion and deletion operations on
linked lists. In this unit, you will learn about the traversing and representation of
linked lists. Traversing means to access the elements of the lists for searching an
element, find the position for insertion etc.
8.1 OBJECTIVES
Traversing
Traversing a list means accessing the elements of a linked list, one by one, to
process all or some of the elements. For example, to display values of the nodes,
the number of nodes counted, or a particular item in the list is searched, then
traversing is required. Alist can be traversed by using a temporary pointer variable
temp, which will point to the node that is currently being processed. Initially,
temp points to the first node, processes that element, moves temp point to the
next node using the statement temp=temp->next, processes that element,
and moves on as long as the last node is not reached, that is, until temp becomes
NULL.
Self-Instructional
Material 119
Traversal Algorithm 8.1 Traversing a List
display(Start)
Another example of traversing a linked list is counting the number of nodes in the
linked list, which is described in the algorithm as illustrated here.
Algorithm 8.2 Counting the Number of Nodes
count_node(Start)
1. Set count = 0
2. Set temp = Start //initialising temp with Start
3. While temp != NULL //traversing the list
Set count = count + 1 //incrementing count
Set temp = temp->next
End While
4. Return count //returning total number of nodes in the
list
5. End
To maintain a linked list in the memory, two parallel arrays of equal size are used.
One array (INFO) is used for the ‘info’ field and another array (NEXT) is used
for the ‘next’ field of the nodes of a list. Values in the arrays are stored such that the
‘ith’ location in arrays ‘INFO’ and ‘NEXT’ contain the ‘info’ and ‘next’ fields of a
node of the list respectively. In addition, a pointer variable ‘Start’ is maintained in
memory that stores the starting address of the list. Figure 8.1 shows the memory
representation of a linked list where each node contains an integer.
In Figure 8.1, the pointer variable Start contains 25, which is the address of
first node of the list. This node stores the value 37 in array INFO and its
corresponding element in array NEXT stores 49 which is the address of next
node in the list and so on. Finally, the node at address 24 stores value 69 in array
INFO and NULL in array NEXT, thus, it is the last node of the list. It must be
noted that values in array INFO are stored randomly and array NEXT is used to
keep a track of the values in the list.
Memory allocation
As memory is allocated dynamically to the linked list, a new node can be inserted
anytime in the list. For this, the memory manager maintains a special linked list
known as a free-storage list or memory bank or free pool which consists of
unused memory cells. This list keeps a track of the free space available in the
Self-Instructional
120 Material
memory and a pointer to this list is stored in a pointer variable Avail (see Figure Traversal
8.2). Note that the end of the free-storage list is also denoted by storing NULL in
the last available block of memory.
NOTES
Self-Instructional
Material 121
Traversal In Figure 8.2, Avail contains 22, hence, INFO[22] is the starting point of
the free-storage list. Since NEXT[22] contains 26, INFO[26] is the next
free memory location. Similarly, other free spaces can be accessed and the NULL
in NEXT[23] indicates the end of free-storage list.
NOTES
While creating a linked list or inserting an element into a linked list, if a
request for a new node arrives, the memory manager searches through the free-
storage list for the block of desired size. If the block of desired size is found, it
returns a pointer to that block. However, sometimes there is no space available,
i.e., the free-storage list is empty. This situation is termed as overflow and the
memory manager replies accordingly.
1. To maintain a linked list in the memory, two parallel arrays of equal size are
used.
2. Traversing a list means accessing the elements of a linked list, one by one,
to process all or some of the elements.
3. As memory is allocated dynamically to the linked list, a new node can be
inserted anytime in the list.
8.5 SUMMARY
Self-Instructional
122 Material
• To maintain a linked list in the memory, two parallel arrays of equal size are Traversal
used.
• As memory is allocated dynamically to the linked list, a new node can be
inserted anytime in the list.
NOTES
• While creating a linked list or inserting an element into a linked list, if a
request for a new node arrives, the memory manager searches through the
free- storage list for the block of desired size.
• If the block of desired size is found, it returns a pointer to that block.
Short-Answer Questions
1. Write a short note on linked lists.
2. How are linked lists represented?
3. List the operations performed on linked lists.
Long-Answer Questions
1. “Traversing a list means accessing the elements of a linked list, one by one,
to process all or some of the elements.” Explain.
2. “As memory is allocated dynamically to the linked list, a new node can be
inserted anytime in the list.” Discuss.
3. “While creating a linked list or inserting an element into a linked list, if a
request for a new node arrives, the memory manager searches through the
free- storage list for the block of desired size.” Discuss.
Self-Instructional
Material 123
Traversal Preiss, Bruno. 2008. Data Structures and Algorithms with Object-Oriented
Design Patterns in C++. London: John Wiley and Sons.
Pandey, Hari Mohan. 2009. Data Structures and Algorithms. New Delhi: Laxmi
Publications.
NOTES
Goodrich Michael, Tamassia Roberto and Michael H. Goldwasser. 2014. Data
Structures and Algorithms in Java. London: John Wiley and Sons.
McMillan, Michael. 2007. Data Structures and Algorithms Using C#.
Cambridge, UK: Cambridge University Press.
Louise I. Shelly 2020 Dark Commerce
Self-Instructional
124 Material
Trees
BLOCK - III
NON-LINEAR DATA STRUCTURE
NOTES
UNIT 9 TREES
Structure
9.0 Introduction
9.1 Objectives
9.2 Binary Trees
9.2.1 Forms/Types of Binary Tree
9.2.2 Binary Tree Representations
9.3 Answers to Check Your Progress Questions
9.4 Summary
9.5 Key Words
9.6 Self Assessment Questions and Exercises
9.7 Further Readings
9.8 Learning Outcomes
9.0 INTRODUCTION
A tree is a widely used abstract data type also called an ADT, or data structure.
This ADT simulates a hierarchical tree structure that has a root value and subtrees
of children with a parent node; these are represented as a set of linked nodes.
A binary tree is made up of nodes, where each node contains a ‘left’ and ‘right’
reference, and a data element. The topmost node in the tree is called the root.
Nodes that go with the same parent are called siblings. In this unit you will learn in
detail about trees.
9.1 OBJECTIVES
A binary tree is a special type of tree, which can either be empty or has finite set of
nodes such that one of the nodes is designated as root node and remaining nodes
are partitioned into two sub trees of root node known as left sub tree and right sub
Self-Instructional
Material 125
Trees tree. The nonempty left sub tree and the right sub tree are also binary trees. Unlike
general tree each node in binary tree is restricted to have only two child nodes.
Consider a sample binary tree T shown in Figure 9.1.
Level 1 B C
Level 3 G H
T1, left
sub tree
In Figure 9.1, the topmost node Ais the root node of the tree T. Each node
in this tree has zero or at the most two child nodes. The nodes A, B and D have
two child nodes, node C has only one child node, and the nodes G, H, E and F are
leaf nodes having no child nodes. The nodes B, C, D are internal nodes having
child as well as parent nodes. Some basic terms associated with binary trees are:
• Ancestor and descendant: Node N1 is said to be an ancestor of
node N2. N1 is the parent node of N2 or so on, whereas, node N2 is
said to be the descendant of node N1. The node N2 is said to be left
descendant of node N1 if it belongs to left sub tree of N1 and is said to
be the right descendant of N1 if it belongs to right sub tree of N1. In
binary tree shown in Figure 9.1, node Ais ancestor of node H and node
H is left descendent of node A.
• Degree of a node: Degree of a node is equal to the number of its child
nodes. In binary tree shown in Figure 9.1, the nodes A, B and D have
degree 2, node C has degree 1 and nodes G, H, E and F have degree 0.
• Level: Since binary tree is a multilevel data structure, each node belongs
to a particular level number. In binary tree shown in Figure 9.1, the root
node A belongs to level 0, its child nodes belongs to level 1, child nodes
of nodes B and C belong to level 2, and so on.
• Depth (or height): Depth of the binary tree is the highest level number
of any node in a binary tree. In binary tree shown in Figure 9.1, the
nodes G and H are nodes with highest level number 3. Hence, the depth
of the binary tree is 3.
• Siblings: The nodes belonging to the same parent node are known as
sibling nodes. In binary tree shown in Figure 9.1, nodes B and C are
sibling nodes as they have same parent node, that is, A. Similarly, the
nodes D and E are also sibling nodes.
Self-Instructional
126 Material
• Edge: Edge is a line connecting any two nodes. In binary tree shown in Trees
Figure 9.1, there exists an edge between nodes A and B, whereas, there
is no edge between the nodes B and C.
• Path: Path between the two nodes x and y is a sequence of consecutive
NOTES
edges being followed from node x to y. In binary tree shown in Figure
9.1, the path between the nodes A and H is A->B->D->H. Similarly, the
path from A to F is A->C->F.
9.2.1 Forms/Types of Binary Tree
There are various forms of binary trees that are formed by imposing certain
restrictions on them. Some of the variations of binary trees are—complete binary
tree and extended binary tree.
Complete Binary Tree
A binary tree is said to be complete binary tree if all the leaf nodes of the tree are
at the same level. Thus, the tree has maximum number of nodes at all the levels
(Figure 9.2).
At any level n of binary tree, there can be at the most 2n nodes. That is,
At n = 0, there can be at most 20 = 1 node.
At n = 1, there can be at most 21 = 2 nodes.
At n = 2, there can be at most 22 = 4 nodes.
At level n, there can be at most 2n nodes.
A
B C
D E F G
I J K L M N O
H
Self-Instructional
Material 127
Trees
A
B C
NOTES
D E C F
G H
3 4 5 6
D I P T
0 1 2 3 4 5 6
M G R D I P T
Self-Instructional
128 Material
The numbers assigned to the nodes indicates the position (index value) of an array Trees
at which that particular node is stored. The array representation of this tree is
shown in Figure 9.4(b). It can be observed that if any node is stored at position p,
then its left child node is stored at 2*p+1 position and its right child node is
stored at 2*p+2 position. For example, in Figure 9.4(b), the node G is stored at NOTES
position 1, its left child node D is stored at position 3 (2*1+1) and its right child
node is stored at position 4 (2*1+2). Notice that if any of the nodes in the tree has
empty sub trees (except the leaf nodes), the nodes forming the part of these empty
sub trees are also numbered and their values in the corresponding position in the
array is NULL. For example, consider a binary tree shown in Figure 9.5(a), its
array representation is shown in Figure 9.5(b).
0
A
1 2
B C
4 5 6
3
D E F
7 8 9 10 11 12 13 14
G H
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
A B C D E F G H
Fig. 9.5 Array Representation of Binary Tree with Empty Sub Trees
Self-Instructional
Material 129
Trees
0
A
1 2
B
NOTES
4 5 6
3
D
7 8 9 10 11 12 13 14
G
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
A B D G
It can be observed from this array representation that most of the array
positions are NULL, leading to wastage of memory space. Due to this disadvantage
of array representation of binary trees, the linked representation of binary trees is
preferred.
Linked Representation
Linked representation is one of the most common and important wayof representing
a binary tree in memory. The linked representation of a binary tree is implemented
by using a linked list having info part and two pointers. The info part contains
the data value and two pointers, left and right are used to point to the left
and right sub tree of a node, respectively. The structure of such a node is shown in
Figure 9.7.
Pointing A Pointing
to left to right
sub tree sub tree
info part
Self-Instructional
130 Material
struct node *left; Trees
NOTES
In linked representation, a pointer variable Root of Node type is used to
point to the root node of a tree. Root variable is used for accessing the root and
the subsequent nodes of a binary tree. Since binary tree is empty in the beginning,
the pointer variable Root is initialized with NULL. The linked representation of
a sample binary tree (see Figure 9.1) is shown in Figure 9.8.
Root
B C
NULL
D E F
1. Depth of the binary tree is the highest level number of any node in a binary
tree.
2. The nodes belonging to the same parent node are known as sibling nodes.
9.4 SUMMARY
• A binary tree is a special type of tree, which can either be empty or has
finite set of nodes. The nonempty left sub tree and the right sub tree are also
binary trees.
Self-Instructional
Material 131
Trees • Degree of a node is equal to the number of its child nodes.
• Since binary tree is a multilevel data structure, each node belongs to a
particular level number.
NOTES • Depth of the binary tree is the highest level number of any node in a binary
tree.
• The nodes belonging to the same parent node are known as sibling nodes.
• There are various forms of binary trees that are formed by imposing certain
restrictions on them. Some of the variations of binary trees are—complete
binary tree and extended binary tree.
• A binary tree is said to be complete binary tree if all the leaf nodes of the
tree are at the same level.
• A binary tree is said to be extended binary tree (also known as 2-tree) if all
of its nodes are of either zero or two degree.
• Like stacks and queues, binary trees can also be represented in two ways
in memory—array (sequential) representation and linked representation.
• In array representation binary tree is represented sequentially in memory
by using single one-dimensional array.
• The numbers assigned to the nodes indicates the position (index value) of
an array at which that particular node is stored.
• Linked representation is one of the most common and important way of
representing a binary tree in memory.
Short-Answer Questions
1. Write a short note on binary trees.
2. Show a diagrammatic representation of a binary tree.
3. What do you mean by ancestor and descendent?
Self-Instructional
132 Material
Long-Answer Questions Trees
Self-Instructional
Material 133
Binary Tree
Operations/Applications
UNIT 10 BINARY TREE
OPERATIONS/
NOTES
APPLICATIONS
Structure
10.0 Introduction
10.1 Objectives
10.2 Traversing Binary trees
10.3 Binary Search Tree
10.4 Traversing a Binary Search Tree
10.5 Answers to Check Your Progress Questions
10.6 Summary
10.7 Key Words
10.8 Self Assessment Questions and Exercises
10.9 Further Readings
10.10 Learning Outcomes
10.0 INTRODUCTION
In the previous unit you have learnt about binary trees. This unit will explain about
binary tree operations and applications. A binary tree can be traversed in three
different ways— in-order, pre-order and post-order traversal. You will learn these
in detail along with the basic concepts of binary search tree.
10.1 OBJECTIVES
Traversing a binary tree refers to the process of visiting each and every node of the
tree exactly once. The three different ways in which a tree can be traversed are—
Self-Instructional
134 Material
in-order, pre-order and post-order traversal. The main difference in these traversal Binary Tree
Operations/Applications
methods is based on the order in which the root node is visited. Note that in all the
traversals the left sub tree is always traversed before the traversal of the right sub
tree. To understand these traversal methods, consider a simple binary tree T, shown
in Figure 10.1. NOTES
B C
T1, left T2, right
sub tree sub tree
D E F G
Pre-order
In pre-order traversal, the root node is visited before traversing its left and right
sub trees. Steps for traversing a nonempty binary tree in pre-order are as follows:
1. Visit the root node R.
2. Traverse the left sub tree of root node R in pre-order.
3. Traverse the right sub tree of root node R in pre-order.
For example, in binary tree T (shown in Figure 10.1), the root node A is
traversed before traversing its left sub tree and the right sub tree. In the left sub
tree T1, the root node B (of left sub tree T1) is traversed before traversing the
nodes D and E. After traversing the root node of binary tree T and traversing the
left sub tree T1, the right sub tree T2 is also traversed following the same
procedure. Hence, the resultant pre-order traversal of the binary tree T is A, B,
D, E, C, F, G.
In-order
In in-order traversal, the root node is visited after the traversal of its left sub tree
and before the traversal of its right sub tree. Steps for traversing a nonempty
binary tree in in-order are as follows:
1. Traverse the left sub tree of root node R in in-order.
2. Visit the root node R.
3. Traverse the right sub tree of root node R in in-order.
Self-Instructional
Material 135
Binary Tree For example, in binary tree T (shown in Figure 10.1), the left sub tree T1
Operations/Applications
is traversed before traversing the root node A. In the left sub tree T1, the node D
is traversed before traversing its root node B (of left sub tree T1). After traversing
the node D and B, the node E is traversed. Once the traversal of left sub tree T1
NOTES and the root node A of binary tree T is complete, the right sub tree T2 is traversed
following the same procedure. Hence, the resultant in-order traversal of the binary
tree T is D, B, E, A, F, C, G.
Post-order
In post-order traversal, the root node is visited after traversing its left and right sub
trees. Steps for traversing a nonempty binary tree in post-order are as follows:
1. Traverse the left sub tree of root node R in post-order.
2. Traverse the right sub tree of root node R in post-order.
3. Visit the root node R.
For example, in binary tree T (shown in Figure 10.1), the root node A is
traversed after traversing its left sub tree and the right sub tree. In the left sub tree
T1, the root node B (of left sub tree T1) is traversed after traversing the nodes D
and E. Similarly, the nodes of right sub tree T2 are traversed following the same
procedure. After traversing the left sub tree (T1) and right sub tree (T2), the root
node A of binary tree T is traversed. Hence, the resultant post-order traversal of
the binary tree T is D, E, B, F, G, C, A.
Self-Instructional
136 Material
binary search tree. In addition, each and every value in binary search tree is unique, Binary Tree
Operations/Applications
that is, no two nodes in it can have identical values.
66
NOTES
40 90
30 50 75 110
35 45 55 70 80 100 120
20
There are various operations that can be performed on the binary search
trees. Some of these are searching a node, insertion of a new node, traversal of a
tree and deletion of a node.
Searching a Node
Searching an element in a binary search tree is easy, since the elements in this tree
are arranged in a sorted order. The element to be searched is compared with the
value in the root node. If the element is smaller than the value in the root node, then
the searching will proceed to the left sub tree and if the element is greater than the
value in the root node, then the searching will proceed to the right sub tree. This
process is repeated until either the element to be searched is found or NULL value
is encountered.
For example, consider a sample binary search tree given in Figure 10.2.
The steps to search element 45 are given as follows:
1. Compare the element 45 with the value in root node (66). Since 45 is
smaller than 66, move it to its left sub tree.
2. Compare the element 45 with the value (40) appearing in the left sub
tree. Since 45 is greater than the 40, move it to its right sub tree.
3. Now, compare the element 45 with the value (50) appearing in the
right sub tree. Since 45 is smaller than 50, move it to its left sub tree.
4. In the next step, compare the element 45 with the value (45) appearing
in the left sub tree. Since 45 is equal to the value (45) stored in this
node, the required element is found. Therefore, terminate the
procedure.
Self-Instructional
Material 137
Binary Tree In case the value 48 is to be searched, the first four steps are same. After
Operations/Applications
the step 4, the right sub tree of 45 will be accessed, this is NULL indicating the end
of the tree. Therefore, the element is not found in the tree and the search is
unsuccessful.
NOTES
Algorithm 10.1 Searching in a Binary Search Tree
search(item, ptr)
1. If !(ptr)
Print "Element not found!" and go to step 3End
If
2. If item < ptr->info
Call search(item, ptr->left)
Else If item > ptr->info
Call search(item, ptr->right)
Else
Print "Element found."
End If
3. End
Traversing a binary search tree is same as traversing a binary tree. That is, binary
search tree can also be traversed in three different ways—pre-order, in-order and
post-order. For example, consider the tree shown in Figure 10.2. The pre-order,
in-order and post-order traversal of this tree is as follows:
Pre-order traversal: 66 40 30 20 35 50 45 55 90 75 70
80 110 100 120
In-order traversal: 20 30 35 40 45 50 55 66 70 75 80
90 100 110 120
Post-order traversal: 20 35 30 45 55 50 40 70 80 75 100
120 110 90 66
It can be observed that when a binary search tree is traversed in in-order, it
results in the sequence of elements in ascending order. The algorithms for traversing
tree in pre-order, in-order and post-order are recursive in nature, which are given
in Algorithms 10.2 to 10.4:
Self-Instructional
138 Material
Algorithm 10.2 Pre-order Traversal Binary Tree
preorder(ptr) Operations/Applications
1. If ptr != NULL
Print ptr->info //ptr is temporary pointer initialised with Root
Call preorder(ptr->left)
Call preorder(ptr->right)
NOTES
End If
2. End
1. If ptr != NULL
Call inorder(ptr->left) //ptr is temporary pointer initialised withRoot
Print ptr->info
Call inorder(ptr->right)
End If
2. End
1. If ptr != NULL
Call postorder(ptr->left) //ptr is temporary pointer initialised
with Root
Call postorder(ptr->right)
Print ptr->info
End If
2. End
Self-Instructional
Material 139
Binary Tree /*Function prototypes*/
Operations/Applications
void insert_node(int, Node **);
void search(int, Node *);
void main()
{
int choice, n;
Node *root=NULL;
do
{
clrscr();
printf(“\nMain Menu”);
printf(“\n1. Insert”);
printf(“\n2. Display in tree form”);
printf(“\n3. Pre-order traversal of tree”);
printf(“\n4. In-order traversal of tree”);
printf(“\n5. Post-order traversal of tree”);
printf(“\n6. Number of nodes”);
printf(“\n7. Number of leaves”);
printf(“\n8. Searching”);
printf(“\n9. Delete”);
printf(“\n10.Exit”);
printf(“\nEnter your choice . . . “);
scanf(“%d”, &choice);
switch(choice)
{
Self-Instructional
140 Material
case 1 : printf(“\nEnter data for new node : Binary Tree
“); Operations/Applications
scanf(“%d”, &n);
insert_node(n, &root);
NOTES
break;
case 2 : printf(“\nTree in tree form —>\n”);
if(!root)
print_treeform(root, 1);
else
printf(“Tree is empty!!”);
break;
case 3 : printf(“\nPre-order traversal of tree
—>\n\n”);
if(!root)
preorder(root);
else
printf(“Tree is empty!!”);
break;
case 4 : printf(“\nIn-order traversal of tree
—>\n\n”);
if(!root)
inorder(root);
else
printf(“Tree is empty!!”);
break;
case 5 : printf(“\nPost-order traversal of
tree —>\n\n”);
if(!root)
postorder(root);
else
printf(“Tree is empty!!”);
break;
case 6 : if(root==NULL)
nodes=0;
else
Self-Instructional
Material 141
Binary Tree nodes=1;
Operations/Applications
count_nodes(root);
printf(“\nNumber of nodes are : %d”,
nodes);
NOTES
break;
case 7 : leaves=0;
count_leaves(root);
printf(“\nNumber of leaves are : %d”,
leaves);
break;
case 8 : printf(“\nEnter value of node to be
searched : “);
scanf(“%d”, &n);
search(n, root);
break;
case 9 : printf(“\nEnter value of node to be
deleted : “);
scanf(“%d”, &n);
del_node(n, &root);
break;
case 10 : printf(“\nNormal termination of
program.”);
break;
default : printf(“\nWrong Choice !!”);
}
getch();
}while(choice!=10);
}
Self-Instructional
142 Material
(*ptr)=(Node*) malloc(sizeof(Node)); Binary Tree
Operations/Applications
(*ptr)->info=item;
(*ptr)->left=NULL;
(*ptr)->right=NULL; NOTES
}
if(item<(*ptr)->info)
insert_node(item,&((*ptr)->left));
else if(item>(*ptr)->info)
insert_node(item,&((*ptr)->right));
}
Self-Instructional
Material 143
Binary Tree
Operations/Applications
/*Funtion to print tree in in-order*/
void inorder(Node *ptr)
NOTES {
if(ptr)
{
inorder(ptr->left);
printf(“%d “, ptr->info);
inorder(ptr->right);
}
}
Self-Instructional
144 Material
if(ptr->right != NULL) Binary Tree
Operations/Applications
{
nodes++;
count_nodes(ptr->right); NOTES
}
}
}
Self-Instructional
Material 145
Binary Tree printf(“Element found.”);
Operations/Applications
}
}
NOTES
/*Funtion to delete a node form tree*/
void del_node(int item, Node **ptr)
{
Node *save;
if(!(*ptr))
{
printf(“\nItem does not exist.”);
return;
}
else
{
if(item<(*ptr)->info)
del_node(item, &((*ptr)->left));
else
if(item>(*ptr)->info)
del_node(item, &((*ptr)->right));
else if(item==(*ptr)->info)
{
save=*ptr;
if(save->right==NULL)
{
*ptr=save->left;
free(save);
}
else
if(save->left==NULL)
{
*ptr=save->right;
free(save);
}
else
Self-Instructional
146 Material
del(&(save->left), save); Binary Tree
Operations/Applications
}
}
return; NOTES
}
Self-Instructional
Material 147
Binary Tree
Operations/Applications
Enter data for new node : 66
Main Menu
1. Insert
2. Display in tree form
3. Pre-order traversal of tree
4. In-order traversal of tree
5. Post-order traversal of tree
6. Number of nodes
7. Number of leaves
8. Searching
9. Delete
10. Exit
Enter your choice . . . 2
120
110
100
90
80
75
70
66
55
50
45
40
35
30
20
Self-Instructional
148 Material
Binary Tree
Operations/Applications
Main Menu
1. Insert
2. Display in tree form NOTES
3. Pre-order traversal of tree
4. In-order traversal of tree
5. Post-order traversal of tree
6. Number of nodes
7. Number of leaves
8. Searching
9. Delete
10. Exit
Enter your choice . . . 3
66 40 30 20 35 50 45 55 90 75 70 80 110 100
120
Main Menu
1. Insert
2. Display in tree form
3. Pre-order traversal of tree
4. In-order traversal of tree
5. Post-order traversal of tree
6. Number of nodes
7. Number of leaves
8. Searching
9. Delete
10. Exit
Enter your choice . . . 4
20 30 35 40 45 50 55 66 70 75 80 90 100 110
120
Self-Instructional
Material 149
Binary Tree Main Menu
Operations/Applications
1. Insert
2. Display in tree form
Main Menu
1. Insert
2. Display in tree form
3. Pre-order traversal of tree
4. In-order traversal of tree
5. Post-order traversal of tree
6. Number of nodes
7. Number of leaves
8. Searching
9. Delete
10. Exit
Enter your choice . . . 6
Main Menu
1. Insert
2. Display in tree form
Self-Instructional
150 Material
3. Pre-order traversal of tree Binary Tree
Operations/Applications
4. In-order traversal of tree
5. Post-order traversal of tree
6. Number of nodes NOTES
7. Number of leaves
8. Searching
9. Delete
10. Exit
Enter your choice . . . 7
Main Menu
1. Insert
2. Display in tree form
3. Pre-order traversal of tree
4. In-order traversal of tree
5. Post-order traversal of tree
6. Number of nodes
7. Number of leaves
8. Searching
9. Delete
10. Exit
Enter your choice . . . 8
Main Menu
1. Insert
2. Display in tree form
3. Pre-order traversal of tree
4. In-order traversal of tree
5. Post-order traversal of tree
6. Number of nodes
7. Number of leaves
Self-Instructional
Material 151
Binary Tree 8. Searching
Operations/Applications
9. Delete
10. Exit
Main Menu
1. Insert
2. Display in tree form
3. Pre-order traversal of tree
4. In-order traversal of tree
5. Post-order traversal of tree
6. Number of nodes
7. Number of leaves
8. Searching
9. Delete
10. Exit
Enter your choice . . . 9
Main Menu
1. Insert
2. Display in tree form
3. Pre-order traversal of tree
4. In-order traversal of tree
5. Post-order traversal of tree
6. Number of nodes
7. Number of leaves
8. Searching
9. Delete
10. Exit
Enter your choice . . . 2
Self-Instructional
152 Material
Binary Tree
Operations/Applications
Tree in tree form —>
120 NOTES
110
100
90
80
66
55
50
45
40
35
30
20
Main Menu
1. Insert
2. Display in tree form
3. Pre-order traversal of tree
4. In-order traversal of tree
5. Post-order traversal of tree
6. Number of nodes
7. Number of leaves
8. Searching
9. Delete
10. Exit
Enter your choice . . . 9
Main Menu
1. Insert
2. Display in tree form
3. Pre-order traversal of tree
Self-Instructional
Material 153
Binary Tree 4. In-order traversal of tree
Operations/Applications
5. Post-order traversal of tree
6. Number of nodes
120
110
100
90
80
66
55
50
45
35
30
20
Main Menu
1. Insert
2. Display in tree form
3. Pre-order traversal of tree
4. In-order traversal of tree
5. Post-order traversal of tree
6. Number of nodes
7. Number of leaves
8. Searching
9. Delete
10. Exit
Enter your choice . . . 10
NOTES
1. Traversing a binary tree refers to the process of visiting each and every
node of the tree exactly once.
2. In pre-order traversal, the root node is visited before traversing its left and
right sub trees.
3. Searching an element in a binary search tree is easy, since the elements in
this tree are arranged in a sorted order.
10.6 SUMMARY
• Traversing a binary tree refers to the process of visiting each and every
node of the tree exactly once.
• The three different ways in which a tree can be traversed are— in-order,
pre-order and post-order traversal.
• The main difference in these traversal methods is based on the order in
which the root node is visited.
• In pre-order traversal, the root node is visited before traversing its left and
right sub trees.
• In in-order traversal, the root node is visited after the traversal of its left sub
tree and before the traversal of its right sub tree.
• In post-order traversal, the root node is visited after traversing its left and
right sub trees.
• There are various operations that can be performed on the binary search
trees. Some of these are searching a node, insertion of a new node, traversal
of a tree and deletion of a node.
• Searching an element in a binary search tree is easy, since the elements in
this tree are arranged in a sorted order.
Self-Instructional
Material 155
Binary Tree
Operations/Applications 10.7 KEY WORDS
• Traversing: It is the process of visiting each and every data item of the
NOTES data structure exactly once.
• Binary tree: It is a tree data structure in which each node has at most two
children, which are referred to as the left child and the right child.
Short-Answer Questions
1. What is binary search tree?
2. What do you mean by traversing binary trees?
3. How do you search a node in binary tree?
Long-Answer Questions
1. “The element to be searched is compared with the value in the root node. If
the element is smaller than the value in the root node, then the searching will
proceed to the left sub tree and if the element is greater than the value in the
root node, then the searching will proceed to the right sub tree.” Explain in
detail.
2. Write a program to illustrate the various operations performed on binary
search tree. NOTE: In case of deletion of a node with two child nodes,
largest value from left sub tree (in-order predecessor) is used for replacement.
3. Write the algorithms for Pre-order, In-order and Post order traversal.
Self-Instructional
156 Material
Operations on
TREE
NOTES
Structure
11.0 Introduction
11.1 Objectives
11.2 Insertion and Deletion Operations
11.3 Hashing Techniques
11.4 Answers to Check Your Progress Questions
11.5 Summary
11.6 Key Words
11.7 Self Assessment Questions and Exercises
11.8 Further Readings
11.9 Learning Outcomes
11.0 INTRODUCTION
11.1 OBJECTIVES
Insertion in a binary search tree is similar to the procedure for searching an element
in a binary search tree. The difference is that in case of insertion, appropriate null
pointer is searched where new node can be inserted. The process of inserting a
node in a binary search tree can be divided into two steps—in the first step, the
tree is searched to determine the appropriate position where the node is to be
inserted and in the second step, the node is inserted at this searched position.
Self-Instructional
Material 157
Operations on Here are two cases of insertion in a tree—first, insertion into an empty tree
Binary Tree
and second, insertion into a nonempty tree. In case the tree is initially empty, the
new node to be inserted becomes its root node. In case the tree is nonempty,
appropriate position is determined for insertion. For this, first of all the value in the
NOTES new node is compared with the root node of the tree. If the value in the new node
is less than the value in the root node, the new node is added as the left leaf if the
left sub tree is empty, otherwise the search continues in the left sub tree. On the
other hand, if the value in the new node is greater than the value in the root node,
the new node is added as the right leaf if the right sub tree is empty, otherwise the
search continues in the right sub tree.
66
40 90
30 50 75 110
35 120
For example, consider a sample binary search tree shown in Figure 11.1.
For inserting elements 20 and 80, follow the steps given:
1. Compare 20 with the value in the root node, that is, 66. Since 20 is
smaller than 66, move to the left sub tree.
2. Finding that the left pointer of root node is non-null, compare 20 with
the value (40) in this node. Since 20 is smaller than 40, move to the
left sub tree.
3. Again, the left pointer of the current node is non-null, compare 20
with the value (30) in this node. Since 20 is smaller than 30, move to
the left sub tree.
4. Now, the left pointer is null, thus 20 will be inserted at this position.
After insertion, the tree will appear as shown in Figure 11.2.
66
40 90
30 50 75 110
40 90
30 50 75 110
New inserted
35 80 120
20 node
1. If !(ptr)
Allocate memory for ptr
Set ptr->info = item
Set ptr->left = NULL
Set ptr->right = NULL
Else
If item < ptr->info
Call insert_node(item, ptr->left)
Else
Call insert_node(item, ptr->right)
End If
End If
2. End
Deleting a Node
Deletion of a node from a binary search tree involves two steps—first, searching
the desired node and second, deleting the node. Whenever a node is deleted from
a tree, it must be ensured that the tree remains a binary search tree, that is, the
sorted order of the tree must not be disturbed. The node being deleted may have
zero, one or two child nodes. On the basis of the number of child nodes to be
deleted, there are three cases of deletion which are discussed as follows:
Case 1: If the node to be deleted has no child node, it is deleted by making
its parent’s pointer pointing to NULL and de-allocating memory allocated to it. Self-Instructional
Material 159
Operations on 66
Binary Tree
40 90
NOTES 50 75 110
30
55 120
20 35 45
For example, the node with value 75 is to be deleted from the tree shown in
Figure 11.4. Since this node has no child node, its parent’s (90) left pointer will be
made to point to NULL and the memory space of the node (75) is de-allocated.
Case 2: If the node to be deleted has only one child node, it is deleted by
adjusting its parent’s pointer pointing to its only child and de-allocating memory
allocated to it.
66
90
40
50 110
30
55 120
20 35 45
For example, the node with value 110 is to be deleted from the tree shown
in Figure 11.5. Since this node has one child node, its parent’s (90) right pointer
will be made to point to its child node (120) and memory space of the node (110)
is de-allocated.
Case 3: If the node to be deleted has two child nodes, it is deleted by
replacing its value by largest value in the left sub tree (in-order predecessor) or by
smallest value in the right sub tree (in-order successor). The node whose value is
used for replacement is then deleted using case 1 or case 2.
66
90
40
120
30 Copying 50
20 35 45 55
90
35
120
30 50
20 45 55
1. If !(ptr)
Print "Item does not exist." and go to step 3
2. If item < ptr->info
Call del_node(item,&(ptr->left))
Else
If item > ptr->info
Call del_node(item,&(ptr->right))
Else
If item = ptr->info
Set save = ptr
If save->right = NULL
Set ptr = save->left
Deallocate save
Else
If save->left = NULL
Set ptr = save->right
Deallocate save
Else
Call del(&(save->left),save)
End If
End If
End If
End If
End If
3. End
1. If p->right != NULL
Call del(&(p->right),q)
Else
Set delnode = p
Set q->info = p->info
Set p = p->left
Deallocate delnode
End If
2. End
Self-Instructional
Material 161
Operations on
Binary Tree 11.3 HASHING TECHNIQUES
Self-Instructional
164 Material
Collision Resolution Techniques Operations on
Binary Tree
The main problem associated with most hashing functions is that they do not yield
distinct hash addresses for distinct keys, because the number of key values is
much larger than the number of available locations in the hash table. Due to this, NOTES
sometimes the problem called collision occurs. Since one cannot eliminate collisions
altogether, one needs some mechanisms to deal with them. There are several ways
for resolving collisions, the two most common techniques used are separate chaining
and open addressing.
Separate chaining
In this technique, a linked list of all the key values that hash to the same hash value
is maintained. Each node of the linked list contains a key value and the pointer to
the next node. Each index i (0<=i<N) in the hash table contains the address of the
first node of the linked list containing all the keys that hash to the index i. If there is
no key value that hashes to the index i, the slot contains NULL value. Therefore,
in this method, a slot in the hash table does not contain the actual key values;
rather it contains the address of the first node of the linked list containing the
elements that hash to this slot.
Consider the key values 20, 32, 41, 66, 72, 80, 105, 77, 56, and 53 that
need to be hashed using the simple hash function h(k) = k mod 10. The keys 20
and 80 hash to index 0, key 41 hashes to index 1, keys 32 and 72 hashs to index
2, key 53 hashes to index 3, key 105 hashes to index 5, keys 66 and 56 hashes to
index 6 and finally the key 77 hashes to index 7. The collision is handled using the
separate chaining (also known as synonyms chaining) technique as shown in
Figure 11.8.
Note that a new element can be inserted either at the beginning or at the end
of the list. Generally, the elements are inserted in the beginning of the list because
it is simpler to implement, and moreover, it frequently happens that the elements
which are added recently are the most likely to be accessed in the near future.
The main disadvantage of separate chaining is that it makes use of pointers,
which slows down the algorithm a bit because of the time required in allocating
and deallocating the memory. Moreover, maintaining another data structure (that
is, linked list) in addition to the hash table causes extra overheads.
Self-Instructional
Material 165
Operations on Open addressing
Binary Tree
Unlike the separate chaining method, no separate data structure is used in open
addressing because all the key values are stored in the hash table itself. Since,
NOTES each slot in the hash table contains the key value rather than the address value, a
bigger hash table is required in this case as compared to separate chaining. Some
value is used to indicate an empty slot. For example, if it is known that all the keys
are positive values, then -1 can be used to represent a free or empty slot.
To insert a key value, first the slot in the hash table to which the key value
hashes, is determined, using any hash function. If the slot is free, the key value is
inserted into that slot. In case the slot is already occupied, then the subsequent
slots, starting from the occupied slot, are examined systematically in the forward
direction, until an empty slot is found. If no empty slot is found, then an overflow
condition occurs.
In case of searching, first the slot in the hash table to which the key value
hashes is determined, using any hash function. Then, the key value stored in that
slot is compared with the key value to be searched. If they match, the search
operation is successful; otherwise alternative slots are examined systematically in
the forward direction to find the slot containing the desired key value. If no such
slot is found, then the search is unsuccessful.
The process of examining the slots in the hash table to find the location of a
key value is known as probing. The various types of probing are linear probing,
quadratic probing, and double hashing that are used in open addressing method.
Linear probing
Linear probingis the simplest approach for resolving collisions. It uses the following
hash function:
h(k, i) = [h’(k) + i] mod N
where,
h’(k) is any hash function (for simplicity we use k mod N)
i is the probe number ranging from 0 to N-1
To insert a key k in the hash table, first the slot T[h’(k)] is probed. If this slot
is empty, the key is inserted into the slot. Otherwise, the slots T[h’(k)+1],
T[h’(k)+2], T[h’(k)+3], and so on (up to T[N-1]) are probed
sequentially until an empty slot is found. If no empty slot is found up to T[N-1],
we wrap around to slots T[0], T[1], T[2], and so on until an empty slot is
found or we finally reach the slot T[h’(k)-1]. The main advantage of linear
probing is that as long as the hash table is not full, a free slot can always be found,
however, the time taken to find an empty slot can be quite large.
To understand linear probing, consider the insertion of the following keys
into the hash table with N=10.
Self-Instructional
166 Material
126, 75, 37, 56, 29, 154, 10, 99 Operations on
Binary Tree
Further consider that the basic hash function is h’(k)=k mod N.
Step 1: The key value 126 hashes to the slot 6 as follows:
h(126, 0) = (126 mod 10 + 0) mod 10 = (6 + 0) mod 10 = 6 NOTES
mod 10 = 6
Since slot 6 is empty, it is inserted into this slot.
0 1 2 3 4 5 6 7 8 9
126
Self-Instructional
Material 169
Operations on Since slot 1 is empty, 56 is inserted into this slot.
Binary Tree
0 1 2 3 4 5 6 7 8 9 10
56 37 126 75
NOTES Step 5: Next, the key value 29 hashes to the slot 7 as follows:
h(29, 0) = (29 mod 11 + 02) mod 11 = (7 + 0) mod 11 = 7
Since slot 7 is empty, it is inserted into this slot.
0 1 2 3 4 5 6 7 8 9 10
56 37 126 29 75
Step 6: Now, the key value 154 hashes to the slot 0 as follows:
h(154, 0) = (154 mod 11 + 02) mod 11 = (0 + 0) mod 11 = 0
Since slot 0 is empty, 154 is inserted into this slot.
0 1 2 3 4 5 6 7 8 9 10
154 56 37 126 29 75
Step 6: Now, the key value 152 hashes to the slot 9 as follows:
h(152, 0) = (152 mod 13 + 0*(152 mod 11)) mod 13 = (9 + 0)
mod 13 = 9
Since slot 9 is not empty, the next probe sequence is computed as follows:
h(152, 1) = (152 mod 13 + 1*(152 mod 11)) mod 13 = (9 + 9)
mod 13 = 5
Since slot 5 is empty, 152 is inserted into this slot.
0 1 2 3 4 5 6 7 8 9 10 11 12
29 56 152 126 75 37
Since the increment in double hashing depends on the value of key k, the
values that hash to the same initial slot may have different probe sequences. Thus,
double hashing almost eliminates the problem of primaryand secondary clustering
and its performance is very close to the ideal hashing. For example, the key value
35 initially hashes to slot 9 (as that of the key 152). However, the next probe
sequence for 35 is 11 (not 5 as in case of 152).
11.5 SUMMARY
Self-Instructional
Material 173
Operations on • The process of inserting a node in a binary search tree can be divided into
Binary Tree
two steps—in the first step, the tree is searched to determine the appropriate
position where the node is to be inserted and in the second step, the node is
inserted at this searched position.
NOTES
• Deletion of a node from a binary search tree involves two steps—first,
searching the desired node and second, deleting the node.
• If the node to be deleted has two child nodes, it is deleted by replacing its
value by largest value in the left sub tree (in-order predecessor) or bysmallest
value in the right sub tree (in-order successor).
• Hashing (also known as hash addressing) is generally applied to a file F
containing R records.
• Whenever a key is to be inserted in the hash table, a hash function is applied
on it, which yields an index for the key.
• Since, the keys are inserted by applying hash functions on them, searching
a key in the hash table is straightforward.
• A hash function h is simply a mathematical formula that maps the key to
some slot in the hash table T.
• There are a number of hash functions available, however, the one which is
easyto compute and ensures that two distinct values hash to different location
in the hash table is desirable.
• The main problem associated with most hashing functions is that they do
not yield distinct hash addresses for distinct keys, because the number of
key values is much larger than the number of available locations in the hash
table.
• There are several ways for resolving collisions, the two most common
techniques used are separate chaining and open addressing.
• In this technique, a linked list of all the key values that hash to the same hash
value is maintained.
• The main disadvantage of separate chaining is that it makes use of pointers,
which slows down the algorithm a bit because of the time required inallocating
and deallocating the memory.
• Unlike the separate chaining method, no separate data structure is used in
open addressing because all the key values are stored in the hash table
itself.
Self-Instructional
174 Material
• Division-remainder method: It is the simplest and most commonly used Operations on
Binary Tree
method. In this method, the key k is divided by the number of slots N in the
hash table, and the remainder obtained after division is used as an index in
the hash table.
NOTES
11.7 SELF ASSESSMENT QUESTIONS AND
EXERCISES
Short-Answer Questions
1. What do you mean by division remainder method?
2. List a few hashing techniques.
3. Draw a diagram of deletion of a node having two child nodes.
4. Write a short note about insertion and deletion operations.
Long-Answer Questions
1. “Insertion in a binary search tree is similar to the procedure for searching an
element in a binary search tree.” Explain in detail.
2. What are the various cases of insertion in a binary search tree? Explain.
3. What do you mean by deleting a node?
4. Explain the Division-remainder method in detail.
Self-Instructional
Material 175
Searching
BLOCK - IV
SEARCHING TECHNIQUES
NOTES
UNIT 12 SEARCHING
Structure
12.0 Introduction
12.1 Objectives
12.2 Searching
12.2.1 Linear Search
12.2.2 Binary Search
12.3 Answers to Check Your Progress Questions
12.4 Summary
12.5 Key Words
12.6 Self Assessment Questions and Exercises
12.7 Further Readings
12.8 Learning Outcomes
12.0 INTRODUCTION
In this unit, you will learn about various types of searching techniques. Searching is
the process of finding a given value position in a list of provided values. Searching
helps to decide whether a search key is present in the data or not. It can be defined
as thealgorithmicprocess of findingaparticular item inacollection of items. Searching
can be done on both internal data structure and on external data structures.
12.1 OBJECTIVES
12.2 SEARCHING
Linear search is one of the simplest searching techniques. In this technique, the
array is traversed sequentially from the first element until the value is found or the
end of the array is reached. While traversing, each element of the array is compared NOTES
with the value to be searched, and if the value is found the search is said to be
successful. This technique is suitable for performing a search in a small array or in
an unsorted array.
Algorithm 12.1 Linear Search
linear_search (ARR, size, item)
1. Set i = 0
2. While i < size
If ARR [i] = item //item is the value to be searched
Return i and go to step 4
End If
Set i = i + 1
End While
3. Return -1 //search unsuccessful
4. End
/*Function prototype*/
int linear_search(int ARR[] , int size , int item );
void main()
{
int ARR[MAX];
int item, size, pos, i;
do
{
clrscr();
printf(“\nEnter the size of the array (max %d): “,
MAX);
scanf(“%d”, &size);
}while(size>MAX);
printf(“\nEnter elements of the array:\n”);
for(i=0;i<size;i++)
scanf(“%d”, &ARR[i]);
printf(“\nEnter the element to be searched: “);
scanf(“%d”, &item);
pos=linear_search(ARR, size, item);
if (pos==-1)
Self-Instructional
Material 177
Searching printf(“\nElement not found”);
else
printf(“\nElement found at location: %d”, pos+1);
getch();
NOTES
}
1 2 3 4 5 6 7 NOTES
0 1 2 3 4 5 6
To search an item (say, 7) using binary search in the array ARR with
size=7, the following steps are performed.
1. Initially, set LOW=0 and HIGH=size–1. The middle of the array
is determined using the formula MID=(LOW+HIGH)/2, that is,
MID=(0+6)/2, which is equal to 3. Thus, ARR [MID]=4.
LOW MID HIGH
1 2 3 4 5 6 7
0 1 2 3 4 5 6
2. Since the value stored at ARR [3] is less than the value to be
searched, that is 7, the search process is now restricted from ARR[4]
to ARR[6]. Now LOW is 4 and HIGH is 6. The middle element of
this segment of the array is calculated as MID=(4+6)/2, that is, 5.
Thus, ARR[MID]=6.
LOW MID HIGH
5 6 7
4 5 6
3. The value stored at ARR[5] is less than the value to be searched,
hence the search process begins from the subscript 6. As ARR[6]
is the last element, the item to be searched is compared with this
value. Since ARR[6] is the value to be searched, the search is
successful.
Algorithm 12.2: Binary Search
binary_search(ARR, size, item)
1. Set LOW = 0
2. Set HIGH = size - 1
3. While LOW <= HIGH
Set MID = (LOW + HIGH) / 2
If ITEM = ARR[MID]
Return MID and go to step 5
Else If item < ARR[MID]
Set HIGH = MID – 1
Else
Set LOW = MID + 1
End If
End While
4. Return -1
5. End
Self-Instructional
Material 179
Searching Example 12.2: Aprogram to perform binary search
#include<stdio.h>
#include<conio.h>
#define MAX 20
NOTES
/*Function prototype*/
int binary_search(int ARR[], int size, int item);
void main()
{
int ARR[MAX];
int item, size, pos, i;
do
{
clrscr();
printf(“\nEnter the size of the array (max %d): “,
MAX);
scanf(“%d”, &size);
}while(size>MAX);
printf(“\nEnter elements in sorted order:\n”);
for(i=0;i<size;i++)
scanf(“%d”, &ARR[i]);
printf(“\nEnter the element to be searched: “);
scanf(“%d”, &item);
pos=binary_search(ARR, size, item);
if (pos==-1)
printf(“\nElement not found”);
else
printf(“\nElement found at location: %d”, pos+1);
getch();
}
1 7 13 19 25 31 36
0 1 2 3 4 5 6
Since the size of the array is 7, the initial value of Fm will be 8. The search
first compares the element 13 with element at index 5 (Fm-1), that is, 26. Since
13 is less than 26, the sub-list left to index 5 is considered. The size of this sub-list
is 5, therefore, new Fm will be 5. Now, the element 13 is compared with the
element at index 3 (Fm-1), that is, 13. Since, it is the desired element, the search
is successful, and the element is found at position 4.
Algorithm 12.3 Fibonacci Search
fibonacci_search(ARR, size, item)
1. Set a = 1, b = 1, c = 1
2. If (n = 0 OR n = 1)
Return 0 and go to step 3
Else
While c < n
Set c = a + b
Set a = b
Set b = c
End While
Return a
End If
3. End
Self-Instructional
182 Material
Example 12.3: A program to implement Fibonacci search Searching
#include<stdio.h>
#include<conio.h>
#define MAX 20
NOTES
/*Function prototypes*/
int fibonacci_search(int [], int, int);
int retfib(int n);
void main()
{
int ARR[MAX], size, item, pos, i;
do
{
clrscr();
printf(“\nEnter the size of the array (max %d): “,
MAX);
scanf(“%d”, &size);
}while(size>MAX);
printf(“\nEnter elements in sorted order:\n”);
for(i=0;i<size;i++)
scanf(“%d”, &ARR[i]);
printf(“\nEnter the element to be searched: “);
scanf(“%d”, &item);
pos=fibonacci_search(ARR, size, item);
if (pos==-1)
printf(“\nElement not found”);
else
printf(“\nElement found at location: %d “, pos);
getch();
}
int retfib(int n)
{
int a=1, b=1, c=1, i;
if(n==0 || n==1)
return 0;
else
{
while(c<n)
Self-Instructional
Material 183
Searching {
c=a+b;
a=b;
b=c;
NOTES
}
return a;
}
}
Self-Instructional
184 Material
Enter elements in sorted order: Searching
45
67
89
NOTES
100
120
1 7 13 19 25 31 36
0 1 2 3 4 5 6
void main()
{
int ARR[MAX];
int item, size, pos, i;
do
{
clrscr();
printf(“\nEnter the size of the array (max %d): “,
MAX);
scanf(“%d”, &size);
}while(size>MAX);
printf(“\nEnter elements in sorted order:\n”);
for(i=0;i<size;i++)
scanf(“%d”, &ARR[i]);
printf(“\nEnter the element to be searched: “);
scanf(“%d”, &item);
pos=interpol_search(ARR, size, item);
if (pos==-1)
printf(“\nElement not found”);
Self-Instructional
186 Material
else Searching
Self-Instructional
Material 187
Searching 80
100
120
180
NOTES
200
12.4 SUMMARY
Short-Answer Questions
1. Write a short note on searching.
2. What do you mean by linear search?
3. Write a note on binary search.
4. Write an algorithm for binary search.
Long-Answer Questions
1. Write a program to perform linear search.
2. Write a program to perform binary search.
3. “The binary search process is repeated until the element is found or the
array segment is reduced to a single element that is not equal to item.”
Discuss.
4. Give a detailed comparison of different search algorithms.
Self-Instructional
Material 191
Sorting
BLOCK - V
SORTING TECHNIQUES
NOTES
UNIT 13 SORTING
Structure
13.0 Introduction
13.1 Objectives
13.2 Definition
13.3 Bubble Sort
13.4 Insertion Sort
13.5 Radix Sort
13.6 Answers to Check Your Progress Questions
13.7 Summary
13.8 Key Words
13.9 Self Assessment Questions and Exercises
13.10 Further Readings
13.11 Learning Outcomes
13.0 INTRODUCTION
In the previous unit, you learnt about searching. This unit will discuss sorting. Sorting
refers to the way in which data is arranged in a particular order. Asorting algorithm
is employed to rearrange a given array elements according to a comparison
operator on the elements. This unit will first begin with the definition of sorting. It
will then discuss Bubble Sort, Insertion Sort and Radix Sort.
13.1 OBJECTIVES
13.2 DEFINITION
The process of arranging the data in some logical order is known as sorting. The
order can be ascending or descending for numeric data, and alphabetically for
character data. There are two types of sorting, namely, internal sorting and external
sorting. If all the data that is to be sorted fits entirely in the main memory, then internal
(in-memory) sorting is used.
On the other hand, if all the data that is to be sorted do not fit entirely in the
Self-Instructional main memory, external sorting is required. An external sorting requires the use of
192 Material
external memory such as disks or tapes during sorting. In external sorting, some Sorting
part of the data is loaded into the main memory, sorted using any internal sorting
technique and written back to the disk in some intermediate file. This process
continues until all the data is sorted.
NOTES
Internal Sorting
There are different internal sorting algorithms such as insertion sort, bubble sort,
selection sort, heap sort, merge sort, quick sort and bucket sort. The choice of a
particular algorithm depends on the properties of the data and the operations to
be performed on the data. For all these algorithms, we will consider an array ARR
containing n elements, which are to be sorted in an ascending order.
The bubble sort algorithm requires n-1 passes to sort an array. In the first pass,
each element (except the last) in the list is compared with the element next to it,
and if one element is greater than the other then both the elements are swapped.
After the first pass, the largest element in the list is placed at the last position.
Similarly, in the second pass the second largest element is placed at its appropriate
position. Thus, in each subsequent pass, the next largest element is placed at its
appropriate position. Since this algorithm makes the larger values to ‘bubble up’
to the end of the list, it is named bubble sort.
The bubble sort algorithm possesses an important property. This property
is that if a particular pass is made through the list without swapping any items, then
there will be no further swapping of elements in the subsequent passes. This property
can be used to eliminate the unnecessary passes once the list is sorted in the
desired order. For this, a flag variable can be used to detect if any interchange
has been made during the pass. We use flag = 0 to indicate that no swaps have
occurred in a particluar pass, therefore, no further passes are required.
To understand the bubble sort technique, consider an unsorted array shown
here.
8 7 65 5 43
The steps to sort the values stored in the array in ascending order using
bubble sort are as follows:
First pass:
1. The values 8 and 7 are compared with each other. Since 7 is smaller than 8,
both the values are swapped with each other.
2. No swapping: Next, the values 8 and 65 are compared with each other.
Since 8 is less than 65, means they are in proper order and, hence, no
swapping is required. The list remains unchanged.
No swapping
7 8 65 5 43 Self-Instructional
Material 193
Sorting 3. Elements compared: Then the values 65 and 5 are compared with each
other. Since 5 is less than 65, both the values are swapped.
Elements compared
NOTES 7 8 65 5 43
7 8 5 65 43
Elements swapped
4. Elements compared: Next, the values 65 and 43 are compared with each
other. Since 43 is less than 65, both the values are swapped.
Elements compared
7 8 5 65 43
7 8 5 43 65
Elements swapped
After the first pass, the largest value of the array (here, 65) is placed at last
position.
Second pass
1. The values 7 and 8 are compared with each other. Since 7 is smaller than 8,
no swapping is required.
2. Then the values 8 and 5 are compared. Since 8 is greater than 5, both are
swapped.
3. Next, the elements 8 and 43, and 43 and 65 are compared. Since they are
already in ascending order, they need not be swapped.
7 5 8 43 65
Third Pass
1. The values 7 and 5 are compared with each other. Since 7 is greater than 5,
both are swapped.
2. Since the remaining elements are already in ascending order, they are not
swapped.
5 7 8 43 65
Fourth Pass
1. In the fourth pass, no swapping is required as all the elements are already in
ascending order. Thus, at the end of this pass, the list is sorted in ascending
order as follows:
5 7 8 43 65
Self-Instructional
194 Material
Algorithm 13.1 Bubble Sort Sorting
bubble_sort(ARR, size)
1. Set i = 0, flag = 1
2. While (i < size-1 AND flag = 1)
Set j = 0
Set flag = 0 NOTES
While (j < size-i-1)
If (ARR[j] > ARR[j+1])
Set flag = 1 //swap will occur, hence set flag = 1
Set temp = ARR[j] //temp is temporary variable used to swap
//two values
Set ARR[j] = ARR[j+1]
Set ARR[j+1] = temp
End If
Set j = j + 1
End While
Print ARR after (i+1)th pass
Set i = i + 1
End While
3. Print “No. of passes: ”, i
4. End
/*Function prototype*/
void bubble_sort(int [], int);
void main()
{
int ARR[MAX],i, size;
do
{
clrscr();
printf(“\nEnter the size of the array (max %d): “,
MAX);
scanf(“%d”, &size);
}while(size>MAX);
printf(“\nEnter the elements of the array:\n”);
for(i=0;i<size;i++)
scanf(“%d”, &ARR[i]);
bubble_sort(ARR, size);
printf(“\nThe sorted array is: “);
for(i=0;i<size;i++)
printf(“%d “, ARR[i]);
getch();
Self-Instructional
Material 195
Sorting }
The insertion sort algorithm selects each element and inserts it at its proper position
in the earlier sorted sub-list. In the first pass, the element ARR[1] is compared NOTES
with ARR[0], and if ARR[1] and ARR[0] are not sorted, they are swapped.
In the second pass, the element ARR[2] is compared with ARR[0] and
ARR[1], and it is inserted at its proper position in the sorted sub-list containing
the elements ARR[0], ARR[1]. Similarly, during ith iteration, the element
ARR[i] is placed at its proper position in the sorted sub-list containing the elements
ARR[0], ARR[1], ARR[2],…, ARR[i-1].
In order to determine the actual position of the element (say, ARR[i]) in
the sorted sub-list containing the elements ARR[0], ARR[1], …, ARR[i-
1], the element ARR[i] is compared with all other elements to its left, until an
element ARR[j] is found such that ARR[j]<=ARR[i]. Now, to insert the
element at its actual position, all the elements ARR[i-1], ARR[i-2], ARR[i-
3],…, ARR[j+1] are shifted one position towards the right to create the space
for ARR[i], and then ARR[i] is inserted at (j+1)st position.
To understand the insertion sort algorithm, consider an unsorted array shown
here. The steps to sort the values stored in the array in ascending order using
insertion sort are given here.
7 33 20 11 6
7 33 20 11 6
7 20 33 11 6
7 20 33 11 6
7 11 20 33 6 Self-Instructional
Material 197
Sorting • Finally, the last element 6 is compared with all the elements preceding
it. Since it is smaller than all the other elements, they are shifted one
position towards right and 6 is inserted at the first position in the array.
After this pass, the array is sorted.
NOTES
7 11 20 33 6
6 7 11 20 33
1. Set i = 1
2. While (i < size)
Set temp = ARR[i]j
=i-1
While (temp < ARR[j] AND j >= 0)
Set ARR[j+1] = ARR[j]
Set j = j - 1
End While
Set ARR[j+1] = temp
Print ARR after ith passSet
i=i+1
End While
3. Print “No. of passes: ”, i-1
4. End
Since the largest element (that is, 899) consists of three digits, the array will
be sorted in three passes.
First pass
In the first pass, the digits at the units place are considered, and the elements are
placed in the corresponding buckets as follows:
Bucket Bucket Bucket Bucket Bucket Bucket Bucket Bucket Bucket Bucket
0 1 2 3 4 5 6 7 8 9
110 21 912 233 674 555 56 318 899
746
Now, the elements are retrieved from each bucket and copied into the
original array. The array now becomes:
110 21 912 233 674 555 56 746 318 899
Second pass
In the second pass, the digits at the tens place are considered, and the elements
are placed in the corresponding buckets as follows:
Bucket Bucket Bucket Bucket Bucket Bucket Bucket Bucket Bucket Bucket
0 1 2 3 4 5 6 7 8 9
110 21 233 746 555 674 899
912 56
Self-Instructional 318
200 Material
Now, the elements are retrieved from each bucket and copied into the Sorting
Now, the elements are retrieved from each bucket and copied into the
original array. After this pass, the array is sorted as follows:
21 56 110 233 318 555 674 746 899 912
Self-Instructional
Material 201
Sorting Example 13.3: A program to show sorting of an array using radix sort
#include<stdio.h>
#include<conio.h>
#define MAX 20
NOTES
/*Function prototype*/
void bucket_sort(int [], int);
void main()
{
int ARR[MAX], i, size;
do
{
clrscr();
printf(“\nEnter the size of the array (max %d): “,
MAX);
scanf(“%d”, &size);
}while(size>MAX);
printf(“\nEnter the elements of the array:\n”);
for(i=0;i<size;i++)
scanf(“%d”, &ARR[i]);
bucket_sort(ARR, size);
printf(“\nThe sorted array is: “);
for(i=0;i<size;i++)
printf(“%d “, ARR[i]);
getch();
}
Self-Instructional
202 Material
{ Sorting
largest/=10;
digitcount++;
}
for(i=0;i<digitcount;i++) NOTES
{
for(k=0;k<10;k++)
buckcount[k]=0;
for(j=0;j<size;j++)
{
r=(ARR[j]/divisor)%10;
bucket[buckcount[r]++][r]=ARR[j];
}
t=0;
for(j=0;j<10;j++)
for(k=0;k<buckcount[j];k++)
{
ARR[t++]=bucket[k][j];
}
printf(“\nArray after pass %d: “,i+1);
for(j=0;j<size;j++)
printf(“%d “, ARR[j]);
divisor*=10;
}
printf(“\nNo. of passes: %d “, digitcount);
}
The output of the program is
Enter the size of the array (max 20): 10
Self-Instructional
Material 203
Sorting
Array after pass 1: 110 21 912 233 674 555 56 746 318 899
Array after pass 2: 110 912 318 21 233 746 555 56 674 899
Array after pass 3: 21 56 110 233 318 555 674 746 899 912
NOTES
No. of passes: 3
The sorted array is: 21 56 110 233 318 555 674 746 899 912
1. The process of arranging the data in some logical order is known as sorting.
2. There are two types of sorting, namely, internal sorting and external sorting.
3. An important property of the bubble sort algorithm is that if a particular
pass is made through the list without swapping any items, then there will be
no further swapping of elements in the subsequent passes.
4. The radix or bucket sort algorithm sorts the numbers by considering
individual digits starting from right to left.
13.7 SUMMARY
• The process of arranging the data in some logical order is known as sorting.
The order can be ascending or descending for numeric data, and
alphabetically for character data.
• There are two types of sorting, namely, internal sorting and external sorting
• If all the data that is to be sorted do not fit entirely in the main memory,
external sorting is required
• The bubble sort algorithm requires n-1 passes to sort an array. In the first
pass, each element (except the last) in the list is compared with the element
next to it, and if one element is greater than the other then both the elements
are swapped.
• The insertion sort algorithm selects each element and inserts it at its proper
position in the earlier sorted sub-list.
Self-Instructional
204 Material
• The radix or bucket sort algorithm sorts the numbers byconsidering individual Sorting
digits starting from right to left.
Short-Answer Questions
1. What are the two types of sorting?
2. What does external sorting require?
3. How does insertion sort work?
Long-Answer Questions
1. Describe the steps to sort the values stored in the array in ascending order
using bubble sort.
2. Write a program showing sorting of an array using bubble sort and insertion
sort.
3. Examine the steps to sort values using radix sort.
14.0 INTRODUCTION
In the previous unit, you were introduced to sorting. You learnt about sorting
techniques such as insertion sorting, bubble sorting and bucket sorting. In this unit,
you will be introduced with other sorting techniques such as selection sort, quick
sort and tree sort.
14.1 OBJECTIVES
In selection sort, first, the smallest element in the list is searched and is swapped
with the first element in the list (that is, it is placed at the first position). Then, the
second smallest element is searched and swapped with the second element in the
list (that is, it is placed at the second position), and so on.
Like bubble sort algorithm, the selection sort also requires n-1 passes to
sort an array containing n elements. However, there is a slight difference between
Self-Instructional
206 Material
the selection sort and the bubble sort algorithms. In selection sort, the smallest Other Sorting Techniques
element is the first one to be placed at its correct position, then the second smallest
element takes its position, and so on. Whereas, in bubble sort, the largest element
is the first one to be placed at its appropriate position, then the second largest
element, and so on. NOTES
To understand the selection sort algorithm, consider an unsorted array shown
here.
8 33 6 21 4
The steps to sort the values stored in the array in ascending order using
selection sort are as follows:
1. In the first pass, the entire array is scanned for the smallest element,
which is 4 in this list. It is swapped with the first element, that is, 8.
Thus, 4 is placed at its correct position and is not used for any further
comparisons.
2. In the second pass, the smallest element is searched from the last four
elements, which is 6. It is swapped with the second element, that
is, 33.
4 33 6 21 8
4 6 33 21 8
3. In the third pass, the smallest element is searched from the last three
elements, which is 8. This value is swapped with the third element,
that is, 33.
4 6 33 21 8
4 6 8 21 33
4. In the fourth pass, the smallest element is searched from the last two
elements. Since 21 is smaller than 33, therefore, no changes are made
in the list obtained after the third pass, and the list is sorted in ascending
order. The sorted list is as follows.
4 6 8 21 33
Self-Instructional
Material 207
Other Sorting Techniques Algorithm 14.1 Selection Sort
selection_sort(ARR, size)
1. Set i = 0
2. While (i < size-1)
Set small = ARR[i]Set
NOTES pos = i
Set j = i + 1
While (j < size) //searching the smallest element in unsorted list
If (ARR[j]<small)
Set small = ARR[j]Set
pos = j
End If
Set j = j + 1
End While
Set ARR[pos] = ARR[i] //placing the smallest element at its correct position
Set ARR[i] = small
Print ARR after (i+1)th passSet
i=i+1
End While
3. Print “No. of passes: ”, i
4. End
/*Function prototype*/
void selection_sort(int [], int);
void main()
{
int ARR[MAX],i, size;
do
{
clrscr();
printf(“\nEnter the size of the array (max %d): “,
MAX);
scanf(“%d”, &size);
}while(size>MAX);
printf(“\nEnter the elements of the array:\n”);
for(i=0;i<size;i++)
scanf(“%d”, &ARR[i]);
selection_sort(ARR, size);
printf(“\nThe sorted array is: “);
Self-Instructional
208 Material
for(i=0;i<size;i++) Other Sorting Techniques
printf(“%d “, ARR[i]);
getch();
}
NOTES
Self-Instructional
Material 209
Other Sorting Techniques
Self-Instructional
210 Material
element referred to by pivot. If the element referred to by pivot Other Sorting Techniques
is smaller than the element referred to by end, they are swapped and
step 2 is performed. Otherwise, beg is incremented by 1 and step 3
is continued.
NOTES
The first pass terminates when pivot, beg and end all refer to the same
array element. This indicates that the pivot element is placed at its final position.
The elements to the left of this element are smaller than this element, and elements
to its right are greater.
To understand the quick sort algorithm, consider an unsorted array:
8 33 6 21 4
The steps to sort the values stored in the array in ascending order using
quick sort are as follows:
1. Initially, the index 0 in the list is chosen as the pivot, and the index variables
beg and end are initialized with index 0 and n–1 respectively.
8 33 6 21 4
2. The scanning of elements is started from the end of the list. ARR[pivot]
(that is, 8) is greater than ARR[end] (that is, 4). Therefore, they are swapped.
8 33 6 21 4
pivot end
beg
3. Now, the scanning of elements is started from the beginning of the list. Since
ARR[pivot] (that is, 8) is greater than ARR[beg] (that is 33), therefore beg
is incremented by 1, and the list remains unchanged.
4 33 6 21 8
beg pivot
end
4. Next, the element ARR[pivot] is smaller than ARR[beg], they are swapped.
4 8 6 21 33
pivot end
beg
Self-Instructional
Material 211
Other Sorting Techniques 5. Again, the list is scanned from right to left. Since, ARR[pivot] is smaller
than ARR[end], therefore the value of end is decremented by 1, and the list
remains unchanged.
NOTES 4 8 6 21 33
pivot end
beg
pivot end
beg
beg pivot
end
8. Now, the list is scanned from left to right. Since, ARR[pivot] is greater than
ARR[beg], value of beg is incremented by 1. The list remains unchanged.
4 6 8 21 33
pivot
beg
end
At this point since the variables pivot, beg and end all refer to the
same element, the first pass is terminated and the value 8 is placed at its
appropriate position. The elements to its left are smaller than 8, and elements
to its right are greater than 8. The same process is applied on the left and
right sub-lists.
Self-Instructional
212 Material
Algorithm 14.2 Quick Sort Other Sorting Techniques
quick_sort(ARR, size, lb, ub)
1. Set i = 1 //i is a static integer variable
2. If lb < ub
Call splitarray(ARR, lb, ub) //returning an integer value pivot
Print ARR after ith pass NOTES
Set i = i + 1
Call quick_sort(ARR, size, lb, pivot – 1) //recursive call to quick_sort() to
//sort left sub list
Call quick_sort(ARR, size, pivot + 1, ub); //recursive call to quick_sort() to
//sort right sub list
Else if (ub=size-1)
Print “No. of passes: ”, iEnd
If
3. End
/*Function prototypes*/
void quick_sort(int [], int, int, int);
int splitarray(int [], int, int);
Self-Instructional
Material 213
Other Sorting Techniques void main()
{
int ARR[MAX], i, size;
do
NOTES {
clrscr();
printf(“\nEnter the size of the array (max %d): “,
MAX);
scanf(“%d”, &size);
}while(size>MAX);
printf(“\nEnter the elements of the array:\n”);
for(i=0;i<size;i++)
scanf(“%d”, &ARR[i]);
quick_sort(ARR, size, 0, size-1);
printf(“\nThe sorted array is: “);
for(i=0;i<size;i++)
printf(“%d “, ARR[i]);
getch();
}
}
int splitarray(int ARR[], int lb, int ub)
{
Self-Instructional
214 Material
int pivot, beg, end, temp, flag=0; Other Sorting Techniques
beg=pivot=lb;
end=ub;
while(!flag)
{ NOTES
while ((ARR[pivot]<=ARR[end]) && (pivot!=end))
end—;
if (pivot==end)
flag=1;
else
{
temp=ARR[pivot];
ARR[pivot]=ARR[end];
ARR[end]=temp;
pivot=end;
}
if (!flag)
{
while ((ARR[pivot]>=ARR[beg]) && (pivot!=beg))
beg++;
if (pivot==beg)
flag=1;
else
{
temp=ARR[pivot];
ARR[pivot]=ARR[beg];
ARR[beg]=temp;
pivot=beg;
}
}
}
return pivot;
}
The output of the program is
Enter the size of the array (max 20): 5
PROCEDURE InOrder(BinaryTree:searchTree)
IF searchTree.Node IS NULL THEN
EXIT PROCEDURE
ELSE
InOrder(searchTree.LeftSubTree)
EMIT searchTree.Node
InOrder(searchTree.RightSubTree)
Self-Instructional
216 Material
PROCEDURE TreeSort(Collection:items) Other Sorting Techniques
BinaryTree:searchTree
InOrder(searchTree)
1. In selection sort, first, the smallest element in the list is searched and is
swapped with the first element in the list (that is, it is placed at the first
position).
2. Quick sort algorithm also follows the principle of divide-and-conquer.
3. Tree sort is a sorting algorithm that is based on Binary Search.
14.6 SUMMARY
• In selection sort, first, the smallest element in the list is searched and is
swapped with the first element in the list (that is, it is placed at the first
position). Then, the second smallest element is searched and swapped with
the second element in the list (that is, it is placed at the second position),
and so on.
• Like bubble sort algorithm, the selection sort also requires n-1 passes to
sort an array containing n elements.
• Quick sort algorithm also follows the principle of divide-and-conquer.
However, it does not simply divide the list into halves. Rather it first picks
up a partitioning element, called pivot that divides the list into two sub-lists.
• A tree sort is a sort algorithm that builds a binary search tree from the
elements to be sorted, and then traverses the tree so that the elements come
out in sorted order.
Self-Instructional
Material 217
Other Sorting Techniques
14.7 KEY WORDS
Short-Answer Questions
1. Differentiate between bubble sort and selection sort.
2. How does the quick sort algorithm sort data?
Long-Answer Questions
1. Describe the steps to sort the values stored in the array in ascending order
using selection sort.
2. Write a program showing sorting of an array using selection sort and quick
sort.
Self-Instructional
218 Material