DAA Notes
DAA Notes
com/design-analysis-algorithms-
tutorial.html
https://www.codingninjas.com/studio/library/design-
and-algorithm-analysis
It is far more convenient to have basic metrics for an algorithm's efficiency than to
develop the algorithm and assess its efficiency each time a specific parameter in
the underlying computer system changes
It is hard to foresee an algorithm's exact behavior. There are far too many variables
to consider
Determine the input and output of the algorithm. Do not make the algorithm runs
infinite.
Characteristics of Algorithms
Algorithms must have an endpoint. It should not run for infinity. There must be a
finite amount of time for which the algorithm must run
Definition of input and output should be well defined. You must give sample input
other than 0 and output for better understanding
There must be a defined instruction for solving the problem. The algorithm should
not have an unnecessary number of instructions
You must give clear and concise instructions without making them difficult to
understand
Provides scalability. Divide the problem into smaller steps as it gives a better
understanding of the problem
Use the best technologies to get the most efficient and best solution
To understand the comparison between different algorithms and find the best time
complexity with the best space resource
Factors of Algorithm
It is important to consider some factors when you write an algorithm.
Understandable: It is important that when you write an algorithm, it must be easily
understandable and easy to read and understand
Simplify: The algorithm should have simplicity. You must write an algorithm that is
simple and concise
Short and Crisp: You must consider this factor when writing an algorithm. The
algorithm should be short and must have complete information about the problem
Description: The algorithm should have complete information about the problem
and describe the problem in complete detail
Modular: You should be able to break down the problem into smaller sections. The
algorithm should be specially designed so that it can be easily understood
Precision: Algorithms are expected to be precise and correct. The input should
give the desired output. Algorithms should be correct and work according to the
need
Development of Problem
There are different stages when a problem is documented.
1. Definition and development of a model
Best Case: We find the best case of an algorithm, i.e., the condition when the algorithm
gets executed in the minimum number of operations. We find the lower bound of the
algorithm when the algorithm performs successfully. For example: When we perform a
linear search algorithm in any data structure, if we search for an element and the
element is present in the first position, that case is referred to as the best case.
Worst Case: We find the worst case of an algorithm, i.e., the condition when the
algorithm gets excited in the maximum number of operations. In the worst case, we get
an algorithm's higher bound running time. For example: When we perform a linear
search algorithm in any data structure if we search for an element that is not present in
that data structure, that case is referred to as the worst case.
Average Case: We find the average case of an algorithm, i.e., the condition when the
algorithm gets excited in a few numbers of operations. For example: When we perform
a linear search algorithm in any data structure, if we search for an element and the
element is present in the middle position, that case is referred to as the average case.
Also read - Kadane's Algorithm
Analysis Methods
There are different analysis methods. The most common are given below.
Asymptotic Analysis
In asymptotic analysis, there are three main asymptotic notations.
Big O Notation: This notation represents the worst case. It only calculates the
upper bound of time when the algorithm is implemented
Omega Notation: This notation represents the best case. It only calculates the
lower bound of time when the algorithm is implemented
Theta Notation: It is used for analyzing the average case. It calculates the time
complexity using the upper and lower bounds
Must Read Lower Bound in C++
Types of Algorithms
There are different types of algorithms, and the most commonly used algorithms are
discussed below:
Sorting Algorithms
We perform sorting operations on data to sort the data in ascending or descending
order. It helps in arranging the data in any format. Different problems can be solved
using sorting algorithms, some as bubble sort, merge sort, quick sport, selection sort,
and insertion sort are a few such sorting algorithms.
int main()
{
int [] array={1,5,6,7,8};
int search=6;
boolean flag = false;
for(int i = 0; i < arr.length ; i++)
{
if(array[i] == search)
{
flag=true;
}
}
if(flag == true)
System.out.println("Number found");
else
System.out.println("Number not found");
}
Output
Number found
Recursive Algorithms
Recursive algorithms are the most important algorithm in computer science. In this
algorithm, a function gives a call to itself. It recursively calls its function to solve the
problem. You don't have to worry about the subproblems; only consider a case and
write the algorithm accordingly. While writing this algorithm, you must consider the time
management factor as recursion calls recursive stack.
Let's try to understand this algorithm by an example.
int factorial(int number)
{
if(number<=1){
return 1;
}
else{
return number * factorial(number-1);
}
}
Backtracking Algorithm
The better version of the brute force approach. In this algorithm, we first start with a
solution, and if the solution is successful in solving the problem, we print the same
solution, but in case the first move does not provide the solution, then you backtrack
and try to solve it with another move. This backtracking process is called as
backtracking algorithm. There are many applications of this algorithm. Some of them
are the N - Queens problem, the KnapSack algorithm, generating binary strings, etc.
Learn Introduction To Backtracking
Greedy Algorithm
In this algorithm, you find the solution that is best for the present. You don't worry about
the future and look for another optimal solution. The algorithm works in a top-down
approach and might not be the best solution as it chooses the solution that works locally
and is chosen globally. It has two properties i.e., Greedy choice property and optimal
structure. The are many applications of this algorithm. Huffman coding, K centers
problems, Graph coloring, fractional knapsack problems, minimum spanning trees, etc.
Learn Greedy algorithms
Prims and Kruskal Algorithm
Advantages of Algorithms
There are many advantages of writing algorithms. Some of them are discussed below.
Understanding the problem is easy. The steps and sequence help in better
understanding the problem
The algorithm helps in determining the solution without writing the implementation
The problems are broken down into smaller sub-problems which helps the
programmer easily convert the solution into the code
The programmer can understand the algorithm and find the optimal solution without
writing the actual program and coding it
Disadvantages of Algorithm
Writing an algorithm is time-consuming
Describing big problems is difficult to solve and writing algorithms for that kind of
problem is more difficult
Table of Content
Introduction of Algorithms
Asymptotic Analysis
Worst, Best and Average Case
How to Analyse Loops for Complexity Analysis of Algorithms?
How to combine the time complexities of consecutive loops?
Algorithms Cheat Sheet for Complexity Analysis:
Runtime Analysis of Algorithms:
Little o and Little omega notations
What does ‘Space Complexity’ mean?
Previous Year GATE Questions
Introduction of Algorithms
The word Algorithm means “A set of rules to be followed in calculations or
other problem-solving operations” Or “A procedure for solving a mathematical
problem in a finite number of steps that frequently involves recursive
operations “.
Therefore Algorithm refers to a sequence of finite steps to solve a particular
problem. Algorithms can be simple and complex depending on what you
want to achieve.
Types of Algorithms:
1. Brute Force Algorithm
2. Recursive Algorithm
3. Backtracking Algorithm
4. Searching Algorithm
5. Sorting Algorithm
6. Hashing Algorithm
7. Divide and Conquer Algorithm
8. Greedy Algorithm
9. Dynamic Programming Algorithm
10. Randomized Algorithm
Asymptotic Notations
In mathematics, asymptotic analysis, also known as asymptotics, is a
method of describing the limiting behavior of a function. In
computing, asymptotic analysis of an algorithm refers to defining the
mathematical boundation of its run-time performance based on the input size.
For example, the running time of one operation is computed as f(n), and maybe
for another operation, it is computed as g(n2). This means the first operation
running time will increase linearly with the increase in n and the running time of
the second operation will increase exponentially when n increases. Similarly,
the running time of both operations will be nearly the same if n is small in value.
Usually, the analysis of an algorithm is done based on three cases :
1. Best Case (Omega Notation (Ω))
2. Average Case (Theta Notation (Θ))
3. Worst Case (O Notation(O))
Asymptoti Symbo Definitio
c Notation l n Graph Representation
f(n) =
Ω(g(n)), If
there are
positive
constants
n0 and c
Ω such that,
to the right
of n0 the
f(n) always
lies on or
Omega above
Notation c*g(n).
f(n) =
Θ(g(n)), If
there are
positive
constants
n0 and c
such that,
Θ to the right
of n0 the
f(n) always
lies on or
above
c1*g(n)
Theta and below
Notation c2*g(n).
Asymptoti Symbo Definitio
c Notation l n Graph Representation
f(n) =
O(g(n)), If
there are
positive
constants
n0 and c
O such that,
to the right
of n0 the
f(n) always
lies on or
Big-O below
Notation c*g(n).
Asymptotic Analysis
Given two algorithms for a task, how do we find out which one is better?
One naive way of doing this is – to implement both the algorithms and run the
two programs on your computer for different inputs and see which one takes
less time. There are many problems with this approach for the analysis of
algorithms.
It might be possible that for some inputs, the first algorithm performs better
than the second. And for some inputs second performs better.
It might also be possible that for some inputs, the first algorithm performs
better on one machine, and the second works better on another machine for
some other inputs.
Asymptotic Analysis is the big idea that handles the above issues in analyzing
algorithms. In Asymptotic Analysis, we evaluate the performance of an
algorithm in terms of input size (we don’t measure the actual running time).
We calculate, how the time (or space) taken by an algorithm increases with the
input size.
Time complexity
The most common way to find the time complexity for an algorithm is to deduce
the algorithm into a recurrence relation. Let us look into it further below.
These recurrence relations can be solved using multiple methods; they are −
Substitution Method
Recurrence Tree Method
Iteration Method
Master Theorem
Substitution Method
The substitution method is a trial and error method; where the values that we might
think could be the solution to the relation are substituted and check whether the
equation is valid. If it is valid, the solution is found. Otherwise, another value is
checked.
Procedure
Example
Let us look into an example to solve a recurrence using the substitution method,
T(n) = 2T(n/2) + n
Here, we assume that the time complexity for the equation is O(nlogn). So
according the mathematical induction phenomenon, the time complexity for T(n/2)
will be O(n/2logn/2); substitute the value into the given equation, and we need to
prove that T(n) must be greater than or equal to nlogn.
≤ 2n/2Log(n/2) + n
= nLogn - nLog2 + n
= nLogn - n + n
≤ nLogn
In the recurrence tree method, we draw a recurrence tree until the program cannot
be divided into smaller parts further. Then we calculate the time taken in each level
of the recurrence tree.
Procedure
Example
Consider the binary search algorithm and construct a recursion tree for it −
Since the algorithm follows divide and conquer technique, the recursion tree is
drawn until it reaches the smallest input level T(n2k)T(n2k).
T(n2k)=T(1)T(n2k)=T(1)
n=2kn=2k
logn=log2klogn=log2k
k=log2nk=log2n
Master's Method
3. Master Method:
Master Method is a direct way to get the solution. The master method works
only for the following type of recurrences or for recurrences that can be
transformed into the following type.
Representation of Array
3. Three-Dimensional Array:
A Three Dimensional Array or 3D array in C is a collection of two-
dimensional arrays. It can be visualized as multiple 2D arrays stacked
on top of each other.
Representation of 3D array
1D array
2-D Array
3-D Array
Formula used:
Address of[I][J][K] =B + W (M * N(i-x) + N *(j-y) + (k-z))
Solution:
Address of arr[5][-1][8] = 400 + 2 * {[6 * 6 * (5 – 1)] + 6 * [(-1 + 4)]}
+ [8 – 5]
= 400 + 2 * (6*6*4)+(6*3)+3
= 400 + 2 * (165)
= 730
Column Major Order:
To find the address of the element using column-major order, use the
following formula:1
Address of A[i][j][k]= B + W(M * N(i – x) + M *(k – z) + (j – y))
Here:
B = Base Address (start address)
W = Weight (storage size of one element stored in the array)
M = Row (total number of rows)
N = Column (total number of columns)
P = Width (total number of cells depth-wise)
x = Lower Bound of block (first subscipt)
y = Lower Bound of Row
z = Lower Bound of Column
Example: Given an array arr[1:8, -5:5, -10:5] with a base value
of 400 and the size of each element is 4 Bytes in memory find the
address of element arr[3][3][3] with the help of column-major order ?
Solution:
Given:
Row Subset of an element whose address to be found I = 3
Column Subset of an element whose address to be found J = 3
Block Subset of an element whose address to be found K = 3
Base address B = 400
Storage size of one element store in any array(in Byte) W = 4
Lower Limit of blocks in matrix x = 1
Lower Limit of row/start row index of matrix y = -5
Lower Limit of column/start column index of matrix z = -10
M (row)= Upper Bound – Lower Bound + 1 = 5 +5 + 1 = 11
N (column)= Upper Bound – Lower Bound + 1 = 5 + 10 + 1 = 16
Formula used:
Address of[i][j][k] = B + W(M * N(i – x) + M * (j-y) + (k – z))
Solution:
Address of arr[3][3][3] = 400 + 4 * ((11*16*(3-1)+11*(3-(-5)+(3-(-10)))
= 400 + 4 * ((176*2 + 11*8 + 13)
= 400 + 4 * (453)
= 400 + 1812
= 2212
int main()
int arr[2] = { 1, 2 };
cout << 0 [arr] << ", " << 1 [arr] << endl;
return 0;
(a) 1, 2
(b) Syntax error
(c) Run time error
(d) None
Answer: (a)
Explanation: 0[arr]] is a different way to represent array element,
which represents the first element of the array.
similarly, 1[arr] is a different way to represent array element, which
represents the second element of the array.
Question 3: The minimum number of comparisons required to
determine if an integer appears more than n/2 times in a sorted array
of n integers is
(a) O(n)
(b) O(log(n))
(c) O(nlog(n))
(d) O(1)
Answer: (b)
Explanation: If you answered Theta(1), then think of examples {1, 2,
2, 2, 4, 4}, {1, 1, 2, 2, 2, 2, 3, 3} The Best way to find out whether an
integer appears more than n/2 times in a sorted array(Ascending
Order) of n integers, would be binary search approach.
1. The First occurrence of an element can be found out in O(log(n))
time using divide and conquer technique,lets say it is i.
2. The Last occurrence of an element can be found out in O(log(n))
time using divide and conquer technique,lets say it is j.
3. Now number of occurrence of that element(count) is (j-i+1). Overall
time complexity = log n +log n +1 = O(log(n)).
Question 4: Let A be a square matrix of size n x n. Consider the
following program. What is the expected output?
C = 100
for i = 1 to n do
for j = 1 to n do
{
Temp = A[i][j] + C
A[i][j] = A[j][i]
A[j][i] = Temp - C
}
for i = 1 to n do
for j = 1 to n do
Output(A[i][j]);
Answer: 1
Explanation: If we take look at the inner statements of first loops, we
can notice that the statements swap A[i][j] and A[j][i] for all i and j.
Since the loop runs for all elements, every element A[l][m] would be
swapped twice, once for i = l and j = m and then for i = m and j = l.
Swapping twice means the matrix doesn’t change.
Question 5: An algorithm performs (logN)1/2 find operations, N insert
operations, (logN)1/2 delete operations, and (logN)1/2 decrease-key
operations on a set of data items with keys drawn from a linearly
ordered set. For a delete operation, a pointer is provided to the record
that must be deleted. For the decrease-key operation, a pointer is
provided to the record that has its key decreased. Which one of the
following data structures is the most suited for the algorithm to use, if
the goal is to achieve the best total asymptotic complexity considering
all the operations?
(a) Unsorted array
(b) Min-heap
(c) Sorted array
(d) Sorted doubly linked list
Answer: (a)
Explanation: The time complexity of insert in unsorted array is O(1),
O(Logn) in Min-Heap, O(n) in sorted array and sorted DLL.
For unsorted array, we can always insert an element at end and do
insert in O(1) time
For Min Heap, insertion takes O(Log n) time. Refer Binary Heap
operations for details.
For sorted array, insert takes O(n) time as we may have to move all
elements worst case.
For sorted doubly linked list, insert takes O(n) time to find position
of element to be inserted.
Question 6: Consider an array consisting of –ve and +ve numbers.
What would be the worst case time complexity of an algorithm to
segregate the numbers having same sign altogether i.e all +ve on one
side and then all -ve on the other ?
(a) O(N)
(b) O(Nlog(N))
(c) O(N*N)
(d) O(Nlog(log(N)))
Answer: (c)
Explanation: Here we can use the partition algorithm of quick
sort for segregation and answer will be O(N*N). Choose the first
element as pivot whatever may be its sign we don’t care and keep an
extra index at pivot position.
Question 7: Let A[1…n] be an array of n distinct numbers. If i <
j and A[i] > A[j], then the pair (i, j) is called an inversion of A. What is
the expected number of inversions in any permutation on n elements ?
(a) n(n-1)/2
(b) n(n-1)/4
(c) n(n+1)/4
(d) 2nlog(n)
Answer: (b)
Explanation: There are n(n-1)/2 pairs such that i < j. For a pair (a i,
aj), probability of being inversion is 1/2. Therefore expected value of
inversions = 1/2 * (n(n-1)/2) = n(n-1)/4.
Question 8: Consider the following array declaration in the ‘C’
language:
int array 1[] = {2, 3};
int array2[3]={9};
What will be the output of the following print statement?
printf(“%d, %d”, array1 [1], array2 [2]);
(a) 2, 0
(b) 3, 0
(c) 2, 9
(d) 4, 9
Answer: (b)
Question 9: Consider the following C program.
#include < stdio.h >
int main () {
int a [4] [5] = {{1, 2, 3, 4, 5},
{6, 7, 8, 9, 10},
{11, 12, 13, 14, 15},
{16, 17, 18, 19, 20}};
printf (“%d\n”, *(*(a+**a+2) +3));
return (0);
}
The output of the program is _______.
Answer: 19
Question 10: Which operations can not be done in O(1) for an array of
sorted data.
(a) Print the nth largest element
(b) Print the nth smallest element
(c) Delete element
(d) None of the above
Answer: (c)
Explanation: If we have to delete x and its index is last, it would take
O(n).
Table of Content
What is Linked List?
Singly Linked List
Doubly Linked List
Circular Linked List
Applications of Linked List
Advantages of Linked Lists
Disadvantages of Linked Lists
Previous Year GATE Questions on Linked List:
Linked-List-Data-Structure
Note: Unlike other types of Linked Lists, Circular Doubly Linked List
takes O(1) time for insertion or deletion at the end of the Linked List.
Applications of Linked List:
Image viewer – Previous and next images are linked and can be
accessed by the next and previous buttons.
Previous and next page in a web browser – We can access the
previous and next URL searched in a web browser by pressing the
back and next buttons since they are linked as a linked list.
Music Player – Songs in the music player are linked to the previous
and next songs. So you can play songs either from starting or
ending of the list.
GPS navigation systems– Linked lists can be used to store and
manage a list of locations and routes, allowing users to easily
navigate to their desired destination.
Advantages of Linked Lists:
Dynamic Size: Linked lists can grow or shrink dynamically, as
memory allocation is done at runtime.
Insertion and Deletion: Adding or removing elements from a
linked list is efficient, especially for large lists.
Flexibility: Linked lists can be easily reorganized and modified
without requiring a contiguous block of memory.
Disadvantages of Linked Lists:
Random Access: Unlike arrays, linked lists do not allow direct
access to elements by index. Traversal is required to reach a
specific node.
Extra Memory: Linked lists require additional memory for storing
the pointers, compared to arrays.
Gate Archives on Linked List:
Q1. Consider the problem of reversing a singly linked list. To take an
example, given the linked list below,
fun1(head->next);
printf("%d ", head->data);
}
temp = current->prev;
current->prev = current->next;
current->next = temp;
current = current->prev;
if(temp != NULL )
*head_ref = temp->prev;
struct node
int data;
};
of linked list */
next = current->next;
current->next = prev;
prev = current;
current = next;
if(start == NULL)
return;
fun(start->next->next);
(A) 1 4 6 6 4 1
(B) 1 3 5 1 3 5
(C) 1 2 3 5
(D) 1 3 5 5 2 3 1
Answer: (B)
Explanation: The function prints the data of the current node and
then recursively calls itself with the second next node (i.e., start-
>next->next).
So, it prints the data of every alternate node of the linked list i.e 1 3 5,
and then, since the next->next of 5 is null, it returns and prints the
data of the current node, so it then prints 5 3 1.
Therefore, for the given linked list 1->2->3->4->5->6, the function
would print 1 3 5 5 3 1.
Q9. The following C function takes a simply-linked list as input
argument. It modifies the list by moving the last element to the front of
the list and returns the modified list. Some part of the code is left
blank. Choose the correct alternative to replace the blank line.
C
int value;
} Node;
Node* move_to_front(Node* head)
return head;
q = NULL; p = head;
q = p;
p = p->next;
_______________________________
return head;
class Node {
int value;
Node next;
Node p, q;
int temp;
return;
p = list;
q = list.next;
while (q != null) {
temp = p.value;
p.value = q.value;
q.value = temp;
p = q.next;
(A) 1 4 6 6 4 1
(B) 1 3 5 1 3 5
(C) 1 2 3 5
(D) 1 3 5 5 2 3 1
Answer: (B)
Explanation: The function rearrange() exchanges data of every node
with its next node. It starts exchanging data from the first node itself.
For eg. 3,5,7,9,11
A Queue is defined as a linear data structure that is open at both ends and the
operations are performed in First In First Out (FIFO) order. Queue is a list in
which all additions to the list are made at one end, and all deletions from the list
are made at the other end. The element, which is first pushed into the order,
the operation is first performed on that.
FIFO Property in Queue
Table of Content
Implementing Queues using Arrays:
Implementing Queues using Linked List:
Implementation of Queue using Stack:
Circular Queue:
Priority Queue:
Double Ended Queue:
GATE Archives – Previous Years Questions on Queue:
Implementing Queues using Arrays:
To implement a queue using an array,
Create an array arr of size n and
Take two variables front and rear both of which will be initialized to 0 which
means the queue is currently empty.
Element
rear is the index up to which the elements are stored in the array
and
front is the index of the first element of the array.
Now, some of the implementations of queue operations are as follows:
Enqueue: Addition of an element to the queue. Adding an element will be
performed after checking whether the queue is full or not. If rear < n which
indicates that the array is not full then store the element at arr[rear] and
increment rear by 1 but if rear == n then it is said to be
an Overflow condition as the array is full. Enqueue has O(1) time
complexity.
Dequeue: Removal of an element from the queue. An element can only be
deleted when there is at least an element to delete i.e. rear > 0. Now, the
element at arr[front] can be deleted but all the remaining elements have to
shift to the left by one position in order for the dequeue operation to delete
the second element from the left on another dequeue operation. Dequeue
has O(N) time complexity.
Front: Get the front element from the queue i.e. arr[front] if the queue is not
empty. Accessing the front of the queue has O(1) time complexity.
Display: Print all elements of the queue. If the queue is non-empty, traverse
and print all the elements from the index front to rear. Displaying all the
elements has O(N) time complexity.
Overall Space Complexity: O(N)
Method 1 (By making enQueue operation costly): This method makes sure
that oldest entered element is always at the top of stack 1, so that deQueue
operation just pops from stack1. To put the element at top of stack1, stack2 is
used.
enQueue(q, x):
While stack1 is not empty, push everything from stack1 to stack2.
Push x to stack1 (assuming size of stacks is unlimited).
Push everything back to stack1.
Time complexity will be O(N).
deQueue(q):
If stack1 is empty, then error
Pop an item from stack1 and return it.
Time complexity will be O(1).
Method 2 (By making deQueue operation costly): In this method, in en-
queue operation, the new element is entered at the top of stack1. In de-queue
operation, if stack2 is empty then all the elements are moved to stack2 and
finally top of stack2 is returned.
enQueue(q, x):
Push x to stack1 (assuming size of stacks is unlimited).
Time complexity will be O(1)
deQueue(q):
If both stacks are empty then error.
If stack2 is empty, while stack1 is not empty, push everything from stack1 to
stack2.
Pop the element from stack2 and return it.
Time complexity will be O(N)
Method 2 is definitely better than method 1. Method 1 moves all the elements
twice in enQueue operation, while method 2 (in deQueue operation) moves the
elements once and moves elements only if stack2 empty. So, the amortized
complexity of the dequeue operation becomes Θ(1)
Method 3 (Using one user stack and one function call stack): Method 2
can be modified where recursion (or Function Call Stack) is used to implement
queue using only one user defined stack.
enQueue(x):
Push x to stack1.
Time complexity will be O(1)
deQueue():
If stack1 is empty, then error.
If stack1 has only one element, then return it.
Recursively pop everything from the stack1, store the popped item in
variable res, push the res back to stack1 and return res.
Time Complexity will be O(N).
Circular Queue:
A Circular Queue is an extended version of a normal queue where the last
element of the queue is connected to the first element of the queue forming a
circle. The operations are performed based on FIFO (First In First Out)
principle. It is also called ‘Ring Buffer’.
while (!isEmpty(Q))
push(&S, deQueue(Q));
while (!isEmpty(&S))
enQueue(Q, pop(&S));
Q7. Consider the following pseudo code. Assume that IntQueue is an integer
queue. What does the function fun do?
C
void fun(int n)
q.enqueue(0);
q.enqueue(1);
int a = q.dequeue();
int b = q.dequeue();
q.enqueue(b);
q.enqueue(a + b);
print(a);
}
}
Introduction to Stack:
A stack is a linear data structure in which the insertion of a new element and
removal of an existing element takes place at the same end represented as the
top of the stack.
To implement the stack, it is required to maintain the pointer to the top of the
stack, which is the last element to be inserted because we can access the
elements only on the top of the stack.
Stack
push() O(1)
pop() O(1)
isEmpty() O(1)
Operations Complexity
size() O(1)
Pop Operation:
First Check whether there is any node present in the linked list or not, if not
then return
Otherwise make pointer let say temp to the top node and move forward the
top node by 1 step
Now free this temp node
Peek Operation:
Check if there is any node present or not, if not then return.
Otherwise return the value of top node of the linked list
Display Operation:
Take a temp node and initialize it with top pointer
Now start traversing temp till it encounters NULL
Simultaneously print the value of the temp node
Example:
Input : n = 9
Output : 34
In mathematical terms, the sequence Fn of Fibonacci numbers is defined by
the recurrence relation:
Introduction to Hashing
Hashing refers to the process of generating a fixed-size output from an input of
variable size using the mathematical formulas known as hash functions. This
technique determines an index or location for the storage of an item in a data
structure.
Separate Chaining
The idea is to make each cell of the hash table point to a linked list of records
that have the same hash function value. Chaining is simple but requires
additional memory outside the table.
Example: We have given a hash function and we have to insert some elements
in the hash table using a separate chaining method for collision resolution
technique.
Hash function = key % 5,
Elements = 12, 15, 22, 25 and 37.
Let’s see step by step approach to how to solve the above problem:
Step 1: First draw the empty hash table which will have a possible range of
hash values from 0 to 4 according to the hash function provided.
Step 2: Now insert all the keys in the hash table one by one. The first key to
be inserted is 12 which is mapped to bucket number 2 which is calculated by
using the hash function 12%5=2.
Step 3: Now the next key is 22. It will map to bucket number 2 because
22%5=2. But bucket 2 is already occupied by key 12.
Step 4: The next key is 15. It will map to slot number 0 because 15%5=0.
Step 5: Now the next key is 25. Its bucket number will be 25%5=0. But
bucket 0 is already occupied by key 25. So separate chaining method will
again handle the collision by creating a linked list to bucket 0.
Hence In this way, the separate chaining method is used as the collision
resolution technique.
Open Addressing
In open addressing, all elements are stored in the hash table itself. Each table
entry contains either a record or NIL. When searching for an element, we
examine the table slots one by one until the desired element is found or it is
clear that the element is not in the table.
Linear Probing:
In linear probing, the hash table is searched sequentially that starts from the
original location of the hash. If in case the location that we get is already
occupied, then we check for the next location.
Algorithm:
1. Calculate the hash key. i.e. key = data % size
2. Check, if hashTable[key] is empty
store the value directly by hashTable[key] = data
3. If the hash index already has some value then
check for next index using key = (key+1) % size
4. Check, if the next index is available hashTable[key] then store the value.
Otherwise try for next index.
5. Do the above process till we find the space.
Example: Let us consider a simple hash function as “key mod 5” and a
sequence of keys that are to be inserted are 50, 70, 76, 85, 93.
Step 1: First draw the empty hash table which will have a possible range of
hash values from 0 to 4 according to the hash function provided.
Step 2: Now insert all the keys in the hash table one by one. The first key is
50. It will map to slot number 0 because 50%5=0. So insert it into slot
number 0.
Step 3: The next key is 70. It will map to slot number 0 because 70%5=0 but
50 is already at slot number 0 so, search for the next empty slot and insert it.
Step 4: The next key is 76. It will map to slot number 1 because 76%5=1 but
70 is already at slot number 1 so, search for the next empty slot and insert it.
Step 5: The next key is 93 It will map to slot number 3 because 93%5=3, So
insert it into slot number 3.
Quadratic Probing:
Quadratic probing is an open addressing scheme in computer programming for
resolving hash collisions in hash tables. Quadratic probing operates by taking
the original hash index and adding successive values of an arbitrary quadratic
polynomial until an open slot is found.
An example sequence using quadratic probing is:
H + 12, H + 22, H + 32, H + 42…………………. H + k2
This method is also known as the mid-square method because in this method
we look for i2‘th probe (slot) in i’th iteration and the value of i = 0, 1, . . . n – 1.
We always start from the original hash location. If only the location is occupied
then we check the other slots.
Let hash(x) be the slot index computed using the hash function and n be the
size of the hash table.
If the slot hash(x) % n is full, then we try (hash(x) + 1 2) % n.
If (hash(x) + 12) % n is also full, then we try (hash(x) + 2 2) % n.
If (hash(x) + 22) % n is also full, then we try (hash(x) + 3 2) % n.
This process will be repeated for all the values of i until an empty slot is found
Example: Let us consider table Size = 7, hash function as Hash(x) = x % 7 and
collision resolution strategy to be f(i) = i 2 . Insert = 22, 30, and 50
Step 1: Create a table of size 7.
where
i is a non-negative integer that indicates a collision number,
k = element/key which is being hashed
n = hash table size.
Complexity of the Double hashing algorithm:
Time complexity: O(n)
Example: Insert the keys 27, 43, 692, 72 into the Hash Table of size 7. where
first hash-function is h1(k) = k mod 7 and second hash-function is h2(k) = 1 +
(k mod 5)
Step 1: Insert 27
27 % 7 = 6, location 6 is empty so insert 27 into 6 slot.
Step 2: Insert 43
43 % 7 = 1, location 1 is empty so insert 43 into 1 slot.
Step 4: Insert 72
72 % 7 = 2, but location 2 is already being occupied and this is a
collision.
So we need to resolve this collision using double hashing.
hnew = [h1(72) + i * (h2(72)] % 7
= [2 + 1 * (1 + 72 % 5)] % 7
= 5 % 7
= 5,
What is Rehashing?
As the name suggests, rehashing means hashing again. Basically, when the
load factor increases to more than its predefined value (the default value of the
load factor is 0.75), the complexity increases. So to overcome this, the size of
the array is increased (doubled) and all the values are hashed again and stored
in the new double-sized array to maintain a low load factor and low complexity.
Introduction to Tree:
Tree Data Structure is a hierarchical data structure in which a collection of
elements known as nodes are connected to each other via edges such that
there exists exactly one path between any two nodes.
Basic Terminologies In Tree Data Structure:
Parent Node: The node which is a predecessor of a node is called the
parent node of that node. {B} is the parent node of {D, E}.
Child Node: The node that is the immediate successor of a node is called
the child node of that node. Examples: {D, E} are the child nodes of {B}.
Root Node: The topmost node of a tree or the node that does not have any
parent node is called the root node. {A} is the root node of the tree. A non-
empty tree must contain exactly one root node and exactly one path from the
root to all other nodes of the tree.
Leaf Node or External Node: The nodes which do not have any child nodes
are called leaf nodes. {K, L, M, N, O, P, G} are the leaf nodes of the tree.
Ancestor of a Node: Any predecessor nodes on the path of the root to that
node are called Ancestors of that node. {A,B} are the ancestor nodes of the
node {E}
Descendant: Any successor node on the path from the leaf node to that
node. {E,I} are the descendants of the node {B}.
Sibling: Children of the same parent node are called siblings. {D,E} are
called siblings.
Level of a node: The count of edges on the path from the root node to that
node. The root node has level 0.
Internal node: A node with at least one child is called Internal Node.
Neighbour of a Node: Parent or child nodes of that node are called
neighbors of that node.
Subtree: Any node of the tree along with its descendant.
Tree Traversal Techniques:
1. Inorder Traversal:
Algorithm Inorder(tree)
Traverse the left subtree, i.e., call Inorder(left->subtree)
Visit the root.
Traverse the right subtree, i.e., call Inorder(right->subtree)
In the case of binary search trees (BST), Inorder traversal gives nodes in non-
decreasing order. To get nodes of BST in non-increasing order, a variation of
Inorder traversal where Inorder traversal is reversed can be used.
2. Preorder Traversal:
Algorithm Preorder(tree)
Visit the root.
Traverse the left subtree, i.e., call Preorder(left->subtree)
Traverse the right subtree, i.e., call Preorder(right->subtree)
Preorder traversal is used to create a copy of the tree. Preorder traversal is also
used to get prefix expressions on an expression tree.
3. Postorder Traversal:
Algorithm Postorder(tree)
Traverse the left subtree, i.e., call Postorder(left->subtree)
Traverse the right subtree, i.e., call Postorder(right->subtree)
Visit the root
Postorder traversal is used to delete the tree. Postorder traversal is also useful
to get the postfix expression of an expression tree
Types of Tree data structures :
Below are types of Tree data structure:
1. Binary Tree
2. Ternary Tree
3. N-ary Tree or Generic Tree
4. Binary Search Tree
5. AVL Tree
6. B-Tree
1. Binary Tree:
In a binary tree, each node can have a maximum of two children linked to it.
Some common types of binary trees include full binary trees, complete binary
trees, balanced binary trees, and degenerate binary trees.
Below are list of different Binary trees:
Full Binary Tree: A Binary Tree is a full binary tree if every node has 0 or 2
children. The following are examples of a full binary tree. We can also say a
full binary tree is a binary tree in which all nodes except leaf nodes have two
children. A full Binary tree is a special type of binary tree in which every
parent node/internal node has either two or no children. It is also known as a
proper binary tree.
Degenerate (or pathological) tree: A Tree where every internal node has
one child. Such trees are performance-wise same as linked list. A
degenerate or pathological tree is a tree having a single child either left or
right.
Skewed Binary Tree : A skewed binary tree is a pathological/degenerate
tree in which the tree is either dominated by the left nodes or the right nodes.
Thus, there are two types of skewed binary tree: left-skewed binary tree and
right-skewed binary tree.
Complete Binary Tree: A Binary Tree is a Complete Binary Tree if all the
levels are completely filled except possibly the last level and the last level
has all keys as left as possible.
Perfect Binary Tree A Binary tree is a Perfect Binary Tree in which all the
internal nodes have two children and all leaf nodes are at the same level.
Balanced Binary Tree A binary tree is balanced if the height of the tree is
O(Log n) where n is the number of nodes. For Example, the AVL tree
maintains O(Log n) height by making sure that the difference between the
heights of the left and right subtrees is at most 1.
2. Ternary Tree:
A Ternary Tree is a tree data structure in which each node has at most three
child nodes, usually distinguished as “left”, “mid” and “right”.
3. N-ary Tree or Generic Tree :
Generic trees are a collection of nodes where each node is a data structure that
consists of records and a list of references to its children(duplicate references
are not allowed). Unlike the linked list, each node stores the address of multiple
node.
4. Binary Search Tree:
Binary Search Tree is a node-based binary tree data structure which has the
following properties:
The left subtree of a node contains only nodes with keys lesser than the
node’s key.
The right subtree of a node contains only nodes with keys greater than the
node’s key.
The left and right subtree each must also be a binary search tree.
Operations in an BST:
1. Insertion in BST:
2. Searching in BST:
3. Deletion in BST:
4.1 Insertion in BST:
A new key is always inserted at the leaf by maintaining the property of the
binary search tree. We start searching for a key from the root until we hit a leaf
node. Once a leaf node is found, the new node is added as a child of the leaf
node. The below steps are followed while we try to insert a node into a binary
search tree:
Check the value to be inserted (say X) with the value of the current node
(say val) we are in:
If X is less than val move to the left subtree.
Otherwise, move to the right subtree.
Once the leaf node is reached, insert X to its right or left based on the
relation between X and the leaf node’s value.
Time Complexity: O(h) where h is the height of the Binary Search Tree. In the
worst case, we may have to travel from the root to the deepest leaf node. The
height of a skewed tree may become n and the time complexity of insertion
operation may become O(n).
Auxiliary Space: O(1), if we use a iterative approach, and (n), as we use
recursive approach.
4.2 Searching in BST:
For searching a value in BST, consider it as a sorted array. Now we can easily
perform search operation in BST using Binary Search Algorithm . Let’s say we
want to search for the number X, We start at the root. Then:
We compare the value to be searched with the value of the root.
If it’s equal we are done with the search if it’s smaller we know that
we need to go to the left subtree because in a binary search tree all
the elements in the left subtree are smaller and all the elements in
the right subtree are larger.
Repeat the above step till no more traversal is possible
If at any iteration, key is found, return True. Else False.
Time Complexity: O(h), where h is the height of the BST.
Auxiliary Space:The auxiliary space complexity of searching in a binary search
tree is O(1) if we use a iterative approach, and (n), as we use recursive
approach.
4.3 Deletion in BST:
The task to delete a node in this BST, can be broken down into 3 scenarios:
Case 1. Delete a Leaf Node in BST
If the node to be deleted is a leaf node, it can simply be removed from the tree.
The parent node of the deleted node must have its corresponding child pointer
set to NULL to reflect the change in the tree.
Case 2. Delete a Node with Single Child in BST
If the node to be deleted has only one child, the child can be promoted to
replace the deleted node. The parent node of the deleted node must have its
corresponding child pointer updated to point to the promoted child.
Case 3. Delete a Node with Both Children in BST
If the node to be deleted has two children, the replacement node can be found
by either selecting the minimum value from the right subtree or the maximum
value from the left subtree of the node to be deleted. After finding the
replacement node, it can be promoted to replace the deleted node. The left
subtree of the replacement node (if it exists) must be attached to the left child of
the promoted node, and the right subtree of the replacement node (if it exists)
must be attached to the right child of the promoted node. The parent node of
the deleted node must have its corresponding child pointer updated to point to
the promoted node.
Time Complexity: O(h), where h is the height of the BST.
Auxiliary Space: O(n).
6. AVL Tree
An AVL tree defined as a self-balancing Binary Search Tree (BST) where the
difference between heights of left and right subtrees for any node cannot be
more than one.
The difference between the heights of the left subtree and the right subtree for
any node is known as the balance factor of the node.
Rotating the subtrees in an AVL Tree:
An AVL tree may rotate in one of the following four ways to keep itself
balanced:
Left Rotation:
When a node is added into the right subtree of the right subtree, if the tree gets
out of balance, we do a single left rotation.
Right Rotation:
If a node is added to the left subtree of the left subtree, the AVL tree may get
out of balance, we do a single right rotation.
Left-Right Rotation:
A left-right rotation is a combination in which first left rotation takes place after
that right rotation executes.
Right-Left Rotation:
A right-left rotation is a combination in which first right rotation takes place after
that left rotation executes.
Operations in an AVL Tree:
Insertion
Deletion
Searching
Previously Asked GATE Questions on Trees:
Question 1: Let LASTPOST, LASTIN and LASTPRE denote the last vertex
visited in a postorder, inorder and preorder traversal. Respectively, of a
complete binary tree. Which of the following is always true? (GATE CS 2000)
(a) LASTIN = LASTPOST
(b) LASTIN = LASTPRE
(c) LASTPRE = LASTPOST
(d) None of the above
Answer: (d)
Explanation: It is given that the given tree is complete binary tree . For a
complete binary tree, the last visited node will always be same for inorder and
preorder traversal. None of the above is true even for a complete binary tree.
The option (a) is incorrect because the last node visited in Inorder traversal is
right child and last node visited in Postorder traversal is root.
The option (c) is incorrect because the last node visited in Preorder traversal is
right child and last node visited in Postorder traversal is root.
For option (b), see the following counter example.
1
/ \
2 3
/ \ /
4 5 6
Inorder traversal is 4 2 5 1 6 3
Preorder traversal is 1 2 4 5 3 6
Question 2: The most appropriate matching for the following pairs is (GATE CS
2000): :
X: depth first search 1: heap
Y: breadth-first search 2: queue
Z: sorting 3: stack
(a) X—1 Y—2 Z-3
(b) X—3 Y—1 Z-2
(c) X—3 Y—2 Z-1
(d) X—2 Y—3 Z-1
Answer: (c)
Explanation: Stack is used for Depth first Search
Queue is used for Breadth First Search
Heap is used for sorting
Question 3: Consider the following nested representation of binary trees: (X Y
Z) indicates Y and Z are the left and right sub stress, respectively, of node X.
Note that Y and Z may be NULL, or further nested. Which of the following
represents a valid binary tree?
(a) (1 2 (4 5 6 7))
(b) (1 (2 3 4) 5 6) 7)
(c) (1 (2 3 4)(5 6 7))
(d) (1 (2 3 NULL) (4 5))
Answer: (c)
Question 4: Consider the label sequences obtained by the following pairs of
traversals on a labeled binary tree. Which of these pairs identify a tree uniquely
(GATE CS 2004)?
i) preorder and postorder
ii) inorder and postorder
iii) preorder and inorder
iv) level order and postorder
a) (i) only
b) (ii), (iii)
c) (iii) only
d) (iv) only
Answer: (b)
Question 5: The following numbers are inserted into an empty binary search
tree in the given order: 10, 1, 3, 5, 15, 12, 16. What is the height of the binary
search tree (the height is the maximum distance of a leaf node from the root)?
(GATE CS 2004)
a) 2
b) 3
c) 4
d) 6
Answer: (b)
Explanation: Constructed binary search tree will be..
10
/\
1 15
\/\
3 12 16
\
5
Question 6: A data structure is required for storing a set of integers such that
each of the following operations can be done in (log n) time, where n is the
number of elements in the set.
o Deletion of the smallest element
o Insertion of an element if it is not already present in the set
Which of the following data structures can be used for this purpose?
(a) A heap can be used but not a balanced binary search tree
(b) A balanced binary search tree can be used but not a heap
(c) Both balanced binary search tree and heap can be used
(d) Neither balanced binary search tree nor heap can be used
Answer: (b)
Explanation: A self-balancing balancing binary search tree containing n items
allows the lookup, insertion, and removal of an item in O(log n) worst-case time.
Since it’s a self-balancing BST, we can easily find out minimum element in
O(logn) time which is always the leftmost element (See Find the node with the
minimum value in a Binary Search Tree ).
Since Heap is a balanced binary tree (or almost complete binary tree), insertion
complexity for heap is O(logn). Also, complexity to get minimum in a min heap
is O(logn) because removal of root node causes a call to heapify (after
removing the first element from the array) to maintain the heap tree property.
But a heap cannot be used for the above purpose as the question says – insert
an element if it is not already present. For a heap, we cannot find out in O(logn)
if an element is present or not. Thanks to the game for providing the correct
solution.
Question 7: The height of a binary tree is the maximum number of edges in
any root to leaf path. The maximum number of nodes in a binary tree of height h
is:
(a) 2^h -1
(b) 2^(h-1) – 1
(c) 2^(h+1) -1
(d) 2*(h+1)
Answer: (c)
Explanation: Maximum number of nodes will be there for a complete tree.
Number of nodes in a complete tree of height h = 1 + 2 + 2^2 + 2*3 + …. 2^h =
2^(h+1) – 1
Question 8: The inorder and preorder traversal of a binary tree are d b e a f c g
and a b d e c f g, respectively. The postorder traversal of the binary tree is:
(a) d e b f g c a
(b) e d b g f c a
(c) e d b f g c a
(d) d e f g b c a
Answer: (a)
Below is the given tree.
a
/\
/\
bc
/\/\
/\/\
defg
Question 9: A complete n-ary tree is a tree in which each node has n children
or no children. Let I be the number of internal nodes and L be the number of
leaves in a complete n-ary tree. If L = 41, and I = 10, what is the value of n?
(a) 3
(b) 4
(c) 5
(d) 6
Answer: (c)
For an n-ary tree where each node has n children or no children, following
relation holds
L = (n-1)*I + 1
Where L is the number of leaf nodes and I is the number of internal nodes.
Let us find out the value of n for the given data.
L = 41 , I = 10
41 = 10*(n-1) + 1
(n-1) = 4
n=5
Question 10: What is the number of binary search trees with 20 nodes with
elements 1, 2, 3,…..20 such that the root of tree is 12 and the root of left
subtree is 7?
(a) 2634240
(b) 1243561
(c) 350016
(d) 2642640
Answer: (d)
Explanation:
Number of nodes in left subtree = 11 {1, 2, 3, 4….11}
Number of nodes in the right subtree = 8 {13, 14, ….20}
Since for the left subtree root is 7
Number of elements in the left part of left subtree = 6 {1, 2, 3..6}
Number of elements in the right part of left subtree = 4 {8, 9, 10, 11}
We know number of Binary Search trees with n nodes = (C(2n,n)/n+1)
Number of BST with 6 nodes = (C(12,6)/7) = 132
Number of BST with 4 nodes = (C(8,4)/5) = 14
Number of BST with 8 nodes = (C(16,8)/9) =1430
Total number of BST = 2642640
What is Graph?
A Graph is a non-linear data structure consisting of vertices and edges. The
vertices are sometimes also referred to as nodes and the edges are lines or
arcs that connect any two nodes in the graph. More formally a Graph is
composed of a set of vertices( V ) and a set of edges( E ). The graph is denoted
by G(V, E).
Components of a Graph
Vertices: Vertices are the fundamental units of the graph. Sometimes,
vertices are also known as vertex or nodes. Every node/vertex can be
labeled or unlabelled.
Edges: Edges are drawn or used to connect two nodes of the graph. It can
be ordered pair of nodes in a directed graph. Edges can connect any two
nodes in any possible way. There are no rules. Sometimes, edges are also
known as arcs. Every edge can be labelled/unlabelled.
Breadth First Search or BFS in Graph
The Breadth First Search (BFS) algorithm is used to search a graph data
structure for a node that meets a set of criteria. It starts at the root of the graph
and visits all nodes at the current depth level before moving on to the nodes at
the next depth level.
BFS
Time complexity: O(V + E), where V is the number of vertices and E is the
number of edges in the graph.
Auxiliary Space: O(V + E), since an extra visited array of size V is required,
And stack size for iterative call to DFS function.
Types of Graphs
1. Null Graph
A graph is known as a null graph if there are no edges in the graph.
2. Trivial Graph
Graph having only a single vertex, it is also the smallest graph possible.
3. Undirected Graph
A graph in which edges do not have any direction. That is the nodes are
unordered pairs in the definition of every edge.
4. Directed Graph
A graph in which edge has direction. That is the nodes are ordered pairs in the
definition of every edge.
5. Connected Graph
The graph in which from one node we can visit any other node in the graph is
known as a connected graph.
6. Disconnected Graph
The graph in which at least one node is not reachable from a node is known as
a disconnected graph.
7. Regular Graph
The graph in which the degree of every vertex is equal to K is called K regular
graph.
8. Complete Graph
The graph in which from each node there is an edge to each other node.
9. Cycle Graph
The graph in which the graph is a cycle in itself, the degree of each vertex is 2.
10. Cyclic Graph
A graph containing at least one cycle is known as a Cyclic graph.
11. Directed Acyclic Graph
A Directed Graph that does not contain any cycle.
12. Bipartite Graph
A graph in which vertex can be divided into two sets such that vertex in each
set does not contain any edge between them.
13. Weighted Graph
A graph in which the edges are already specified with suitable weight is
known as a weighted graph.
Weighted graphs can be further classified as directed weighted graphs and
undirected weighted graphs.
Representations of Graph
Here are the two most common ways to represent a graph :
1. Adjacency Matrix
2. Adjacency List
Adjacency Matrix
An adjacency matrix is a way of representing a graph as a matrix of boolean
(0’s and 1’s).
Let’s assume there are n vertices in the graph So, create a 2D matrix adjMat[n]
[n] having dimension n x n.
If there is an edge from vertex i to j, mark adjMat[i][j] as 1.
If there is no edge from vertex i to j, mark adjMat[i][j] as 0.
Representation of Directed Graph to Adjacency Matrix:
The below figure shows a directed graph. Initially, the entire Matrix is initialized
to 0. If there is an edge from source to destination, we insert 1 for that
particular adjMat[destination].
Directed Graph to Adjacency Matrix
Adjacency List
An array of Lists is used to store edges between two vertices. The size of array
is equal to the number of vertices (i.e, n). Each index in this array represents a
specific vertex in the graph. The entry at the index i of the array contains a
linked list containing the vertices that are adjacent to vertex i.
Let’s assume there are n vertices in the graph So, create an array of list of
size n as adjList[n].
adjList[0] will have all the nodes which are connected (neighbour) to
vertex 0.
adjList[1] will have all the nodes which are connected (neighbour) to
vertex 1 and so on.
Representation of Directed Graph to Adjacency list:
The below directed graph has 3 vertices. So, an array of list will be created of
size 3, where each indices represent the vertices. Now, vertex 0 has no
neighbours. For vertex 1, it has two neighbour (i.e, 0 and 2) So, insert vertices 0
and 2 at indices 1 of array. Similarly, for vertex 2, insert its neighbours in array
of list.
Directed Graph to Adjacency list
(A)
1) Stack
2) Queue
3) Priority Queue
4) Union Find
(B)
1) Queue
2) Stack
3) Priority Queue
4) Union Find
(C)
1) Stack
2) Queue
3) Union Find
4) Priority Queue
(D)
1) Priority Queue
2) Queue
3) Stack
4) Union Find
Solution: (B)
Explanation: 1) Queue is used in Breadth-First Search
2) Stack is used in depth-first search-dfs
3) Priority Queue is used in Prim’s Minimum Spanning Tree .
4) Union Find is used in Kruskal’s Minimum Spanning Tree .
4. Let G be a weighted graph with edge weights greater than one and G’
be the graph constructed by squaring the weights of edges in G. LetT and
T’ be the minimum spanning trees of G and G’ respectively, with total
weights t and t’. Which of the following statements is TRUE? [GATE CSE
2020 ]
(A) T’ = T with total weight t’ = t^2
(B) T’ = T with total weight t’ < t^2
(C) T’ =t- T but total weight t’ = t^2
(D) None of these
Solution: (D)
5. The Breadth-First Search algorithm has been implemented with the help of a
queue. What is a possible order of visiting the nodes of the following graph is
(A) NQMPOR
(B) QMNPOR
(C) QMNPRO
(D) MNOPQR
Solution: (C)
Explanation: Option (A) is NQMPOR. It cannot be BFS because P is visited
before O here.
Option (D) is MNOPQR. It cannot be a BFS because the traversal begins with
M, but O has been visited before N and Q.
In BFS, every adjacent must be called before adjacent of adjacent.
(B) and (C) correspond to QMNP. Before N and P, M had been added to the
queue (because M comes before NP in QMNP). R is placed in the line before N
and P’s neighbors because it is M’s neighbor (which is O). As a result, R is
visited first, followed by O.
6. Let G be an undirected graph. Consider a depth-first traversal of G,
where T is the depth-first search tree that results. Let u be the first new
(unvisited) vertex visited after u in the traversal, and v be its first new
(unvisited) vertex visited after u. Which of the assertions below is always
true? [GATE CSE 2014 ]
(A) In G, u,v must be an edge, while in T, u is a descendent of v.
(B) In G, u,v must be an edge, while in T, v is a descendent of u.
(C) If u,v in G is not an edge, then u in T is a leaf
(D) If u,v in G is not an edge, then u and v in T must have the same parent.
Solution: (C)
Explanation:
In DFS, if ‘v’ is visited
after ‘u,’ one of the following is true.
1) (u, v) is an edge.
u
/\
vw
//\
xyz
2) A leaf node is ‘u.’
w
/\
xv
//\
uyz
In DFS, after we have visited a node, we first go back to all children who were
not visited. If no children are left unvisited(u is a leaf), then control goes back to
the parent, and the parent then visits the subsequent unvisited children.
7. Which of the two traversals (BFS and DFS) may be used to find if there
is a path from s to t given two vertices in a graph s and t? [GATE CSE
2014 Set 2]
(A) Only BFS
(B) Only DFS
(C) Both BFS and DFS
(D) Neither BFS nor DFS
Solution: (C)
Explanation: Both traversals can be used to see if there is a path from s to t.
8. The statement written below is true or false? [GATE CSE 2021]
If a directed graph’s DFS contains a back edge, any other directed graph’s DFS
will also have at least a single back edge.
(A) True
(B) False
Solution: (A)
Explanation: A cycle in the graph is called its back edge. So if we get a cycle,
all DFS traversals would contain at least one back edge.
9. Which of the condition written below is sufficient to detect a cycle in a
directed graph? [GATE CSE 2008]
(A) There is an edge from a currently visited node to an already seen node.
(B) There is an edge from the currently visited node to an ancestor of the
currently visited node in the forest of DFS.
(C) Every node is seen two times in DFS.
(D) None of the above
Solution: (B)
Explanation: If there is an edge from the currently visited node to an ancestor
of the currently visited node in the forest of DFS, it means a cycle is formed. As
this is an apparent condition about cycle formation, so this condition is
sufficient.
10. If the finishing time f[u] > f[v] of DFS for two vertices u and v in a
graph G which is directed, and u and v are in the DFS tree same as each
other in the DFS forest, then u is an ancestor of v in the depth-first
tree. [GATE CSE 2014 Set 2]
(A) True
(B) False
Solution: (B)
Explanation: In a graph that contains three nodes, r u and v, with edges (r; u)
and (r; v), and r is the starting point for the DFS, u and v are siblings in the DFS
tree; neither as the ancestor of the other.
11. Is the statement written below true or false? [GATE CSE 2015]
A DFS of a directed graph generally produces the exact number of edges of a
tree, i.e., not dependent on the order in which vertices are considered for DFS.
(A) True
(B) False
Solution: (B)
Explanation: Consider the following graph. If we start from ‘a’, then there is
one tree edge. If we start from ‘b,’ there is no tree edge.
a—->b