BCAC103_Data Structure Using C++
BCAC103_Data Structure Using C++
Chavan
Maharashtra Data Structure
Open University using C++
Development Team
1.1 Introduction
In real life we always deal with different sets of values such as name, cost of item, roll number, Aadhar
number, pin code of city, and marks in examination. These sets of values represent facts and they are
called as Data. Data item refers to single set of value such as Aadhar number.
In this chapter we will discuss what we mean by data structure, basic terns associated with data
structure, data organization, and classification of data structures.
Collection of data needs to be organized in memory so that we can make an efficient access to it. Data
structure is a way to organize data in computers so that it can be accessed efficiently. Programmer need
to select appropriate data structure for storing of data elements in memory. It is considered as a first
step towards good programming.
Group Items
There are different ways to organize data and accordingly there are different types of data structures.
Data items that can be further divided into sub items are called as group items. For example, name can
be further divided into first name, middle name and last name.
Elementary Items
Data items that cannot be further subdivided are called as elementary data items. Ex: Roll number. Data
items that can be further subdivided are called as group items. For Ex: Name of student.
Data with properties (attributes) is called as entity that can be assigned numeric or non numeric vale.
For Ex: Attribute Age, value 23.
Entity Set
Entities with similar attributes are called as entity set. For Ex: Students of a college or employees of
university are entity set.
Every attribute of entity set has a range of values, the set of all possible values. For Ex: Range of age can
be 0-100
Data with given attributes is called as information, that is, processed data is called as information. For
Ex: Pass or Fail students.
Example of file:
Primary Key
A record may contain many fields but one of them can have a unique value and it is called as primary
key. For Ex: Roll number of a student can be primary key.
A file can have a fixed length records or variable length records. The minimum and maximum length of
record can be specified. For Ex, we can have 4 digits for roll number, 20 characters for name and 2 digits
for marks.
1 Student Name N
2 Roll Number Y
3 Address N
4 ID Number of Employee Y
5 Salary N
Fields, records and files are not sufficient to process all type of data and hence we require more complex
data structures. Complex data structures are arrays, linked lists, stacks, trees, queues and graphs. Good
programming begins with correct choice of Data Structure. It requires less execution time and memory
space. In the next sessions we will discuss about complex data structures.
Primitive data structures cannot be further divided and they are called as simple data types. For Ex:
Integer, Real, Character and Boolean.
3 Character A, B, f, r, N, 6
4 Boolean T, F
Non primitive data structures are classified into linear and non linear data structures. Fig 1.4 shows
different non primitive data structures.
Arrays
An array is a linear list of elements. It can have one or more dimensions. A subscript/index is used to
refer to elements of array. For Ex: A[5] refers to 5th element of array A. Fig 1.5 shows elements of array
with index.
Fig 1.5: Array Elements
Observe that index can start from 0. So, first element of array is A[0]. It is also called as lower bound.
Upper bound refers to last element in array.
Arrays are used to store multiple values in a single variable instead of declaring separate variables for
each value. They can be used to store a wide range of data types, including integers, floating-point
numbers, characters, and even complex data values.
Linked List
A linked list is a list in which each element has a link/pointer to next element. Linked lists are more
efficient than arrays. Linked list is a collection nodes where every node consist of Value and pointer.
Figure 1.6 shows linked list.
Linked lists use only as much memory as needed for the actual data. Arrays might have unused pre-
allocated space. They do not require contiguous blocks of memory like arrays.
Linked list is used in addition of long integers, representation of metrics and Polynomial representation.
They are used in implementing stack and queues and hash tables. Undo and Redo buttons in browsers
makes use of linked lists. Next and previous buttons in image viewers are also implemented by using
linked lists.
Stack
Stack is a linear list in which insertion and deletion takes place at one end only. It is also called as LIFO
(Last In First Out) system. Fig 1.7 shows stack.
The stack is like a cylinder with one end closed and other end open. We can perform push and pop
operations on stack.
A stack can be used for evaluating expressions. An expression that consists of operands and operators.
Stacks can be used for backtracking, i.e., to check parenthesis matching in an expression. It can also be
used to convert one form of expression to another form. It can be used for systematic Memory
Management like process scheduling in operating systems. Many Computer Science algorithms are
implemented by using stack memory.
Queue
Queue is a linear list in which insertion takes place at rear end and deletion takes place at front end. It is
FIFO (First In First Out) system. Fig 1.8 shows Queue data structure.
Fig 1.8: Queue
Queues are used in many applications, such as task scheduling, managing requests, handling interrupts,
website traffic, networking and media players.
Tree
Tree is a data structure that has a root and leaves. It represents hierarchical relationship between
elements. Fig 1.9 shows tree data structure.
A tree consists of nodes. All nodes are connected by edge. Topmost node is called as root and nodes
below it are called as Childs.
Trees are used in applications such a file systems for directory structure. It is used to organize
subdirectories and files. They are used in decision making in expert systems and game playing.
Graph
Graph is a pictorial representation of elements along with links. There may not be hierarchical
relationship. Fig 1.10 shows graph.
A graph consists of vertices and edges. Each vertex is named by a number. There can be two or more
edges from each vertex. They are used to represent relationships and connections between objects.
Graphs are used in many applications such as Social networks, Maps and navigation, Computer
networks, Biology, Computer vision, Natural language processing, Telecommunication and Circuit
design.
Questions
1. Answer the following questions.
(iv) What do you mean by linear and non linear data structure?
1. Data items that can be further divided into sub-items are called elementary data items.
Answer: False
2. The name of a student, consisting of first name, middle name, and last name, is an example of a
group item.
Answer: True
7. A primary key is a unique field within a record that can identify it uniquely.
Answer: True
9. Primitive data structures, such as integers and characters, cannot be further divided.
Answer: True
11. Arrays use indexes to refer to specific elements, starting with 1 as the lower bound.
Answer: False
12. Linked lists use pointers to connect elements, allowing efficient memory usage.
Answer: True
13. A stack is a linear data structure that uses the FIFO (First In First Out) system.
Answer: False
14. Queues are used for task scheduling and handling requests in systems.
Answer: True
15. Trees represent a hierarchical relationship and have a root and child nodes.
Answer: True
16. Graphs show relationships between objects and always have a hierarchical structure.
Answer: False
17. A file is a collection of records, and each record consists of multiple fields.
Answer: True
18. Linked lists are not used in applications like undo and redo operations in browsers.
Answer: False
19. Non-linear data structures are best suited for tasks requiring sequential data processing.
Answer: False
(i) Data structure is a way to __________ data in computers so that it can be accessed
efficiently.
Answer: organize
(ii) __________ items can be further divided into sub-items, whereas __________ items
cannot.
Answer: Group, elementary
(iii) A data item with properties or attributes is called an __________.
Answer: entity
(iv) Entities with similar attributes are referred to as an __________ __________.
Answer: entity set
(v) The set of all possible values for an attribute is called its __________ of __________.
Answer: range, values
(vi) Data that has been processed is called __________.
Answer: information
Summary
Collection of data needs to be organized in memory so that we can make an efficient access to it. Data
structure is a way to organize data in computers so that it can be accessed efficiently.
Various terms such as Group Items, Elementary Items are defined. Data can be structured in a
hierarchy of fields, records, and files. Primitive Data Structures are Integer, Real, Character, Boolean.
Non-Primitive Data Structures are further classified into linear and non-linear structures. Linear Data
Structures are Arrays, Linked Lists, Stacks (LIFO) and Queues (FIFO). Non-Linear Data Structures are trees
and graphs. Understanding data structures is crucial for efficient programming and problem-solving.
Choosing the right data structure optimizes memory usage and execution time.
1. "Data Structures and Algorithms in C++" – Michael T. Goodrich, Roberto Tamassia, David
M. Mount
2. "Data Structures Using C++" – D. S. Malik
3. "Data Structures and Algorithm Analysis in C++" – Mark Allen Weiss
Udemy - Mastering Data Structures & Algorithms using C++ (Abdul Bari) (Paid Course)
[Link]
Coursera - Data Structures and Algorithms Specialization (UC San Diego & HSE) (Free/Paid
Certificate)
[Link]
Open Data Structures (in C++) – By Pat Morin (Free PDF Book)
[Link]
MIT OpenCourseWare - Introduction to Algorithms (Lecture Notes & Videos)
[Link]
to-algorithms-fall-2011/
2. Learn fundamental operations such as insertion, deletion, searching, updating, and traversal.
2.1 Introduction
Data stored in data structures need to be manipulated. To manipulate the data we need to use certain
method. Data structure operations are the methods used to manipulate the data in a data structure. The
most common data structure operations are: Insertion, Deletion, Traversing, Searching, Merging and
Sorting.
Observe that after insertion operation number of elements and their indices are changed. In linked lists
the pointer values also gets changed.
Observe that after deletion operation number of elements and their indices are changed. In graph the
edges also gets deleted. In stacks, top of stack may get changed.
In the given array we have searched element 78. The element is found at index 4. We need to search
from first to last element. If search element is not found then No Match Found message will be
generated.
Summary
Data stored in data structures must be manipulated using specific operations. These data structure
operations include methods such as insertion, deletion, traversing, searching, merging, and sorting,
which are essential for data management. These fundamental data structure operations help manage,
manipulate, and organize data effectively, ensuring efficient storage, retrieval, and processing in various
applications.
Questions
1. Answer the following questions
(i) List the different operations that can be performed on data structures.
(i) Insertion operation in a data structure always occurs at the end of the structure.
Answer: False
(ii) After an insertion operation, the indices of elements in an array may change.
Answer: True
(iii) Deletion operations can occur at any position within a data structure.
Answer: True
(iv) Traversing a data structure modifies the data elements.
Answer: False
(v) During traversing, each element of the data structure is accessed without making any
changes.
Answer: True
(vi) Searching in an array requires checking every element sequentially from the start to the
end.
Answer: True
(vii) If a searched element is not found, a "Match Found" message is displayed.
Answer: False
(viii) Merging involves combining two or more similar data structures into one.
Answer: True
(ix) After merging two arrays, elements of both arrays retain their original order within the
new array.
Answer: True
(x) Sorting arranges elements of a data structure in either ascending or descending order.
Answer: True
(xi) Sorting is used to merge two data structures into one.
Answer: False
(xii) Insertion in linked lists changes pointer values in addition to adding a new element.
Answer: True
(xiii) Deletion in a stack does not affect the top of the stack.
Answer: False
(xiv) Traversing a data structure is required to modify data elements.
Answer: False
(xv) A searching operation can generate a "No Match Found" message if the element is
absent.
Answer: True
(xvi) Merging two arrays results in a single array containing elements from both arrays.
Answer: True
(xvii) Sorting is limited to numeric data and cannot be performed on alphabetic data.
Answer: False
(xviii) Insertion and deletion operations do not alter the number of elements in a data
structure.
Answer: False
(xix) Merging and sorting are independent operations performed on data structures.
Answer: True
(xx) Sorting always places the smallest element at the beginning, regardless of order
preference.
Answer: False
4. "Data Structures and Algorithms in C++" – Michael T. Goodrich, Roberto Tamassia, David
M. Mount
5. "Data Structures Using C++" – D. S. Malik
6. "Data Structures and Algorithm Analysis in C++" – Mark Allen Weiss
Udemy - Mastering Data Structures & Algorithms using C++ (Abdul Bari) (Paid Course)
[Link]
Coursera - Data Structures and Algorithms Specialization (UC San Diego & HSE) (Free/Paid
Certificate)
[Link]
Open Data Structures (in C++) – By Pat Morin (Free PDF Book)
[Link]
2. Explain the Top-Down approach and how it emphasizes breaking a problem into smaller sub
problems.
3. Illustrate the Bottom-Up approach, where smaller sub problems are solved first and combined
to form a solution.
1.1What is an Algorithm?
Let us consider an example to post a letter. The sequence of steps for this would be:
1.2Need of Algorithm
Following points illustrate us the need of algorithm.
2. It is easy to code the program from algorithm in high level programming language.
3. If the algorithm is correct, computer will run the program correctly, every time.
4. The purpose of using an algorithm is to increase the reliability, accuracy and efficiency of obtaining
solutions.
Algorithms can be iterative. That is, certain steps of algorithm are repeatedly executed. Algorithms
are recursive as well. That is, we can call certain action within action itself.
Bottom Up approach
In Top Down approach the problem is divided into smaller sub problems. This approach is also called as
Divide and Conquer. In this approach the main task is divided into smaller subtasks as shown in fig. 3.1.
Steps:
Following are advantages of top down approach. Fig 3.2 shows advantages of top down approach.
1. Easier to Understand: When complex task is sub divided into smaller sub tasks then steps of
algorithm becomes easy to understand.
2. Better Planning: With simple steps we can achieve our goal with considerations of obstacles and
resources.
3. Early Identification of Issues: If there are any chances of occurrence of problem in obtaining a
solution then that is identified at early stage.
4. Facilitates Testing: Test data can be run to check correctness at each level .
In Bottom Up approach we start from simplest sub problem and build the solution to larger problem.
This approach is also called as human approach because most of real life problems are solved by
humans by attempting simple parts first.
Steps:
In Computer Science multiple algorithms are available for same problem. Algorithms are compared by
using complexity. Every algorithm requires certain resources for it’s execution.
Resources can be in the form of memory space and time. Measure of resources for any algorithm is
called as complexity of algorithm. An algorithm with less complexity is always better than that of high
complexity.
1. Execution times: Not a good measure as execution times are specific to a particular computer
2. Number of statements executed: Not a good measure, since the number of statements varies
with the programming language as well as the style of the individual programmer
Ideal solution is:
Let us assume that we express the running time of a given algorithm as a function of the input size n
(i.e., f(n)) and compare these different functions corresponding to running times. This kind of
comparison is independent of machine time, and programming style.
The rate at which the running time increases as a function of input is called rate of growth. Let us
assume that you go to a shop to buy a car and a bicycle. If your friend sees you there and asks what you
are buying, then in general you say buying a car.
This is because the cost of the car is high compared to the cost of the bicycle.
In above function n4, 2n2, 100n and 500 are the individual costs of some function and approximate to n4
since n4 is the highest rate of growth.
Some commonly used rate of growth is given in following table 3.1. Here n stands for number of inputs.
1 Constant
log(n) Logarithmic
n Linear
n2 Quadratic
n3 Cubic
2n Exponential
Observe that in above table rate of growth is lowest for constant 1 and highest for exponential 2n.
1 Constant
log(n) Logarithmic
n Linear
n2 Quadratic
n3 Cubic
2n Exponential
n! Factorial
Complexity Meaning
13. 1 m. Logarithmic
Summary
An algorithm is a step-by-step procedure designed to solve a specific problem, much like the process of
posting a letter, where steps must be followed in a logical sequence. Algorithms are essential in
programming because they simplify coding, ensure accuracy, and improve efficiency. They have key
features such as input, output, finiteness, definiteness, effectiveness, and can be iterative or recursive.
Algorithms can be designed using two main approaches: Top-Down, which divides a problem into
smaller subproblems and Bottom-Up, which starts from solving simpler components to build larger
solutions. To evaluate algorithms, their complexity is measured in terms of time (execution steps) and
space (memory usage). Complexity is expressed using growth rates like constant, logarithmic, linear,
quadratic, cubic, exponential, and factorial. Time complexity reflects the execution time based on input
size, while space complexity refers to the memory required. Efficient algorithms aim for low time and
space complexity, ensuring reliable, accurate, and optimal problem-solving.
Questions
1. Answer the following questions
Answer: True
Answer: False
Answer: False
Answer: False
5. Bottom-up approaches solve smaller sub-problems first and combine them to solve the
larger problem.
Answer: True
6. Complexity of an algorithm measures the resources it requires, such as time and memory.
Answer: True
Answer: False
9. Time complexity is the total time required for the complete execution of an algorithm.
Answer: True
Answer: True
Answer: True
Answer: True
Answer: Algorithm
Answer: First
(iii). The ________ approach divides a problem into smaller sub-problems and solves each one
individually.
Answer: Top-down
(iv) The ________ approach starts from the simplest sub-problem and builds the solution to the
larger problem.
Answer: Bottom-up
(v) One of the key features of an algorithm is that it must have zero or more ________.
Answer: Inputs
Answer: Steps
(viii) ________ refers to the rate at which the running time increases as a function of input size.
(x) ________ is a measure of the time required for the complete execution of an algorithm.
(xii) The time complexity for an algorithm is considered ________ when the time required does
not depend on the input size.
Answer: Constant
Answer: 1 (Constant)
Answer: Big O
A Text Book on Data Structure Using C++
3. Analyze Time Complexity by using Big-O notation to measure the efficiency of an algorithm.
5. Compare different algorithms based on their time and space complexities to determine optimal
solutions.
In this chapter we will understand the different types of notations that are used for describing
complexity of algorithms. First of all we will understand different types of analysis.
An algorithm can be represented in the form of an expression. That means we represent the algorithm
with multiple expressions: One for the case where it takes less time (Best Case) and another for the case
where it takes more time (Worst Case).
Worst case defines the input for which the algorithm takes a long time. Best case defines the input for
which the algorithm takes the least time. Average case provides a prediction about the running time of
the algorithm.
Big O Notation- Upper bound time complexity or worst case time complexity is given by this notation.
Omega (Ω) Notation- Here the execution time serves as a lower bound on the algorithm’s time
complexity.
Theta (Ѳ) Notation- It represents the upper and the lower bound of the running time of an algorithm. It
is used for analyzing the average-case complexity of an algorithm.
This notation gives the tight upper bound of the given function. Generally, it is represented as f(n) =
O(g(n))That means, at larger values of n, the upper bound of f(n) is g(n).
O–notation defined as O(g(n)) = {f(n): there exist positive constants c and n0 such that 0 ≤ f(n) ≤ cg(n) for
all n > n0}. g(n) is an asymptotic tight upper bound for f(n). Our objective is to give the smallest rate of
growth g(n) which is greater than or equal to the given algorithms’ rate of growth f(n).
For example, if f(n) = n4 + 100n 2 + 10n + 50 is the given algorithm, Then n4 is g(n). That means g(n) gives
the maximum rate of growth for f(n) at larger values of n.
Generally we discard lower values of n. That means the rate of growth at lower values of n is not
important. In the figure, n0 is the point from which we need to consider the rate of growth for a given
algorithm. Below n0 , the rate of growth could be different. n0 is called threshold for the given function.
The maximum time required by an algorithm or the worst-case time complexity. It returns the highest
possible output value (big-O) for a given input. Big-O (Worst Case) is defined as the condition that allows
an algorithm to complete statement execution in the longest amount of time possible.
Example:
Given the following algorithms, identify the best, worst, and average cases for each:
Observe that exponential functions grow significantly faster than polynomial functions.
It specifies the lower bound of a function. The minimum time required by an algorithm or the best-case
time complexity. It returns the lowest possible output value (Omega) for a given input.
Omega(Best Case) It is defined as the condition that allows an algorithm to complete statement
execution in the lowest amount of time possible.
Solution: ∃ c, n0 Such that: 0 ≤ cn2≤ 5n2 ⇒ cn2 ≤ 5n2 ⇒ c = 5 and n0 = 1 ∴ 5n2 = Ω(n2 ) with c = 5 and n0 = 1.
As an example, let us assume that f(n) = 10n + n is the expression. Then, its tight upper bound g(n) is
O(n). The rate of growth in the best case is g(n) = O(n)
For a given function (algorithm), if the rates of growth (bounds) for O and Ω are not the same, then the
rate of growth for the Θ case may not be the same. In this case, we need to consider all possible time
complexities and take the average of those.
It is defined as Θ(g(n)) = {f(n): there exist positive constants c1 ,c2 and n0 such that 0 ≤ c1g(n) ≤ f(n) ≤
c2g(n) for all n ≥ n0}. g(n) is an asymptotic tight bound for f(n). Θ(g(n)) is the set of functions with the
same order of growth as g(n).
Fig 4.3: Function f(n) and g(n)
Example:
Summary
The analysis of algorithms helps determine how an algorithm performs with different inputs, focusing on
best case (least time), worst case (longest time), and average case (expected time). To represent these,
three asymptotic notations are used: Big O for the upper bound (worst-case complexity), Omega (Ω) for
the lower bound (best-case complexity), and Theta (Θ) for the average-case complexity, which lies
between the two bounds. Big O is most widely used as it shows the maximum growth rate of an
algorithm, Omega highlights the minimum required time, and Theta confirms if both bounds coincide,
giving a tight bound for the algorithm’s growth. These notations allow comparison of algorithms
independent of machine or programming style by focusing on the rate of growth of functions, making
them essential for understanding efficiency and scalability.
Questions
1. Answer the following questions.
(ii) Write three asymptotic notations used for describing complexity of algorithms.
Answer: b) It represents both the upper and lower bounds of the running time
4. The "Big O" notation is most commonly used to represent which of the following?
6. In the Big O notation, what is the rate of growth for the expression f(n) = n^4 + 100n^2 + 10n + 50 at
larger values of n?
Options: a) n^4
b) n^2
c) 100n^2
d) 50
Answer: a) n^4
Options: a) It indicates when we start ignoring lower growth rates in the algorithm.
b) It represents the number of inputs required for an algorithm to start performing efficiently.
c) It provides the worst-case input size for the algorithm.
d) It is used to calculate the exact running time of an algorithm.
Answer: a) It indicates when we start ignoring lower growth rates in the algorithm.
8. In the expression f(n) = 5n^2, the lower bound given by Omega (Ω) notation is:
Options: a) Ω(n^3)
b) Ω(n^2)
c) Ω(n)
d) Ω(1)
Answer: b) Ω(n^2)
10. Which of the following statements is true about Theta (Θ) notation?
Options: a) It is used only when the upper and lower bounds of an algorithm are the same.
b) It represents the best-case time complexity of an algorithm.
c) It represents only the average-case time complexity.
d) It is used to describe the average running time between the upper and lower bounds.
Answer: a) It is used only when the upper and lower bounds of an algorithm are the same.
Answer: False
2. Omega (Ω) notation is used to represent the worst-case time complexity of an algorithm.
Answer: False
3. Theta (Θ) notation represents both the upper and lower bounds of an algorithm’s running time.
Answer: True
4. Big O notation is used to analyze the best-case scenario for an algorithm’s time complexity.
Answer: False
5. In Big O notation, the rate of growth of an algorithm is always considered for larger values of n.
Answer: True
6. Omega (Ω) notation provides a lower bound for the running time of an algorithm.
Answer: True
7. Theta (Θ) notation is only used when the upper and lower bounds of a function are the same.
Answer: True
8. The threshold value (n0) in Big O notation determines when we start ignoring lower growth rates of an
algorithm.
Answer: True
9. In the function f(n) = n^4 + 100n^2 + 10n + 50, the rate of growth is determined by n^4 at larger
values of n.
Answer: True
10. The value of n0 in Omega (Ω) notation indicates the point from which the lower bound of an
algorithm becomes significant.
Answer: True
Answer: upper
2. Omega (Ω) notation represents the __________ bound of an algorithm's running time.
Answer: lower
3. Theta (Θ) notation is used when the __________ and __________ bounds of an algorithm’s
running time are the same.
Answer: Big O
Answer: g(n)
6. In Omega (Ω) notation, the minimum time required by an algorithm is given by the
__________ case time complexity.
Answer: best
7. The value of n0 in asymptotic notations is called the __________ for a given algorithm.
Answer: threshold
8. If f(n) = 100n² + 10n + 50, the asymptotic tight lower bound is represented as __________
(n²).
Answer: Ω
9. In the function f(n) = n⁴ + 100n² + 10n + 50, the highest rate of growth is determined by
__________.
Answer: n⁴
10. Theta (Θ) notation is used to represent the __________ of the running time of an algorithm.
Arranging elements in a given data set in ascending (Low to High) or descending (High to Low) form is
called as sorting. For example for a given array, we can arrange elements of array in increasing order as
shown below.
Sorting can significantly reduce the complexity of a problem, and is often used for database algorithms
and searches.
2. Bubble Sort: Repeatedly performs comparison of adjacent elements and swap them. This is
simplest and in efficient method.
4. Merge Sort: Most efficient algorithm works on principle of divide and conquer.
5. Quick Sort: This method sorts elements faster than other methods.
6. Radix Sort: This method is a linear sorting algorithm that sorts elements by processing them digit
by digit. It is an efficient sorting algorithm.
In this chapter we will discuss selection and bubble sort methods. Rest of the methods will be
discussed in later chapters.
Initially, sorted sub-array is empty and unsorted array is the complete given array.
We perform the steps given below until the unsorted sub-array becomes empty:
Pick the minimum element from the unsorted sub-array.
Now the leftmost element of unsorted sub-array becomes a part (rightmost) of sorted sub-array
and will not be a part of unsorted sub-array.
Time Complexity
3. Average Case:
The number of comparisons is always the same as it depends only on the size of the array.
Time Complexity: O(n2)
Space Complexity
Selection Sort is an in-place sorting algorithm, meaning it doesn't require extra space for sorting other
than a constant amount for variables.
Space Complexity: O(1)
#include <bits/stdc++.h>
//Swap function
*xp = *yp;
*yp = temp; }
{ int i, j, min_idx;
// unsorted array
min_idx = i;
min_idx = j;
swap(&arr[min_idx], &arr[i]);
}
{ int i;
int main()
int n = sizeof(arr)/sizeof(arr[0]);
selectionSort(arr, n);
printArray(arr, n);
return 0;
Output:
Sorted array: 11 12 22 25 64
The statement #include <bits/stdc++.h> using namespace std includes all C++ standard libraries and
allows the use of names from the standard library for variables and objects. The function swap() is used
for interchanging values of variables. The function selectionSort() implements selection sort algorithm.
The function printArray() is used for displaying content of an array. The function main() calls sorting
function and display sorted array.
Suppose we have an array of length n. To sort this array we do the swapping step n - 1 passes. In simple
terms, first, the largest element goes at its extreme right place then, second largest to the last by one
place, and so on. In the ith pass, the ith largest element goes at its right place in the array by swapping.
In real life, bubble sort can be visualized when people in a queue wanting to be standing in a height wise
sorted manner.
Time Complexity
Space Complexity
Bubble Sort is an in-place sorting algorithm, meaning it does not require extra space apart from a few
variables for swapping.
Space Complexity: O(1)
#include <bits/stdc++.h>
void bubbleSort(vector<int>& v) {
int n = [Link]();
int main() {
bubbleSort(v);
for (auto i : v)
return 0;
Output:
1 2 4 5 8
The statement #include <bits/stdc++.h> using namespace std includes all C++ standard libraries and
allows the use of names from the standard library for variables and objects. The using namespace std;
allows the use of standard library functions without the std:: prefix. The function bubbleSort()
implements bubble sort algorithm. This function takes a vector v (list of integers) as input. The n =
[Link](); stores the size of the vector. The function main() calls sorting function and display sorted array.
3. More efficient sorting algorithms like Quick Sort or Merge Sort are preferred for large data sets.
Summary
Questions
(vii) Write and execute program to implement selection sort using C++.
(viii) Write and execute program to implement bubble sort using C++.
(ii) Which sorting algorithm is based on the principle of divide and conquer?
a) Bubble Sort
b) Selection Sort
c) Merge Sort
d) Insertion Sort
(iii) Which of the following sorting algorithms is the simplest but least efficient?
a) Quick Sort
b) Bubble Sort
c) Merge Sort
d) Radix Sort
Answer: b) Empty
(v) What is the time complexity of Selection Sort in the best case?
a) O(n)
b) O(n2)
c) O(log n)
d) O(nlog n)
Answer: b) O(n2)
(vi) Bubble Sort detects an already sorted array in:
a) O(n2) time
b) O(n) time
c) O(log n) time
d) O(1) time
Answer: b) 11 12 22 25 64
(x) In Bubble Sort, the number of passes required to sort an array of size n is:
a) n
b) n−1
c) n+1
d) n/2
Answer: b) n−1
1. Understand the Concept how insertion sort works by comparing, shifting, and inserting
elements into their appropriate positions.
2. Analyze the time complexity in different cases (Best: O(n), Worst: O(n²), Average: O(n²)) and
space complexity (O(1)).
3. Identify the simplicity, efficiency for small datasets, and stability of insertion sort.
4. Understand why insertion sort is inefficient for large, unsorted datasets due to its quadratic time
complexity.
Wherein for an unsorted array, it takes for an element to compare with all the other elements which
mean every n element compared with all other n elements. Thus, making it for n x n, i.e.,n 2 comparisons.
Time Complexity
When the array is already sorted, the inner loop only runs once for each element. The algorithm
performs n−1 comparisons and no shifts are needed. Time Complexity = O(n).
When the array is sorted in reverse order, each element must be compared with all previous elements
and shifted to the beginning. For the ithi^{th}ith element, iii comparisons and iii shifts are performed,
resulting in ∑ I = (n(n−1)/2. Time Complexity = O(n2).
On average, for each element, it is assumed to be compared with half of the previously sorted elements.
This still results in a quadratic complexity. Time Complexity = O(n2).
Space Complexity
1. Simple to implement.
#include <bits/stdc++.h>
int i, key, j;
key = arr[i];
j = i - 1;
// that are greater than key, to one position ahead of their current position
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
int i;
int main()
insertionSort(arr, N);
printArray(arr, N);
return 0;
Output:
1 2 4 5 8
Initially all header files are included in program by using #include statement. The using namespace std;
allows direct use of standard functions like cout without prefixing std::. The function insertionSort() is
used for sorting of elements. arr[] is the array to be sorted. n is the number of elements in the array. key
is the current element being inserted into the sorted portion. i and j are loop variables. The function
printArray() is used to print content of array.
Steps:
2. Then divide the whole array into equal halves using this midpoint.
4. Further divide these two sub arrays into further halves, until the atomic (single element) sub
array is reached, and further division is not possible.
Even in the best case (when the array is already sorted), Merge Sort still divides the array and performs
the merging process. The merging step always requires comparing and combining elements. Time
Complexity = O(nlog n).
The algorithm divides the array into two halves recursively until each subarray contains a single element
(log n levels of recursion). Merging two sorted sub arrays requires O(n) time for each level. Time
Complexity = O(nlog n).
The recursive division and merging process remain the same regardless of the initial ordering of the
elements. Time Complexity = O(nlogn).
Merge Sort requires additional memory for temporary arrays during the merge operation. The space
complexity depends on the implementation. Top-down implementation requires O(n) auxiliary space for
temporary arrays. Bottom-up implementation also requires O(n) space.
2. Stable sorting algorithm, that is, preserves the relative order of equal elements.
2. Slower than in-place algorithms such as Quick Sort for smaller arrays due to the overhead of
recursive calls and merging.
6.11 C++ Program for Merge Sort
// C++ program for the merge sort
#include <iostream>
#include <vector>
int i, j, k;
i = 0;
j = 0;
k = left;
vec[k] = leftVec[i];
i++;
} else {
vec[k] = rightVec[j];
j++;
k++;
vec[k] = leftVec[i];
i++;
k++;
vec[k] = rightVec[j];
j++;
k++;
int main() {
int n = [Link]();
mergeSort(vec, 0, n - 1);
return 0;
Output:
5 6 7 11 12 13
Initially all header files are included in program by using #include statement. The <iostream> is used for
input-output operations. <vector> is used to store and manipulate dynamic arrays. The using namespace
std; allows direct use of standard library functions without prefixing std::.The function merge() is used
for merging of two arrays. The function mergeSort() is used for sorting of array.
Split [12, 11, 13, 5, 6, 7] into [12, 11, 13] and [5, 6, 7]
Merging Phase:
Merge [11, 12, 13] and [5, 6, 7] → [5, 6, 7, 11, 12, 13]
Summary
Insertion Sort is a simple sorting algorithm that works by comparing an element with its adjacent values
and inserting it in the correct position by shifting other elements as needed. It is efficient for small or
nearly sorted datasets but performs poorly for large, random datasets due to its O(n²) worst-case time
complexity. The algorithm operates in-place with a space complexity of O(1), making it memory
efficient. Its main advantages include ease of implementation, stability (preserving the order of equal
elements), and effectiveness for small inputs. However, its inefficiency for large datasets limits its
practical use compared to more advanced algorithms like Merge Sort.
Questions
1. Answer the following questions.
1. What is the primary operation performed during the first step of the insertion sort algorithm?
a) Merging elements
b) Comparing the element in question with its adjacent element
c) Dividing the array into two halves
d) Swapping all elements in the array
2. How does insertion sort handle placing an element at its correct position?
a) O(1)
b) O(n)
c) O(n2)
d) O(logn)
Answer: b) O(n)
4. In the worst case, how many comparisons does insertion sort perform for an array with nnn
elements?
a) n
b) n−1
c) n2
d) (n(n−1))/2
Answer: d) (n(n−1))/2
a) O(1)
b) O(n)
c) O(log n)
d) O(n2)
Answer: a) O(1)
9. During the insertion sort process, what happens in the worst-case scenario?
Answer: b) Each element is compared with all previous elements and shifted to the beginning
10. What is the key feature that makes insertion sort an in-place algorithm?
a) Dynamic programming
b) Divide and conquer
c) Greedy algorithm
d) Backtracking
Answer: b) It divides the dataset into halves, sorts them, and merges the sorted halves
13. What is the key step in merge sort that combines two halves of the dataset?
a) Sorting
b) Splitting
c) Merging
d) Partitioning
Answer: c) Merging
Answer: b) It is split into two equal halves until single elements remain
15. What is the time complexity of merge sort in the best case?
a) O(1)
b) O(n)
c) O(n log n)
d) O(n2)
a) O(1)
b) O(logn)
c) O(n)
d) O(n2)
Answer: c) O(n)
1. In insertion sort, each element is compared with its adjacent element to determine its correct
position.
Answer: True
2. During the insertion process, elements are shifted one position to the left to create space for the
element being inserted.
Answer: True
Answer: True
6. Insertion sort is an in-place sorting algorithm, meaning it does not require additional memory for
temporary arrays.
Answer: True
7. Insertion sort is an unstable algorithm as it changes the relative order of equal elements.
Answer: True
10. Insertion sort is faster than other algorithms for large and random datasets due to its simplicity.
Answer: False (Insertion sort is inefficient for large or random datasets due to its O(n2) time complexity
in the worst case.)
11. Merge Sort is a comparison-based sorting algorithm that follows the divide and conquer paradigm.
Answer: True
12. The merge process in Merge Sort assumes that the two arrays being merged are already sorted.
Answer: True
13. In Merge Sort, the array is divided into halves until each sub-array contains at least three elements.
Answer: False (Each sub array is divided until it contains a single element.)
14. Merge Sort guarantees O(n log n) time complexity in the best, worst, and average cases.
Answer: True
15. Merge Sort is an in-place sorting algorithm as it does not require extra memory.
Answer: False (Merge Sort requires additional memory for temporary arrays, with space complexity
O(n).)
16. The top-down implementation of Merge Sort requires O(1) auxiliary space.
17. Merge Sort is a stable sorting algorithm that preserves the relative order of equal elements.
Answer: True
18. The merging process in Merge Sort involves comparing elements from both sub-arrays and
combining them into a new sorted array.
Answer: True
19. Merge Sort is more efficient than in-place algorithms like Quick Sort for smaller datasets.
Answer: False (Merge Sort is slower for smaller datasets due to recursive overhead.)
20. Merge Sort is highly efficient for sorting large datasets due to its O(n log n) time complexity.
Answer: True
2. The merge process in Merge Sort assumes that the two arrays being merged are already ______.
Answer: sorted
3. In Merge Sort, the array is divided into halves until each sub-array contains a ______ element.
Answer: single
4. Merge Sort guarantees O(________) time complexity in the best, worst, and average cases.
Answer: nlogn
5. Merge Sort requires additional memory for ______ arrays during the merge operation.
Answer: temporary
7. Merge Sort is a ______ sorting algorithm, meaning it preserves the relative order of equal
elements.
Answer: stable
8. The merging process in Merge Sort involves ______ elements from both subarrays and
combining them into a new sorted array.
Answer: comparing
9. Merge Sort is ______ than in-place algorithms like Quick Sort for smaller datasets.
Answer: slower
10. Merge Sort is highly efficient for sorting large datasets due to its O(________) time complexity.
Answer: nlogn
11. In insertion sort, the first step involves the ______ of the element in question with its adjacent
element.
Answer: comparison
12. If at every comparison, the element in question can be inserted at a particular position, then
space is created for it by ______ the other elements one position to the right.
Answer: shifting
13. The above procedure is repeated until all the elements in the array are at their ______ position.
Answer: appropriate
14. The best-case time complexity of insertion sort is a ______ function of n.
Answer: linear
15. For an unsorted array, it takes n×n, i.e., n2 ______ in the worst case.
Answer: comparisons
16. Insertion sort is an ______ sorting algorithm, meaning it does not require additional memory for
temporary arrays.
Answer: in-place
17. In the best case O(n), the algorithm performs n−1 ______ and no shifts are needed.
Answer: comparisons
18. In the worst case O(n2), when the array is sorted in reverse order, each element must be ______
to the beginning.
Answer: shifted
19. The time complexity in the average case for insertion sort is O(______).
Answer: n^2
20. Insertion sort is ______ for small or nearly sorted datasets.
Answer: efficient
21. Insertion sort is ______, meaning it does not change the relative order of equal elements.
Answer: stable
22. Insertion sort is inefficient for ______ datasets due to its O(n2) time complexity in the worst
case.
Answer: large
A Text Book on Data Structure Using C++
7. Identify Strengths and Limitations of radix sort, shell sort and quick sort
Rather than comparing elements directly, Radix Sort distributes the elements into buckets based on
each digit’s value. By repeatedly sorting the elements by their significant digits, from the least significant
to the most significant, Radix Sort achieves the final sorted order. Fig 7.1 shows working of Radix sort.
Fig 7.1: Radix Sort
Step 1: Find the largest element in the array, which is 802. It has three digits, so we will iterate three
times, once for each significant place.
Step 2: Sort the elements based on the unit place digits (X=0). We use a stable sorting technique, such as
counting sort, to sort the digits at each significant place.
It’s important to understand that the default implementation of counting sort is unstable i.e. same keys
can be in a different order than the input array. To solve this problem, we can iterate the input array in
reverse order to build the output array. This strategy helps us to keep the same keys in the same order
as they appear in the input array.
b: The base used for grouping (e.g., base 10 for decimal digits, base 2 for binary digits).
1. Digit Extraction: For each digit or group of digits, the algorithm distributes the numbers into
buckets.
2. Stable Sorting: Each iteration requires a stable sorting algorithm like Counting Sort, which
operates in O(n).
Where:
d: Number of passes or digits (related to k, the maximum number of digits in the largest
number, and the base b).
Special Cases:
If b (the base) is chosen optimally, such as close to n, the complexity becomes approximately
O(n).
The space complexity is O(n+b), where n is for storing the input and b is the number of buckets.
Radix Sort is faster than comparison-based sorts (like Merge Sort or Quick Sort) when the number of
digits d is small relative to n. It is most efficient for fixed-length integers or strings. Radix Sort is not an
in-place algorithm, as it requires additional memory.
7.2 Shell Sort
It is mainly a variation of insertion sort. In insertion sort, we move elements only one position ahead.
When an element has to be moved far ahead, many movements are involved.
The idea of Shell Sort is to allow the exchange of far items. In Shell sort, we make the array h-sorted
for a large value of h. We keep reducing the value of h until it becomes 1. An array is said to be h-
sorted if all sub lists of every h’th element are sorted. Fig 7.2 shows working of Shell sort.
The time complexity of Shell Sort is influenced by the number of elements n and the gap sequence used.
Worst-Case Time Complexity: The worst-case time complexity depends heavily on the gap sequence: For
Shell's original sequence (n/2,n/4,…,1n/2, n/4, \dots, 1n/2,n/4,…,1): O(n2).
Average-Case Time Complexity: The average-case performance also depends on the gap
sequence but is generally better than O(n2).
The best case occurs when the array is already sorted or nearly sorted: O(n log n) for efficient
gap sequences.
[Link] Space Complexity
Shell Sort is an in-place sorting algorithm, so it requires no additional memory apart from the input
array. Space Complexity: O(1).
Shell Sort is generally not stable because elements can be moved far apart during gap sorting, disrupting
their relative order.
1. Choose a Pivot: Select an element from the array as the pivot. The choice of pivot can vary (e.g.,
first element, last element, random element, or median).
2. Partition the Array: Rearrange the array around the pivot. After partitioning, all elements
smaller than the pivot will be on its left, and all elements greater than the pivot will be on its
right. The pivot is then in its correct position, and we obtain the index of the pivot.
3. Recursively Call: Recursively apply the same process to the two partitioned sub-arrays (left and
right of the pivot).
Base Case: The recursion stops when there is only one element left in the sub-array, as a single element
is already sorted.
Best Case
Best Case Occurs when the pivot divides the array into two nearly equal parts at every step. Each
partitioning step takes O(n), and the depth of recursion is O(logn) because the array size halves with
each step. Time Complexity (Best Case):O(nlogn)
Worst Case
Worst case Occurs when the pivot is the smallest or largest element, resulting in highly unbalanced
partitions (e.g., one side has n−1 elements, and the other has 0). In this case, the recursion depth is O(n),
and each step still takes O(n).
Average Case
Assuming the pivot divides the array into reasonably balanced parts, the average number of
comparisons is proportional to O(n log n). Time Complexity (Average Case): O(n logn).
Summary
Radix Sort is a linear sorting algorithm that processes elements digit by digit, distributing them
into buckets based on each digit’s value. It efficiently sorts integers and fixed-size keys without
direct comparisons. The algorithm involves multiple passes, sorting elements based on their
least to most significant digits using a stable sorting method like Counting Sort. Its time
complexity depends on the number of digits and base used, typically O(d * (n + b)), making it
efficient when d (number of digits) is small. Radix Sort requires additional memory for bucket
storage, leading to a space complexity of O(n + b). Compared to comparison-based sorting
algorithms like Merge Sort and Quick Sort, it performs better for fixed-length numbers but is
not in-place. While it ensures stable sorting and linear time complexity under optimal
conditions, it may not be suitable for small datasets or large numbers with high digit counts due
to its extra space requirements.
Questions
Answer:
(ii) Distributing elements into buckets based on digit values.
Answer:
(ii) It is efficient for sorting integers or fixed-size strings.
(i) O(n2)
(iv) O(n)
Answer:
(iii) O(d⋅(n+b))
4. What does the variable d represent in Radix Sort's time complexity formula O(d⋅(n+b))?
Answer:
(ii) The number of digits in the largest number.
1. O(1)
2. O(n)
3. O(n+b)
4. O(log n)
Answer:
(iii) O(n+b)
Answer:
(ii) It requires additional memory for buckets and auxiliary structures.
Answer:
(iii). Insertion Sort
(iii) To divide the array into two equal halves and sort them.
Answer:
(ii). To allow the exchange of far items in the array.
Answer:
(ii) All sub-lists of every h th element are sorted.
10. Which step is repeated until the array is sorted in Shell Sort?
Answer:
(iii). Reducing the value of the gap size h.
11. The time complexity of Shell Sort in the worst case depends on:
Answer:
(iii). The gap sequence used.
12. What is the time complexity of Shell Sort for Shell's original gap sequence in the worst case?
1. O(n)
2. O(n log n)
3. O(n2)
4. O(log n)
Answer:
(iii) O(n2)
(i) O(1)
(ii) O(n)
(iii) O(logn)
(iv) O(n2)
Answer:
(i). O(1)
(i) Greedy
(iv) Backtracking
Answer:
(ii). Divide and Conquer
(ii) Divides the array into two parts, with smaller elements on the left and larger elements on the
right.
Answer:
(ii). Divides the array into two parts, with smaller elements on the left and larger elements on the
right.
16. Which of the following can be chosen as the pivot in Quick Sort?
Answer:
(iv). All of the above.
(i) The array is divided into two parts, with the pivot placed in its correct sorted position.
Answer:
(i). The array is divided into two parts, with the pivot placed in its correct sorted position.
18. The base case for the recursive calls in Quick Sort is:
Answer:
(iii). When the sub-array contains only one element.
19. What is the time complexity of Quick Sort in the best case?
(i) O(n)
(ii) O(n2)
(iii) O(nlog n)
(iv) O(log n)
Answer:
(iii). O(n log n)
1. Radix Sort is a linear sorting algorithm that processes elements digit by digit.
Ans: True
2. Radix Sort works by directly comparing elements to determine their order.
Ans: False
3. The time complexity of Radix Sort is dependent on the number of elements in the array and the
number of digits in the largest element.
Ans: True
4. Radix Sort can be used for both integers and strings with fixed-size keys.
Ans: True
5. The space complexity of Radix Sort is O(n+b), where n is the number of elements and b is the
base used for grouping digits.
Ans: True
6. Radix Sort is more efficient than comparison-based sorting algorithms when the number of
digits is small compared to the number of elements.
Ans: True
7. Radix Sort is an in-place algorithm because it does not require additional memory for sorting.
Ans: False
8. Shell Sort is a variation of Bubble Sort.
Ans: False
9. The main idea of Shell Sort is to allow the exchange of far apart elements.
Ans: True
10. An array is considered h-sorted if all sublists of every h'th element are sorted.
Ans: True
11. Shell Sort begins by making the array 1-sorted and progressively increases the gap size.
Ans: False
12. The Shell Sort algorithm requires the list to be divided into sub-lists with equal intervals to the
current gap size (h).
Ans: True
13. The best-case time complexity of Shell Sort with efficient gap sequences is O(n log n).
Ans: True
14. Quick Sort is based on the Divide and Conquer strategy.
Ans: True
15. In Quick Sort, the pivot element is always chosen as the median of the array.
Ans: False
16. After partitioning in Quick Sort, all elements smaller than the pivot are placed to its left, and all
greater elements to its right.
Ans: True
17. The base case of Quick Sort occurs when there are two elements left in the sub-array.
Ans: False
18. The best-case time complexity of Quick Sort is O(n log n).
Ans: True
19. The worst-case time complexity of Quick Sort is O(n²), which occurs when the pivot results in
highly unbalanced partitions.
Ans: True
20. The average-case time complexity of Quick Sort is O(n²).
Ans: False
1. Quick Sort is a sorting algorithm based on the ________ and ________ approach that picks an
element as a pivot.
(Answer: Divide and Conquer)
2. The pivot in Quick Sort can be chosen as the ________, ________, ________, or the ________ of
the array.
(Answer: first element, last element, random element, median)
3. After partitioning, all elements smaller than the pivot are placed to its ________, and all greater
elements to its ________.
(Answer: left, right)
4. The base case for Quick Sort occurs when the sub-array contains ________ element(s), as it is
already sorted.
(Answer: one)
5. The best-case time complexity of Quick Sort occurs when the pivot divides the array into
________ parts at every step, resulting in a time complexity of ________.
(Answer: nearly equal, O(n log n))
6. The worst-case time complexity occurs when the pivot is the ________ or the ________
element, leading to highly unbalanced partitions and a time complexity of ________.
(Answer: smallest, largest, O(n²))
7. The average-case time complexity of Quick Sort is ________, assuming reasonably balanced
partitions.
(Answer: O(n log n))
8. Quick Sort is an ________ algorithm, meaning it requires no additional memory for the array
itself.
(Answer: in-place)
9. Shell Sort is mainly a variation of ________ sort.
(Answer: insertion)
10. In insertion sort, we move elements only ________ position ahead, which can involve many
movements when an element needs to be moved far.
(Answer: one)
11. The idea of Shell Sort is to allow the exchange of ________ items.
(Answer: far)
12. In Shell Sort, the array is made ________-sorted for a large value of h.
(Answer: h)
13. The value of h is reduced until it becomes ________.
(Answer: 1)
14. An array is said to be h-sorted if all sub-lists of every ________ element are sorted.
(Answer: h’th)
15. The gap size, denoted as ________, is initialized at the beginning of the algorithm.
(Answer: h)
16. The time complexity of Shell Sort heavily depends on the ________ sequence used.
(Answer: gap)
17. The worst-case time complexity of Shell Sort with Shell’s original gap sequence is ________.
(Answer: O(n²))
18. Radix Sort is a ________ sorting algorithm that processes elements digit by digit.
(Answer: linear)
19. Radix Sort is efficient for ________ or ________ with fixed-size keys.
(Answer: integers, strings)
20. Rather than comparing elements directly, Radix Sort distributes the elements into
________ based on each digit’s value.
(Answer: buckets)
A Text Book on Data Structure Using C++
1. Learn about different searching methods: Linear Search and Binary Search.
4. Compare the time complexity of Linear Search (O(n)) and Binary Search (O(log n)).
Finding an element in an array is called as searching. There are two types of searching
Complexity of search algorithm is measured in terms of number of comparisons to be made to find the
element. Searching operation need to be performed several times in computer programming.
1. Best Case:
The target element is the first element in the list. Time Complexity is O(1).
2. Worst Case:
The target element is the last element in the list, or it is not present in the list. Time Complexity: O(n),
where n is the number of elements in the list.
3. Average Case:
The target element is located randomly in the list. On average, half of the elements need to be checked.
Time Complexity is O(n).
2. It is less efficient compared to other searching algorithms like binary search for large datasets.
However, it is simple to implement and works well for small lists or unsorted data.
if (arr[i] == target) {
int main() {
int data[] = {12, 45, 78, 23, 56, 89, 67, 34, 90};
if (result != -1) {
cout << "Element found at index " << result << endl;
} else {
return 0;
Output:
Initially #include statement is used to include all required header files in the program. The <iostream> is
included for input-output operations. The using namespace std; allows us to use standard functions like
cout without needing std::. The function linearSearch() is used to perform search operation. In the main
program it is called.
Repeatedly check until the value is found or the interval is empty. This search method has very low
number of comparisons. Complexity of this algorithm is O(log n). This method is much faster than linear
search.
1. Best Case:
The target element is found in the middle of the array on the first comparison. Time Complexity: is O(1)
2. Worst Case:
The search space is halved repeatedly until only one element is left. For a list of size n, the number of
comparisons is proportional to log n. Time Complexity is O(log n).
3. Average Case:
The target element is equally likely to be anywhere in the sorted array. The number of comparisons is
still proportional to log n. Time Complexity: O(log n).
1. Iterative Version:
Binary search performed iteratively does not require extra space beyond a few variables for indices and
comparisons. Space Complexity is O(1).
2. Recursive Version:
The recursive version of binary search requires space for the function call [Link] the worst case, the
depth of the recursion tree is log2n. Space Complexity is O(log n)
2. It is much faster than linear search for large datasets, especially when the array is sorted.
3. Iterative implementation is generally preferred for space efficiency, as it avoids the overhead of
recursion.
#include <iostream>
// Repeat until the pointers low and high meet each other
if (x == array[mid])
return mid;
if (x > array[mid])
low = mid + 1;
else
high = mid - 1;
return -1;
int main(void) {
int x = 4;
if (result == -1)
printf("Not found");
else
Output:
Initially #include statement is used to include all required header files in the program. The <iostream> is
included for input-output operations. The using namespace std; allows us to use cout and cin without
std:: The function binarySearch() is used to perform search operation. In the main program it is called.
Summary
Searching is the process of finding an element in an array. The two main types of searching are Linear
Search and Binary Search. Linear Search is a simple technique where each element is checked one by
one. It works on both sorted and unsorted lists but is inefficient for large datasets with a worst-case
time complexity of O(n). Binary Search is a faster method that works on sorted arrays by repeatedly
dividing the search space in half. It has a time complexity of O(log n) and is more efficient for large
datasets.
Questions
1. Answer the following questions.
A. Sorting
B. Searching
C. Inserting
D. Traversing
Answer: B. Searching
A. Linear Search
B. Binary Search
C. Sequential Search
D. Quick Search
Answer: D. Quick Search
A. Random Search
B. Sequential Search
C. Binary Search
D. Fast Search
Answer: B. Sequential Search
A. O(n)
B. O(log n)
C. O(1)
D. O(n2)
Answer: C. O(1)
A. O(n)
B. O(1)
C. O(log n)
D. O(n2)
Answer: B. O(1)
6. In linear search, how many elements are checked in the worst case for an array of size nnn?
A. 1
B. n/2
C. n
D. 2n
Answer: C. n
A. One-third
B. Half
C. One-fourth
D. One-fifth
Answer: B. Half
10. Which of the following is the time complexity of Binary Search in the best case?
A. O(n)
B. O(log n)
C. O(1)
D. O(n2)
Answer: C. O(1)
11. Which search method has a lower number of comparisons than Linear Search?
A. Sequential Search
B. Binary Search
C. Depth-First Search
D. Breadth-First Search
Answer: B. Binary Search
12. What is the space complexity of the iterative version of Binary Search?
A. O(n)
B. O(log n)
C. O(1)
D. O(n2)
Answer: C. O(1)
13. What is the space complexity of the recursive version of Binary Search?
A. O(n)
B. O(log n)
C. O(1)
D. O(n2)
Answer: B. O(log n)
3. In linear search, elements are compared one by one starting from the first element.
Answer: True
6. The space complexity of linear search is O(1) because it requires no extra memory apart from
the input array.
Answer: True
7. Linear search is less efficient than binary search for large datasets.
Answer: True
Answer: True
10. The time complexity of Binary Search in the worst case is O(n).
11. The time complexity of Binary Search in the best case is O(log n).
12. Binary Search is slower than Linear Search for large datasets, especially when the array is
sorted.
Answer: False (Binary Search is much faster than Linear Search for large sorted datasets.)
4. In linear search, the search element is compared with each element of the array one by one,
starting from the ______ element.
Answer: first
6. The worst-case time complexity of linear search is ______, where nnn is the number of elements
in the list.
Answer: O(n)
7. The space complexity of linear search is ______ because it requires no extra memory aside from
the input list and a few variables.
Answer: O(1)
9. Linear search is less efficient compared to other searching algorithms like ______ for large
datasets.
Answer: binary search
Answer: half
11. The time complexity of Binary Search in the worst case is ______.
Answer: O(log n)
12. The time complexity of Binary Search in the best case is ______.
Answer: O(1)
13. Binary Search is much ______ than Linear Search for large datasets, especially when the array is
sorted.
Answer: faster
Answer: sorted
15. . In Binary Search, the search ______ when the element is found.
Answer: stops
16. The ______ version of Binary Search is generally preferred for space efficiency.
Answer: iterative
A Text Book on Data Structure Using C++
Ch-9 Stack
Objectives
Stack is used in many applications such as Recursion, keeping track of function calls, evaluation of
expression, servicing hardware interrupts and solving problems using backtracking.
Stack data structure is not inherently supported by programming languages. Stack can be implemented
by using Arrays or Linked Lists.
Value of index variable of an array can be assigned to Top pointer. When we insert element into stack,
Top is incremented by one. When we delete element then Top is decremented by one. By using array,
we can create a stack of fixed size.
There are two commonly performed operations on stack: Push and Pop.
4. Return success
4. Return success
Fig 9.4: Pop Operation on Stack
#include <bits/stdc++.h>
class Stack {
int top;
public:
int pop();
int peek();
bool isEmpty();
};
bool Stack::push(int x)
return false;
else {
a[++top] = x;
return true;
int Stack::pop()
if (top < 0) {
return 0;
else {
int x = a[top--];
return x;
int Stack::peek()
if (top < 0) {
return 0;
}
else {
int x = a[top];
return x;
bool Stack::isEmpty()
class Stack s;
[Link](10);
[Link](20);
[Link](30);
while(![Link]())
[Link]();
return 0;
Output
Top element is : 20
Observe that in above program the #include bits/stdc++.h is a header file in C++ that includes all
standard libraries. The #include keyword instructs the C++ compiler to process the contents of the
specified header file during compilation.
We can reverse a stack in C++ using another set or any other sequential data container. We just have to
reverse the order of the elements present in the stack. The below approach shows how to reverse stack
using another stack.
Approach
#include <iostream>
#include <stack>
while (![Link]()) {
[Link]();
int main()
// Initialize a stack
stack<int> currentStack;
[Link](1);
[Link](2);
[Link](3);
[Link](4);
[Link](5);
printStack(currentStack);
stack<int> tempStack;
while (![Link]()) {
[Link]([Link]());
[Link]();
currentStack = tempStack;
printStack(currentStack);
return 0;
Output:
Original stack: 5 4 3 2 1
Reversed stack: 1 2 3 4 5
The code #include <stack> using namespace std; in C++ means that you can use the stack functions and
classes without calling them, and you can use names from the standard library for variables and objects.
The function printStack() is used to print content of stack. In the main program elements 1,2,3,4,5 are
pushed into stack. This original stack is printed. Content of stack are reversed by using tempStack.
Further the reversed content is printed.
Summary
A stack is a linear data structure that follows the Last In, First Out (LIFO) principle, meaning that the last
element added is the first to be removed. The two fundamental operations of a stack are Push
(insertion) and Pop (deletion). Stacks are commonly implemented using arrays or linked lists, with a Top
pointer keeping track of the last inserted element. The C++ implementation of a stack involves defining a
class with functions for push, pop, peek, and checking if the stack is empty. Stacks are widely used in
applications like recursion, function call management, expression evaluation, and backtracking.
Questions
1. What is a Stack?
A. A linear list where insertion and deletion are performed at both ends
B. A linear list where insertion and deletion are performed only at one end
C. A linear list where elements are arranged in sorted order
D. A non-linear data structure
Answer: B
Answer: B LIFO
A. Insert
B. Enqueue
C. Push
D. Pop
Answer: C Push
A. Delete
B. Dequeue
C. Push
D. Pop
Answer: D Pop
Answer: C
Answer: C
A. It remains unchanged
B. It is decremented by one
C. It is incremented by one
D. It is set to zero
Answer: C
Answer: B
Answer: C
A. Recursion
B. Evaluation of expressions
C. Reversing a list
D. Sorting data using merge sort
Answer: D
11. In reversing a stack, what happens after all elements are pushed to the temporary stack?
Answer: C
1. A stack is a linear list that allows insertion and deletion operations only at ________ end.
Answer: one
2. A stack follows the ________ principle.
Answer: Last In First Out (LIFO)
3. The operation of adding an element to a stack is called ________, and the operation of
removing an element is called ________.
Answer: Push, Pop
4. The pointer ________ keeps track of the top element in a stack.
Answer: Top
5. A stack can be implemented using ________ or ________.
Answer: arrays, linked lists
6. During a Push operation, the Top pointer is ________ by one, and during a Pop
operation, it is ________ by one.
Answer: incremented, decremented
7. Before performing a Push operation, we must check if the stack is ________, and before
performing a Pop operation, we must check if the stack is ________.
Answer: full, empty
8. The operation that returns the value of the top element without removing it is called
________.
Answer: Peek
9. Stacks are used in applications such as recursion, evaluation of expressions, and
________ a list.
Answer: reversing
10. If a stack is full and a Push operation is attempted, it results in ________.
Answer: Stack Overflow
11. If a stack is empty and a Pop operation is attempted, it results in ________.
Answer: Stack Underflow
A Text Book on Data Structure Using C++
Stack-organized computers are better suited for post-fix notation than the traditional infix notation.
Thus, the infix notation must be converted to the postfix notation. The conversion from infix notation to
postfix notation must take into consideration the operational hierarchy.
(A + B) * (C + D) *+AB+CD AB+CD+*
If the precedence of the current scanned operator is higher than the precedence of the
operator on top of the stack, or if the stack is empty, or if the stack contains a ‘(‘, then
push the current operator onto the stack.
Else, pop all operators from the stack that have precedence higher than or equal to that
of the current operator. After that push the current operator onto the stack.
5. If the scanned character is a ‘)’, pop the stack and output it until a ‘(‘ is encountered, and discard
both the parenthesis.
7. Once the scanning is over, Pop the stack and add the operators in the postfix expression until it
is not empty.
#include <bits/stdc++.h>
int prec(char c) {
if (c == '^')
return 3;
return 2;
else
return -1;
void infixToPostfix(string s) {
stack<char> st;
string result;
char c = s[i];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
result += c;
else if (c == '(')
[Link]('(');
// If the scanned character is an ‘)’, pop and add to the output string from the stack
else if (c == ')') {
result += [Link]();
[Link]();
[Link]();
}
// If an operator is scanned
else {
result += [Link]();
[Link]();
[Link](c);
while (![Link]()) {
result += [Link]();
[Link]();
int main() {
infixToPostfix(exp);
return 0;
Output:
abcd^e-fgh*+^*+i-
The code #include bits/stdc++.h using namespace std means that the program includes all standard
libraries and allows the use of names for variables and objects from the standard library. The function
prec() is used to return precedence of operators. For exponentiation operator it returns 3, for / and * it
returns 2 and for + and – it returns 1. For all other symbols it returns -1.
Program further scan the infix expression from left to right. If the scanned character is an operand, put it
in the postfix expression. Otherwise, if the precedence of the current scanned operator is higher than
the precedence of the operator on top of the stack, or if the stack is empty, or if the stack contains a ‘(‘,
then push the current operator onto the stack.
2. Scan the given expression from left to right and do the following for every scanned element.
o If the element is an operator, pop operands for the operator from the stack. Evaluate
the operator and push the result back to the stack.
3. When the expression is ended, the number in the stack is the final answer.
#include <bits/stdc++.h>
stack<int> st;
if (isdigit(exp[i]))
[Link](exp[i] - '0');
// If the scanned character is an operator, pop two elements from stack apply the Operator
else {
[Link]();
[Link]();
switch (exp[i]) {
case '+':
[Link](val2 + val1);
break;
case '-':
[Link](val2 - val1);
break;
case '*':
[Link](val2 * val1);
break;
case '/':
[Link](val2 / val1);
break;
return [Link]();
}
// Main Code
int main()
// Function call
return 0;
Output:
postfix evaluation: -4
In the program first of all the required header files are included. Further a function is written to evaluate
postfix expression to which a postfix expression string is passed as an argument. An expression size stack
is created and elements are pushed into stack. If element is operator then two elements are popped off
stack and operation is performed. When the expression ends, the number on top of stack is answer. In
above example, our expression is 231*+9-. It is evaluated as: (2+3*1)-9 = -4.
Summary
Arithmetic expressions can be represented in infix, prefix (Polish notation), or postfix (Reverse Polish
notation). Infix notation requires operator precedence rules or parentheses to determine the correct
order of operations, while prefix and postfix notations eliminate this ambiguity. Stack-based evaluation
is particularly effective for postfix expressions. To convert an infix expression to postfix, a stack is used
to handle operator precedence and parentheses. The process involves scanning the expression, pushing
operands directly into the output, and managing operators based on their precedence. For postfix
expression evaluation, a stack stores operands. Operators pop values from the stack, perform
calculations, and push the result back. The final value on the stack is the evaluated result.
Questions
b. 55+(78*5)-56
1. What is the main advantage of postfix (reverse Polish) notation over infix notation?
A) It is easier to read.
B) It eliminates the need for parentheses to define operator precedence.
C) It requires fewer operators.
D) It allows for more operands.
Answer: B
A) AB + C *
B) * + A B C
C) A B C + *
D) + * A B C
Answer: B
A) A B C * + D -
B) A + B * C - D
C) A B + C * D -
D) A B C D + * -
Answer: A
A) A B + C D + *
B) A B C D + + *
C) A B * + C D * +
D) A + B * C + D
Answer: A
7. In the context of stacks and arithmetic expression evaluation, what is the purpose of operator
precedence?
8. Which of the following is the correct sequence of steps to evaluate a postfix expression using a stack?
A) Push all operands onto the stack; pop and apply operators.
B) Scan the expression left to right; push operands onto the stack; pop operands when an operator is
encountered and apply the operation.
C) Convert the expression to infix; evaluate using operator precedence.
D) Push operators and operands alternately onto the stack and evaluate as they are encountered.
Answer: B
9. Which of the following operators has the highest precedence in arithmetic expressions?
A) Addition (+)
B) Multiplication (*)
C) Parentheses (())
D) Subtraction (-)
Answer: C
A) A B C + * D /
B) A * B + C / D
C) A B C * + D /
D) A B + C D * /
Answer: A
12. When scanning a postfix expression, what is done if the scanned element is a number?
13. What happens when an operator is encountered during the evaluation of a postfix expression?
14. At the end of evaluating a postfix expression, what does the stack contain?
15. How many operands are popped from the stack when a binary operator (e.g., +, -, *, /) is
encountered?
A) 1
B) 2
C) 3
D) None
Answer: B
A) Queue
B) Linked List
C) Stack
D) Array
Answer: C
18. For the postfix expression 5 6 2 + *, what is the result after evaluating it?
A) 30
B) 40
C) 50
D) 60
Answer: D
19. If a postfix expression has n numbers and m operators, how many elements will the stack contain at
the start of the evaluation?
A) 0
B) n
C) m
D) n + m
Answer: A
20. What would happen if an invalid postfix expression is evaluated (e.g., an operator without enough
operands)?
4. Stack-organized computers are better suited for infix notation than postfix notation.
Answer: False (They are better suited for postfix notation.)
5. The precedence of operators must be considered when converting an infix expression to postfix
notation.
Answer: True
7. When a closing parenthesis is encountered during conversion, operators are popped from the stack
until an opening parenthesis is encountered.
Answer: True
8. After scanning the infix expression, any remaining operators in the stack are discarded.
Answer: False (They are popped and added to the postfix expression.)
10. The order of operands and operators in infix notation uniquely determines the evaluation order.
Answer: False (Parentheses or operator-precedence conventions are required.)
11. A stack is used to store operands or values during the evaluation of a postfix expression.
Answer: True
14. When an operator is encountered, operands are pushed onto the stack.
Answer: False (Operands are popped from the stack, the operation is evaluated, and the result is pushed
back.)
15. At the end of the evaluation, the stack contains multiple results corresponding to different parts of
the expression.
Answer: False (The stack contains only the final answer.)
16. Only one operand is popped from the stack for each binary operator during evaluation.
Answer: False (Two operands are popped for each binary operator.)
17. The result of evaluating a postfix expression is stored in the stack as the only remaining element
after the process is complete.
Answer: True
18. The process of evaluating a postfix expression requires converting it to infix notation first.
Answer: False (Postfix expressions are evaluated directly without conversion.)
19. An operator without sufficient operands in the stack will result in a stack underflow error.
Answer: True
20. Postfix expression evaluation can be implemented efficiently using a queue instead of a stack.
Answer: False (It is implemented using a stack.)
3. Polish notation, also known as _______ notation, places the operator before its operands.
Answer: prefix
5. Stack-organized computers are better suited for _______ notation than traditional infix
notation.
Answer: postfix
6. During the conversion from infix to postfix notation, operands are added _______ to the postfix
expression.
Answer: directly
7. If a scanned operator has _______ precedence than the operator on top of the stack, it is
pushed onto the stack.
Answer: higher
8. When a closing parenthesis is encountered, operators are popped from the stack until an
_______ is encountered.
Answer: opening parenthesis
9. Once the scanning of the infix expression is complete, the remaining operators in the stack are
_______ and added to the postfix expression.
Answer: popped
10. Parentheses or _______ conventions are used to distinguish the order of operations in infix
notation.
Answer: operator-precedence
11. A _______ is used to store operands or values during the evaluation of a postfix expression.
Answer: stack
12. The postfix expression is scanned from _______ to _______.
Answer: left; right
13. If the scanned element is a _______, it is pushed into the stack.
Answer: number
14. When an _______ is encountered, operands are popped from the stack, the operation is
evaluated, and the result is pushed back into the stack.
Answer: operator
15. At the end of the evaluation, the stack contains the _______ as the only remaining element.
Answer: final answer
16. For each binary operator, _______ operands are popped from the stack for evaluation.
Answer: two
17. If the stack does not have enough operands for an operator, it results in a _______ error.
Answer: stack underflow
18. Postfix expressions can be evaluated _______, without converting them to infix notation.
Answer: directly
19. The evaluation of postfix expressions is based on the use of a _______ to store intermediate
results.
Answer: stack
20. A postfix expression is processed element by element until the _______ of the expression is
reached.
Answer: end
A Text Book on Data Structure Using C++
Objectives
Step 1: Reverse the infix expression. Note while reversing each opening bracket ‘(‘ will become closing
bracket ‘)’ and each ‘)’ becomes ‘(‘.
While converting to postfix expression, instead of using pop operation to pop operators with greater
than or equal precedence, here we will only pop the operators from stack that have greater precedence.
#include <bits/stdc++.h>
bool isOperator(char c)
int getPriority(char C)
if (C == '-' || C == '+')
return 1;
return 2;
else if (C == '^')
return 3;
return 0;
stack<char> char_stack;
string output;
if (isalpha(infix[i]) || isdigit(infix[i]))
output += infix[i];
char_stack.push('(');
// If the scanned character is an ‘)’, pop and output from the stack
output += char_stack.top();
char_stack.pop();
char_stack.pop();
// Operator found
else {
if (isOperator(char_stack.top())) {
if (infix[i] == '^') {
while (
getPriority(infix[i])
<= getPriority(char_stack.top())) {
output += char_stack.top();
char_stack.pop();
else {
while (
getPriority(infix[i])
< getPriority(char_stack.top())) {
output += char_stack.top();
char_stack.pop();
char_stack.push(infix[i]);
while (!char_stack.empty()) {
output += char_stack.top();
char_stack.pop();
return output;
}
// Reverse String and replace ( with ) and vice versa Get Postfix Reverse Postfix
int l = [Link]();
// Reverse infix
reverse([Link](), [Link]());
if (infix[i] == '(') {
infix[i] = ')';
infix[i] = '(';
// Reverse postfix
reverse([Link](), [Link]());
return prefix;
int main()
{
string s = ("x+y*z/w+u");
// Function call
return 0;
Output:
++x/*yzwu
First of all the required header files are included in the program. The function isOperator is used to
check if input character is operator. Further operator priorities are fixed by using function getPriority. A
string function infixToPostfix is used to convert infix string to postfix by using above method.
When input string is: x+y*z/w+u then output string is: ++x/*yzwu.
Algorithm
Example:
Expression: +9*26
Sequence of Actions:
Result: 21
#include <bits/stdc++.h>
bool isOperand(char c)
// be an operand
return isdigit(c);
stack<double> Stack;
for (int j = [Link]() - 1; j >= 0; j--) {
// Push operand to Stack To convert exprsn[j] to digit subtract '0' from exprsn[j].
if (isOperand(exprsn[j]))
[Link](exprsn[j] - '0');
else {
double o1 = [Link]();
[Link]();
double o2 = [Link]();
[Link]();
switch (exprsn[j]) {
case '+':
[Link](o1 + o2);
break;
case '-':
[Link](o1 - o2);
break;
case '*':
[Link](o1 * o2);
break;
case '/':
[Link](o1 / o2);
break;
}
return [Link]();
int main()
return 0;
Output:
21
All required header files are included in program by using #include statement. The function isOperand()
is used to check if input character is operand. The function evaluatePrefix is used for prefix expression
evaluation.
Summary
The conversion of infix expressions to prefix notation is an essential concept in computer science,
particularly for efficient expression evaluation. Prefix notation eliminates the need for parentheses and
operator precedence rules, making computations more straightforward. The conversion process
involves reversing the infix expression, converting it into a modified postfix expression, and then
reversing the result to obtain the prefix form. A stack-based approach is used to manage operators and
operands efficiently during the conversion. A C++ program can be implemented to automate this
process by considering operator precedence and using appropriate stack operations.
Questions
1. What is the first step in converting an infix expression to a prefix expression using a stack?
A) Reverse the infix expression and replace brackets appropriately
B) Convert the infix expression directly to postfix
C) Push all operators to a stack
D) Reverse the infix expression without changing the brackets
Answer: A
2. In step 1 of the conversion process, what happens to the brackets when reversing the infix
expression?
A) The brackets remain unchanged
B) Opening brackets ‘(’ become closing brackets ‘)’ and vice versa
C) Only opening brackets are removed
D) Brackets are ignored during this step
Answer: B
3. Which of the following statements is true about step 2 in the conversion process?
A) Operators with equal precedence are always popped from the stack
B) Only operators with greater precedence are popped from the stack
C) Parentheses are ignored in this step
D) The postfix expression is directly reversed
Answer: B
Answer: A
Answer: D
7. In step 2, how does the process of converting to postfix differ from the standard postfix
conversion?
A) Operators with equal precedence are treated differently
B) Only operators with greater precedence are popped
C) Parentheses are not used
D) Operands are pushed to the stack
Answer: B
8. If the infix expression is A + B * C, what would the intermediate "nearly postfix" expression look
like during the process?
A) +A*BC
B) A B C * +
C) * + A B C
D) + * A B C
Answer: B
9. After reversing the postfix expression obtained from the infix expression A * (B + C), what would
the final prefix expression be?
A) *A+BC
B) +A*BC
C) A+BC*
D) *+ABC
Answer: D
10. What is the role of operator precedence in the infix-to-prefix conversion process?
A) To decide the order of operands
B) To determine when operators are pushed or popped from the stack
C) To reverse the expression correctly
D) To check for balanced parentheses
Answer: B
11. Why are prefix and postfix expressions faster to evaluate compared to infix expressions?
A) They don’t require processing brackets or operator precedence rules
B) They are always shorter than infix expressions
C) They require fewer operands
D) They have a fixed number of operators
Answer: A
Answer: B
Answer: B
14. What should be done when the character at pointer PPP is an operand?
A) Ignore it
B) Push it to the stack
C) Pop two elements from the stack
D) Decrement the pointer
Answer: B
15. When the character at pointer P is an operator, what action should be performed?
A) Push it to the stack
B) Pop two elements from the stack, perform the operation, and push the result back
C) Pop one element from the stack and push the operator back
D) Skip the operator and move the pointer
Answer: B
Answer: C
17. Where is the final result of the prefix evaluation stored?
A) At the bottom of the stack
B) At the top of the stack
C) In a separate result variable
D) In the original expression
Answer: B
18. In the example provided, what is the result of evaluating the prefix expression +9*26?
A) 15
B) 18
C) 21
D) 27
Answer: C
Answer: C
1. In the first step of converting an infix expression to a prefix expression, the expression is
reversed, and the brackets are swapped.
True
2. During the second step, operators with equal or higher precedence are always popped
from the stack.
False (Only operators with greater precedence are popped.)
3. The final step of the process is to reverse the postfix expression to obtain the prefix
expression.
True
4. The stack data structure is used to convert infix expressions directly to prefix without
intermediate steps.
False
5. Opening brackets ‘(’ are replaced with closing brackets ‘)’ during the reversal of the infix
expression.
True
6. The purpose of the stack is to manage operator precedence and handle parentheses
effectively during conversion.
True
7. In step 2, the process is the same as standard infix-to-postfix conversion.
False (It differs by only popping operators with greater precedence.)
8. The process of reversing the postfix expression guarantees that operator precedence is
preserved in the prefix expression.
True
9. The intermediate "nearly postfix" expression is obtained by directly converting the
original infix expression without any changes.
False (The reversed infix expression is used to obtain the "nearly postfix" form.)
10. The final prefix expression is obtained by reversing the intermediate postfix expression.
True
11. Prefix and postfix expressions are faster to evaluate because they do not require
processing brackets or operator precedence rules.
True
12. In prefix and postfix expressions, operators are evaluated based on their precedence.
False (They are evaluated in the order they appear.)
13. The first step in evaluating a prefix expression is to initialize a pointer at the start of the
string.
False (The pointer is initialized at the end of the string.)
14. If the character at the pointer is an operand, it is pushed to the stack.
True
15. If the character at the pointer is an operator, two elements are popped from the stack,
the operation is performed, and the result is pushed back to the stack.
True
16. After processing each character in the prefix expression, the pointer is decremented by
1.
True
17. The final result of evaluating a prefix expression is stored at the bottom of the stack.
False (It is stored at the top of the stack.)
18. In the given example, the result of evaluating the prefix expression +9*26 is 21.
True
19. The stack is used to temporarily store operators during prefix expression evaluation.
False (The stack stores operands and intermediate results.)
20. Prefix expressions do not contain brackets, making them easier to evaluate.
True
1. The first step in converting an infix expression to a prefix expression is to _______ the
infix expression and swap the brackets.
Answer: reverse
2. While reversing the infix expression, each opening bracket ‘(’ becomes a _______
bracket ‘)’, and vice versa.
Answer: closing
3. The second step involves converting the reversed infix expression to a "nearly" _______
expression.
Answer: postfix
4. During the postfix conversion step, only operators with _______ precedence are popped
from the stack.
Answer: greater
5. In the final step, the _______ expression obtained in step 2 is reversed to get the prefix
expression.
Answer: postfix
6. The _______ data structure is used to convert infix expressions to postfix and eventually
to prefix.
Answer: stack
7. The stack is primarily used to manage operator _______ and handle parentheses during
the conversion process.
Answer: precedence
8. Reversing the postfix expression ensures that the correct order of operators and
operands is maintained in the _______ expression.
Answer: prefix
9. The reversed infix expression is used to generate a "nearly" postfix expression, not the
_______ infix expression.
Answer: original
10. To convert infix to prefix, the process involves three steps: reverse the infix, convert to a
nearly postfix expression, and finally _______ the postfix expression.
Answer: reverse
11. Prefix and postfix expressions are faster to evaluate because they do not require
processing _______ or operator precedence rules.
Answer: brackets
12. In prefix and postfix expressions, the operator that comes _______ is evaluated first,
regardless of its precedence.
Answer: first
13. To evaluate a prefix expression, the pointer PPP is initialized at the _______ of the
string.
Answer: end
14. If the character at the pointer is an _______, it is pushed to the stack.
Answer: operand
15. If the character at the pointer is an operator, _______ elements are popped from the
stack, the operation is performed, and the result is pushed back to the stack.
Answer: two
16. After processing each character, the pointer is _______ by 1.
Answer: decremented
17. The final result of evaluating a prefix expression is stored at the _______ of the stack.
Answer: top
18. The example prefix expression +9*26 evaluates to _______.
Answer: 21
19. In the given example, after encountering the operator *, the operands 6 and 2 are
_______ together.
Answer: multiplied
20. Prefix expressions do not contain _______, which simplifies their evaluation.
Answer: brackets
A Text Book on Data Structure Using C++
Ch-12 Recursion
Objectives
2. Demonstrate recursion through examples like factorial calculation and Fibonacci sequence.
12.1 Introduction
There are certain problems for which solution depends upon smaller instances of the same problem. For
example, when we want to compute factorial of 5, then it can be computed by obtaining factorial of 4
as, 5 ! = 5 x 4 ! and so on.
Such problems can be solved by making use of technique called as Recursion. Recursion is a technique in
which a function or procedure call itself to find solution of the problem.
To avoid recursive function to go into infinite loop, there must be at least one base criteria or condition
that will stop recursion. Also, during the process of recursive calls, it must come closer to base condition.
Recursion can be implemented by using stack which can hold all information needed during recursion
process.
There are different types of recursion such as Linear Recursion, Binary Recursion and Multiple
Recursion.
Recursion is a programming concept where a function calls itself to solve a problem. It’s a powerful tool
often used to solve problems that can be broken down into smaller, similar sub-problems.
1. Base Case:
o Without a base case, the function would call itself indefinitely, leading to a stack
overflow error.
2. Recursive Case:
o This is the part of the function where it calls itself to work on a smaller version of the
problem.
1. It checks the base case. If the base case is met, it stops calling itself and starts returning values.
2. If the base case is not met, the function calls itself with a modified input, moving closer to the
base case.
Mathematical Definition:
#include<iostream>
//Main Program
int main() {
int n;
cin >> n;
cout << "Factorial of " << n << " = " << factorial(n);
return 0;
}
//Recursive Function
int factorial(int n) {
if(n > 1)
else
return 1;
For n=4:
factorial(4)=4×factorial(3)
factorial(3)=3×factorial(2)
factorial(2)=2×factorial(1)
factorial(1)=1×factorial(0)
Result:
4!=4×3×2×1=24
2. Tree Traversals: The inorder, preorder, and postorder traversal of binary trees can be performed by
using recursion.
3. Divide and Conquer Algorithms: The QuickSort, MergeSort, and Binary Search operations can be
performed by using recursion.
4. Dynamic Programming: Solving overlapping sub problems using recursion with memorization, that
is, cache results of function call.
5. Combinatorial Problems: Generating permutations, combinations, and solving puzzles like the Tower
of Hanoi.
12.4 Advantages of Recursion
1. Simplifies code for problems that have repetitive substructures.
o If the recursion depth exceeds the system's stack size, it can result in a stack overflow
error.
2. Efficiency:
Summary
Recursion is a programming technique where a function calls itself to solve problems that can be broken
down into smaller subproblems. To prevent infinite loops, a base case is defined to stop recursion, while
a recursive case ensures that the function progresses toward the base case. Recursion is widely used in
solving mathematical problems such as factorial computation, Fibonacci sequence, and Greatest
Common Divisor (GCD). It is also applied in tree traversals (inorder, preorder, postorder), divide-and-
conquer algorithms (QuickSort, MergeSort, Binary Search), dynamic programming, and combinatorial
problems like permutations and the Tower of Hanoi. While recursion simplifies complex problems, it
comes with challenges like stack overflow and redundant computations. These issues can be mitigated
using memoization or converting recursion to an iterative approach when necessary.
Questions
Answer: C
Answer: B
Answer: A
Answer: B
Answer: B
Answer: B
A. Linear recursion
B. Binary recursion
C. Multiple recursion
D. Dynamic recursion
Answer: D
Answer: C
Answer: B
Answer: B
Ch-13 Queue
Objectives
By the end of this session, learners should be able to:
Queue is a linear data structure in which insertion takes place at one end and deletion takes place at
other end. A new element is inserted at Rear End (Back End) and existing element is deleted from Front
End.
Queue is also called as First In First Out (FIFO) list. Two operations that are commonly performed on
Queue:
Queue is a very useful data structure that is used when resource is shared among multiple consumers
such as CPU scheduling and Disk scheduling. It is also used in printer sharing, in OS and in networks.
An array can be used to represent queue in memory. Front points to the element at the front of the
queue (the first element to be dequeued). Rear points to the last element in the queue (the most
recently enqueued element). Enqueue is used to add an element to the rear of the queue. Dequeue is
used to emove an element from the front of the queue. Fig 13.2 shows representation of queue as an
array
Define an array with a fixed size capacity\text{capacity}capacity. Use front and rear pointers to track the
queue's state.
2. Enqueue
Check if the queue is full, that is, rear is at the last index. Add the new element at the rear position and
increment the rear.
3. Dequeue
Check if the queue is empty (front is the same as rear for an empty queue). Remove the element at the
front position and increment the front.
#include <iostream>
class Queue {
public:
int front;
int rear;
int arr[MAX_SIZE];
int getFront()
if (isEmpty()) {
return -1;
return arr[front];
int getRear()
{
if (isEmpty()) {
return -1;
return arr[rear];
if (isFull()) {
return;
if (isEmpty())
front = 0;
rear++;
arr[rear] = val;
int dequeue()
if (isEmpty()) {
cout << "Queue is empty" << endl;
return -1;
front++;
if (isEmpty())
return ans;
void display()
if (isEmpty()) {
return;
}
};
int main()
Queue q;
// Enqueueing elements
[Link](1);
[Link](2);
[Link](3);
[Link]();
[Link](4);
[Link](5);
[Link]();
// condition
[Link](6);
// Dequeueing elements
[Link]();
return 0;
Output:
After Dequeueing:
Front element: 3
Rear element: 6
Queue: 3 4 5 6
In above program maximum size of queue is 100 and initial front and rear pointers are set to -1. The
funjction isEmpty() is used to check if queue is empty. The funjction isFull() is used to check if queue is
full. The function enqueue() is used to insert element. The function dequeue() is used to delete element.
Linear queue
Also known as a simple queue, this is the most basic queue structure. It follows the First-In-First-Out
(FIFO) principle, where elements are added to the rear and removed from the front.
Circular queue
Also known as a circular buffer, this queue structure connects the last element to the first, forming a
circular structure. When the queue is full, new elements overwrite the oldest elements in a circular
fashion. Fig 13.3 shows circular queue.
Fig 13.3: Circular Queue
Priority queue
This queue structure assigns a priority value to each element in the queue. Elements with higher priority
are dequeued before elements with lower priority. Fig 13.4 shows priority queue.
Double-ended queue
Also known as a deque, this queue structure supports insertion and deletion operations at both ends
(front and rear). This means that it can be used as both a stack and a queue. Fig 13.4 shows dqueue.
Queues are used in operating systems to manage tasks like CPU scheduling, where processes are stored
in a queue and executed one at a time in order of their priority or arrival.
2. I/O Buffers
Queues are used to manage input/output buffers in devices like printers, where tasks are queued and
processed sequentially.
3. Data Transmission
In communication systems, queues manage data packets in networks. For example, in routers and
switches, queues ensure that packets are transmitted in the correct order.
In graph traversal algorithms, such as Breadth-First Search, queues are used to explore nodes layer by
layer.
5. Resource Management
Queues are used in managing resources such as printers, disk drives, or other shared resources where
jobs wait in line until the resource is available.
Queues are integral to asynchronous communication between different parts of a system, like message
queues in distributed systems and task queues in parallel programming.
7. Real-Time Systems
Real-time applications like call centers use queues to manage incoming calls and distribute them to
available agents.
8. Simulation of Processes
Queues are used in simulations to model real-world systems such as queues at a bank, customer service
desks, or traffic management systems.
9. Multimedia Streaming
In multimedia systems, queues help buffer audio and video streams to ensure smooth playback without
interruptions.
Printers often use queues to hold print jobs until they can be processed sequentially.
In distributed systems, task queues are used to schedule jobs across multiple processors or systems for
load balancing.
A variation of queues, called priority queues, is used in scenarios like Dijkstra's algorithm for shortest
path calculation and event-driven simulation.
Queues are also used to simulate real-world situations like customer lines at a supermarket or ticket
counters.
Queues like circular queues are used in memory management systems for managing buffers and caching
data.
Summary
A queue is a linear data structure based on the First-In-First-Out (FIFO) principle, where new elements
are inserted at the rear and existing elements are removed from the front. The two main operations are
enqueue (insertion at rear) and dequeue (deletion from front). Queues can be represented using arrays
with front and rear pointers to track positions, and implemented in C++ with functions to check
overflow/underflow, insert, delete, and display elements. Different types of queues include linear
queues, circular queues, priority queues, and double-ended queues (deque), each serving specific
purposes. Queues are widely used in applications such as CPU scheduling, disk and printer management,
I/O buffering, data transmission in networks, graph traversal (BFS), resource management,
asynchronous communication, real-time systems, simulations, multimedia streaming, and distributed
scheduling. Their versatility makes them one of the most important data structures in computer science.
Questions
A. A linear data structure where insertion and deletion occur at the same end
B. A linear data structure where insertion takes place at one end and deletion at the other end
C. A non-linear data structure where elements are stored hierarchically
D. A data structure used only for searching algorithms
Answer: B
Answer: C
A. Dequeue
B. Enqueue
C. Push
D. Pop
Answer: B
4. Which operation is used to remove an element from the front of the queue?
A. Enqueue
B. Dequeue
C. Insert
D. Delete
Answer: B
Answer: C
Answer: A
Answer: B
Answer: A
A. CPU scheduling
B. Disk scheduling
C. Depth-First Search (DFS)
D. Printer sharing
Answer: C
10. What are the two pointers used in a queue's array representation?
Answer: B
11. In a queue, if the current value of Rear is 5 and an element is enqueued, what will the new value of
Rear be?
A. 4
B. 5
C. 6
D. 0
Answer: C
12. What happens if you try to enqueue an element into a full queue?
Answer: B
A. Using two pointers: one for the middle and one for the end
B. Using two pointers: Front for deletion and Rear for insertion
C. Using one pointer to manage both insertion and deletion
D. Using three pointers for efficient management
Answer: B
1. In a queue, insertion takes place at one end, and deletion takes place at the other end.
Answer: True
2. A queue follows the Last In First Out (LIFO) principle.
Answer: False
3. The operation of inserting an element into a queue is called Enqueue.
Answer: True
4. Dequeue is the process of removing an element from the rear of the queue.
Answer: False
5. In a queue represented using an array, the rear pointer indicates the position where the next
element will be enqueued.
Answer: True
6. If the front pointer equals the rear pointer, the queue is empty.
Answer: True
7. A queue is a non-linear data structure.
Answer: False
8. The queue is commonly used in CPU scheduling and disk scheduling.
Answer: True
9. A queue cannot be implemented using an array.
Answer: False
10. The base condition for a full queue in an array is when the rear pointer equals the array size
minus one.
Answer: True
11. Enqueue and Dequeue are the two primary operations performed on a queue.
Answer: True
12. In a queue, the front pointer points to the last element in the queue.
Answer: False
13. Printer sharing in an operating system is an example of queue application.
Answer: True
14. During the Enqueue operation, if the rear pointer is at the last index, the queue is full.
Answer: True
15. The first element in a queue is the last one to be removed.
Answer: False
1. Queue is a linear data structure in which ______ takes place at one end and ______ takes place
at the other end.
Answer: insertion, deletion
2. A new element is inserted at the ______ end, and an existing element is deleted from the
______ end.
Answer: rear, front
3. Queue follows the ______ principle, where the first element inserted is the first one to be
removed.
Answer: First In First Out (FIFO)
4. The operation of inserting an element into a queue is called ______.
Answer: Enqueue
5. The operation of removing an element from a queue is called ______.
Answer: Dequeue
6. Queues are used in ______ scheduling and ______ scheduling.
Answer: CPU, disk
7. Printer sharing in an operating system is an application of ______.
Answer: queues
8. In an array representation of a queue, the ______ pointer points to the first element in the
queue.
Answer: front
9. In an array representation of a queue, the ______ pointer indicates the position where the next
element will be added.
Answer: rear
10. If the front pointer equals the rear pointer, the queue is considered ______.
Answer: empty
11. If the rear pointer equals the array size minus one, the queue is considered ______.
Answer: full
12. To implement a queue in memory, an ______ is defined with a fixed size capacity.
Answer: array
13. During the Enqueue operation, if the queue is full, ______ cannot occur.
Answer: insertion
14. During the Dequeue operation, if the queue is empty, ______ cannot occur.
Answer: deletion
15. The process of adding an element at the rear of the queue is called ______, and removing an
element from the front is called ______.
Answer: Enqueue, Dequeue
A Text Book on Data Structure Using C++
Arrays are stored in successive memory locations that requires large memory space. Size of array is fixed
and insertion and deletion in array is difficult. A linked list is a linear collection of data elements that are
not stored in successive memory locations. Every data element in the linked list points to the next
element. Fig 14.1 shows a linked list.
A linked list is a collection of nodes where every node consists of data and pointer. First element is
called as Head and last element is called as Tail of which pointer value is NULL. Accessing elements of
linked list is much easier as each element itself contain address of next element. Memory requirement
of linked list is larger than arrays. Linked list is a dynamic data structure as the list can grow during
program execution.
1. Singly Linked List: This is a basic linked list in which each node contains data and pointer to next
element. Last element pointer has NULL value. In this linked list we can traverse only in forward
direction. Fig 14.2 shows a singly linked list.
2. Circular Linked List: This is a singly linked list where last node points to first node. Such lists can
be used in time sharing problems. Fig 14.3 shows a circular linked list.
3. Doubly Linked List: In this list each node contains two pointers LPTR and RPTR. We can traverse
this list in forward and reverse direction. Fig 14.4 shows a doubly linked list.
Traversal of Singly Linked List is one of the fundamental operations, where we traverse or visit each
node of the linked list
Algorithm
Steps:
1. We will initialize a temporary pointer to the head node of the singly linked list.
2. After that, we will check if that pointer is null or not null, if it is null, then return.
3. While the pointer is not null, we will access and print the data of the current node, then we
move the pointer to next node.
Given a linked list and a key, the task of searching is to check if key is present in the linked list or not.
Algorithm
If the current value (i.e., curr->key) is equal to the key being searched return true.
Given a Linked List, the task is to insert a new node in this given Linked List at the following positions: At
the front of the linked list, before a given node, after a given node, at a specific position or at the end of
the linked list.
To insert a new node at the front, we create a new node and point its next reference to the current
head of the linked list. Then, we update the head to be this new node. This operation is efficient
because it only requires adjusting a few pointers.
Algorithm
1. Make the first node of Linked List linked to the new node
2. Remove the head from the original first node of Linked List
Deleting a node in a Linked List is an important operation and can be done in three main ways: removing
the first node, removing a node in the middle, or removing the last node.
1. Deletion at the Beginning operation involves removing the first node of the linked list.
2. To perform the deletion at the beginning of Linked List, we need to change the head pointer to
point to the second node.
1. Deletion at a specified position in a linked list involves removing a node from a specific
index/position, which can be the first, middle, or last node.
2. To perform the deletion, If the position is 1, we update the head to point to the next node and
delete the current head.
3. For other positions, we traverse the list to reach the node just before the specified position.
4. If the target node exists, we adjust the next of this previous node to point to next of next nodes,
which will result in skipping the target node.
Deletion at the end operation involves removing the last node of the linked list.
1. To perform the deletion at the end of Linked List, we need to traverse the list to find the second
last node, then set its next pointer to null.
2. If the list is empty then there is no node to delete or has only one node then point head to null.
Summary
A linked list is a dynamic linear data structure where elements (nodes) are stored in non-contiguous
memory locations, each containing data and a pointer to the next node. The first node is called the head
and the last node (tail) points to NULL. Unlike arrays, linked lists allow easy insertion and deletion but
require more memory due to pointers. Types include singly linked list (one-way traversal), circular linked
list (last node connects to the first), and doubly linked list (two-way traversal with two pointers).
Operations such as traversing, searching, insertion, and deletion are performed by manipulating node
pointers, making linked lists flexible for dynamic memory management and efficient modifications
compared to arrays.
Questions
1. Answer the following questions.
(i) What is linked list? Describe various terms associated with linked list.
Answer: B
2. Which part of a node in a linked list contains the address of the next node?
A. Data
B. Pointer
C. Head
D. Tail
Answer: B
A. Tail
B. Head
C. Pointer
D. Root
Answer: B
4. In a singly linked list, how many pointers does each node contain?
A. None
B. One
C. Two
D. Three
Answer: B
5. What is unique about a circular linked list compared to a singly linked list?
A. Each node contains an additional pointer
B. The last node points to the first node
C. It requires contiguous memory allocation
D. Nodes can only be traversed in reverse order
Answer: B
6. Which type of linked list allows traversal in both forward and reverse directions?
Answer: C
Answer: B
A. Traversing
B. Sorting
C. Insertion
D. Deletion
Answer: B
Answer: B
10. In the traversal of a singly linked list, when does the algorithm terminate?
Answer: A
11. What is the condition for searching a key in a linked list to be unsuccessful?
Answer: C
12. How can a new node be inserted at the beginning of a linked list?
Answer: B
13. During the deletion of the first node in a linked list, what needs to be updated?
Answer: B
14. What happens when a node is deleted at the end of the linked list?
Answer: B
15. Which type of linked list is best suited for time-sharing problems?
Ch-15 Trees
Objectives
By the end of this session, learners should be able to:
A tree is a non-linear data structure. This data structure is mainly used to represent data containing
hierarchical relationship between its elements. Records or table of contents can be represented in the
form of trees. Fig 15.1 shows hierarchical data structure.
A tree is a collection of zero or more nodes with one node called as root and zero or one or more
subtrees. Nodes are connected to each other by edges. Node with child is called as Parent node and
node with no child is called as Leaf node. Subtree is a part of tree. There are different types of trees
such as General tree, Forests, Binary tree, Binary Search tree, and Expression tree. Fig 15.2 shows
structure of tree.
Fig 15.2: Structure of Tree
2. Parent − Any node except the root node has one edge upward to a node called parent.
3. Child − The node below a given node connected by its edge downward is called its child node.
4. Leaf − The node which does not have any child node is called the leaf node
7. Levels − Level of a node represents the generation of a node. If the root node is at level 0, then
its next child node is at level 1, its grandchild is at level 2, and so on.
8. Keys − Key represents a value of a node based on which a search operation is to be carried out
for a node.
Every node has one parent and two nodes are connected by single path. For height K, number of nodes
are: 2K+1 – 1 for K >= 0. Algebraic expression can be represented by binary tree. Binary tree can be
represented in memory by linked list or array.
Binary tree can be represented by array. Root is stored at index value 0 and then in subsequent
locations left and right child value is stored. For height K, size of array required is: 2K+1 – 1 for K >= 0. Fig
15.5 shows binary tree representation in array.
Fig 15.5: Binary Tree Representation
2. Complete Binary tree: All levels are completely filled except last level. In last level all nodes must
be as left as possible.
3. Perfect Binary tree: All internal nodes has two children and all leafs are at same level.
4. Balanced Binary tree: Both right and left subtree differ by 1 level. Height of tree is O(log n). Ex:
Red Black tree.
5. Degenerate Binary tree: Every internal has one child. Fig 15.6 shows different types of binary
tree.
Fig 15.6: Types of Binary Tree
Preorder: (NLR)
Steps:
1. Process root R
Example:
Fig 15.7: Preorder Traversal
Inorder: (LNR)
Steps:
2. Process root R
Postorder: (LRN)
3. Process root R.
All above algorithms are recursively defined and we need to make use of stack to implement them.
Now For constructing an expression tree we use a stack. We loop through input expression and do the
following for every character.
2. If a character is an operator pop two values from the stack make them its child and push the
current node again.
3. In the end, the only element of the stack will be the root of an expression tree.
Summary
A tree is a non-linear hierarchical data structure consisting of nodes connected by edges, where the
topmost node is called the root and the nodes with no children are called leaves. Each node may
have child nodes, forming parent-child relationships that represent hierarchy. Trees are widely used
to organize data for efficient searching, insertion, and deletion. A binary tree is a special type where
each node has at most two children, while a binary search tree (BST) maintains elements in sorted
order for faster search. Trees can be represented in memory using arrays or linked structures, and
can be traversed using methods such as preorder, inorder, and postorder traversal. They are also
applied in expression evaluation, decision-making, and hierarchical data representation, making
them fundamental in computer science.
Questions
1. Answer the following:
(i) What is tree?
A) Linear
B) Non-linear
C) Sequential
D) Tabular
Answer: B) Non-linear
A) Parent
B) Child
C) Root
D) Leaf
Answer: C) Root
A) Root
B) Parent
C) Leaf
D) Sub-tree
Answer: C) Leaf
A) General tree
B) Binary tree
C) Sequential tree
D) Expression tree
Answer: C) Sequential tree
5. How many children can a node in a binary tree have at most?
A) 1
B) 2
C) 3
D) Unlimited
Answer: B) 2
7. What is the formula for the number of nodes in a binary tree of height K?
A) 2K + 1
B) 2K - 1
C) 2^(K+1) - 1
D) K^2
Answer: C) 2^(K+1) - 1
A) Stack
B) Array or Linked List
C) Queue
D) Hash Table
Answer: B) Array or Linked List
9. Which type of binary tree has all internal nodes with exactly two children and all leaves at the same
level?
10. In which type of binary tree is every internal node connected to only one child?
A) Preorder
B) Inorder
C) Postorder
D) Level-order
Answer: C) Postorder
A) Queue
B) Stack
C) Heap
D) Hash Table
Answer: B) Stack
15. Which of the following operations does an expression tree NOT perform?
4. A binary tree can have more than two children per node.
False
7. A binary search tree (BST) follows the rule that the left child contains values smaller than the
root and the right child contains values greater than the root.
True
8. A complete binary tree has all levels completely filled, except possibly the last level, which is
filled from the left.
True
9. A degenerate binary tree has all internal nodes with exactly two children.
False (It has only one child per internal node)
10. A full binary tree has every node with either 0 or 2 children.
True
15. An expression tree is a type of binary tree where internal nodes are operators and leaf nodes
are operands.
True
18. A balanced binary tree is one where the left and right subtrees differ in height by at most 2
levels.
False (The difference is at most 1 level)
20. The size of an array needed to represent a binary tree of height K is 2 K+1 - 1.
True
8. A __________ binary tree has all levels completely filled except possibly the last level, which is
filled from left to right.
Answer: complete
10. A __________ binary tree has all internal nodes with exactly two children and all leaf nodes at
the same level.
Answer: perfect
12. A degenerate binary tree has all internal nodes with only __________ child.
Answer: one
20. A node except the root has one edge upward to a node called the __________.
Answer: parent
21. A __________ is a tree where the left and right subtrees differ in height by at most one level.
Answer: balanced binary tree
22. An expression tree is a binary tree in which each internal node corresponds to an __________.
Answer: operator
25. In a binary tree, the root is stored at index __________ when using an array representation.
Answer: 0
27. The size of an array required to represent a binary tree of height K is __________.
Answer: 2^(K+1) - 1
A Text Book on Data Structure Using C++
Ch-16 Graphs
Objectives
By the end of this session, learners should be able to:
A graph is a non-linear data structure consisting of nodes and edges. Nodes are also called as vertices
and edges are called as lines or arcs. A graph G = (V, E) where V is set of vertices and E is set of edges.
For Ex: set of vertices can be V = {0,1,2,3,4} and set of edges E = {01,12,23,34,04,14,13}. Fig 16.1 shows
Graph.
2. Edge: Path between two vertices is called as edge and it is represented by adjacent vertices.
3. Adjacency: Two vertices are adjacent if they are connected to each other by edge.
6. Connected Graph: When there is a path from any vertex to every other vertex then it is called as
connected graph.
11. Relation: Relations are often represented using graphs, where vertices represent elements, and
edges represent relationships between them.
12. Weight: Weighted graph is a graph where each edge has an associated numerical value called a
weight or cost. This weight can represent distances, costs, time, or any other measurable
quantity.
13. Length: The length of a path in a graph refers to the sum of the weights of the edges along that
path.
The adjacency matrix A for a graph G = (V, E) with n vertices is a nxn matrix, such that Aij = 1, if there
is an edge from Vi to Vj and Aij = 0, if there is no edge. In linked representation graph can be
represented by adjacency list. Fig 16.3 shows representation of graph.
6. Splitting of Vertices: One vertex can be spliced into two or more vertices.
It begins with a node, then first traverses all its adjacent. Once all adjacent are visited, then their
adjacent are traversed.
Algorithm
1. Initialization: Enqueue the given source vertex into a queue and mark it as visited.
3. Dequeue a node from the queue and visit it (e.g., print its value).
This algorithm ensures that all nodes in the graph are visited in a breadth-first manner, starting from
the starting node. Fig 16.4 shows BFS.
Fig 16.4: BFS
In Depth First Search (or DFS) for a graph, we traverse all adjacent vertices one by one.
When we traverse an adjacent vertex, we completely finish the traversal of all vertices reachable
through that adjacent vertex.
This is similar to a tree, where we first completely traverse the left sub-tree and then move to the
right sub-tree.
The key difference is that, unlike trees, graphs may contain cycles (a node may be visited more than
once). To avoid processing a node multiple times, we use a boolean visited array. Fig 16.5 shows
DFS.
Fig 16.5: DFS
Computer Science
In Networks graphs are used in representing computer networks, where nodes are devices and edges
are connections. They are also used in internet modeling, including routing protocols like Dijkstra's
algorithm for shortest paths.
In data Structures graphs are used for dependency graphs in compilers for managing tasks like
topological sorting.
In Artificial Intelligence they are used in state-space exploration in path finding algorithms.
In database relationships graphs are used. They are used in social Networks modeling social interactions,
where nodes represent individuals; edges represent relationships such as, friendship, following.
In transportation graphs are used in route planning, shortest path algorithms in road networks, GPS
systems, and public transit. They are also used in airline routes. Airports are represented as nodes,
flights as edges, enabling efficient scheduling and route optimization. In traffic management graphs are
used.
Summary
A graph is a non-linear data structure consisting of vertices (nodes) and edges (arcs or lines) that
represent relationships between elements. Graphs can be directed, undirected, weighted, or cyclic, and
are used in real-life applications such as social networks, telecommunication systems, Google Maps, and
transportation networks. Graph terminology includes concepts like degree, in-degree, out-degree, loops,
paths, and connectivity. Graphs can be represented in memory using adjacency matrices or adjacency
lists. Fundamental operations include traversal, searching, insertion, deletion, merging, and splitting of
vertices. Two primary traversal algorithms are Breadth First Search (BFS), which explores all adjacent
vertices before moving deeper, and Depth First Search (DFS), which explores as far as possible along a
branch before backtracking. Graphs are essential in computer science, AI, databases, and networking
due to their ability to efficiently model and solve complex problems.
Questions
1. Answer the following
a) Edges
b) Arcs
c) Vertices
d) Loops
Answer: c) Vertices
3. Which of the following is an example of a real-life application of graphs?
a) Pendent vertex
b) Isolated vertex
c) Loop vertex
d) Weighted vertex
Answer: b) Isolated vertex
5. What is the sum of weights of the edges along a path in a graph called?
a) Edge degree
b) Path length
c) Vertex weight
d) Loop length
Answer: b) Path length
8. In which graph traversal method are all adjacent vertices visited before moving deeper?
a) Queue
b) Stack
c) Heap
d) Array
Answer: b) Stack
a) Traversing
b) Searching
c) Sorting
d) Merging of vertices
Answer: c) Sorting
5. The length of a path in a weighted graph is the sum of the edge weights along that path.
True
6. A connected graph has at least one path between every pair of vertices.
True
8. In Depth First Search (DFS), adjacent vertices are visited before going deeper.
False
10. In a weighted graph, edge weights can represent distances, costs, or other measurable values.
True
12. An adjacency list stores a list of adjacent vertices for each vertex.
True
14. Breadth First Search (BFS) explores all adjacent vertices before going deeper.
True
4. Fill in the blanks
4. A graph is represented as G = (V, E), where V is the set of __________ and E is the set of
__________.
6. The sum of the edge weights along a path in a weighted graph is called the __________ of the
path.
9. __________ First Search (BFS) explores all adjacent vertices before going deeper.
10. In Depth First Search (DFS), __________ is used as the primary data structure.
11. In a weighted graph, each edge has an associated numerical value called a __________.
13. The adjacency __________ representation of a graph stores a list of adjacent vertices for each
vertex.
14. Graphs are widely used in applications such as __________ networks, __________ planning, and
social networks.
(Answers: non-linear, vertices, lines or arcs, vertices, edges, isolated, length, connected, matrix,
Breadth, stack, weight, loop, list, computer, route )
A Text Book on Data Structure Using C++
Ch-17 Hashing
Objectives
1 To understand the concept of hash functions, their properties, and importance in computer science.
2 To study the applications of hashing in data structures, cryptography, networking, file systems, and
compilers.
3 To analyze the problem of collisions in hashing and learn different collision resolution techniques.
4 To explore how hashing enhances efficiency, security, and integrity in real-world applications like
databases, blockchain, and load balancing.
A hash function is a mathematical function that takes an input (or "key") and produces a fixed-size string
of bytes. It is typically represented as a sequence of characters. The output, known as the hash value, is
a representation of the input data. It is often used in various computer science applications. Fig 17.1
shows hash function.
1. Deterministic: The same input always produces the same hash value
2. Fast Computation: It should compute the hash value quickly for any input
4. Minimizing Collisions: Different inputs should produce different hash values as much as possible
5. Irreversibility: Given a hash value, it should be computationally infeasible to determine the
original input (for cryptographic hash functions)
Hash Tables are used for fast data retrieval. A hash function maps keys to indices in an array, enabling
quick lookups.
Cryptography
Password Hashing: Passwords are hashed before storing to enhance security. When a user logs in, the
hash of the entered password is compared to the stored hash.
Digital Signatures: Ensures the integrity and authenticity of data by hashing the content.
Data Integrity
Checksums: Hash functions verify data integrity during transmission or storage by checking if the hash
value of the received data matches the expected hash.
Search Engines: Hashing helps index web pages for efficient retrieval.
File Systems
Networking
Load Balancing: Distributing requests evenly across servers using consistent hashing.
Routing Protocols: Hash functions help determine packet paths in network protocols.
Compilers
Hash functions are used for symbol tables to efficiently store and retrieve variable names, function
names, etc.
Open Addressing
In open addressing, all elements are stored within the hash table itself, and collisions are resolved by
probing (searching) for the next available slot.
Separate Chaining
In separate chaining, each slot in the hash table contains a pointer to a data structure (usually a linked
list) that stores all keys hashing to that slot
Coalesced Hashing
Coalesced hashing combines open addressing with separate chaining. Each slot in the hash table has a
pointer to the next slot in case of a collision, forming a linked list within the table itself.
Summary
Hashing is a powerful technique in data structures and computer science that uses a hash
function to map input data (keys) into fixed-size hash values for efficient data retrieval and
storage. A good hash function must be deterministic, fast, uniformly distributed, collision-
minimizing, and irreversible (in cryptographic contexts). Hashing has wide applications such as
hash tables for quick lookups, password hashing and digital signatures in cryptography,
checksums for data integrity, blockchain security, database indexing, file deduplication,
networking load balancing, and symbol tables in compilers. However, collisions—where
different keys map to the same hash value—are unavoidable and must be resolved using
techniques like open addressing, separate chaining, or coalesced hashing. Thus, hashing forms
the foundation of efficient searching, indexing, and security in computer systems.
Questions
1. Answer the following
(i) What is hash function?
A) Deterministic behavior
B) Fast computation
3. In which of the following areas are hash functions NOT commonly used?
B) Sorting algorithms
C) Cryptographic security
D) Database indexing
B) To prevent attackers from deriving the original input from the hash
Answer: B) To prevent attackers from deriving the original input from the hash
A) Password hashing
B) Digital signatures
C) Checksums
D) Load balancing
Answer: C) Checksums
Answer: B) By using a linked list to store multiple keys at the same index
Answer: B) All elements are stored within the hash table itself
8. Which hashing technique combines both open addressing and separate chaining?
A) Double hashing
B) Coalesced hashing
C) Linear probing
D) Direct mapping
2. A good hash function should be deterministic, meaning the same input always results in the
same hash value.
True
False (Hashing is different from encryption; hashing is one-way, while encryption is reversible.)
4. Hash functions are commonly used in data structures such as hash tables for fast data retrieval.
True
5. A well-designed hash function should produce hash values that are evenly distributed to
minimize collisions.
True
6. Digital signatures use hashing to ensure the authenticity and integrity of data.
True
7. In open addressing, hash collisions are handled by using a linked list at each index of the hash
table.
False (Open addressing resolves collisions by searching for the next available slot, not by using
linked lists.)
8. Separate chaining resolves collisions by using a linked list to store multiple keys at the same
index.
True
10. Checksums use hash functions to verify data integrity during transmission or storage.
True
11. Coalesced hashing is a collision resolution technique that combines elements of both open
addressing and separate chaining.
True
True
13. Hashing cannot be used in networking applications such as load balancing or routing.
14. Hash functions ensure that different inputs always produce different hash values without any
chance of collisions.
False (Collisions can occur due to the pigeonhole principle, but a good hash function minimizes
them.)
15. Hashing helps in file deduplication by comparing file contents directly instead of using hash
values.
False (Hashing helps by comparing hash values, not the actual file contents.)
(Hash function)
(Hash value)
(Uniform)
4. In _________, passwords are transformed into hash values before being stored for security
purposes.
(Password hashing)
(Checksums)
6. Hash tables use a _________ to map keys to indices in an array for fast data retrieval.
(Hash function)
7. _________ hashing is a technique that combines open addressing and separate chaining to
resolve collisions.
(Coalesced)
8. In _________, all elements are stored within the hash table itself, and collisions are resolved by
probing for the next available slot.
(Open addressing)
9. _________ ensures that the same input always results in the same hash value.
(Deterministic property)
10. Digital signatures use hashing to ensure the _________ and authenticity of data.
(Integrity)
11. Hash functions play a crucial role in _________ technology to securely link blocks.
(Blockchain)
12. In _________, each slot in the hash table contains a pointer to a linked list storing multiple keys
hashing to the same slot.
(Separate chaining)
13. Hashing is used in _________ engines to index web pages for efficient retrieval.
(Search)
(Irreversibility)
15. In networking, hashing is used for _________, which distributes traffic evenly across multiple
servers.
(Load balancing)