FDS SOLVED QB Naaz
FDS SOLVED QB Naaz
Q1. What is Row Major and Column Major Representation? Explain with an example. Write
the formula to find any element A[i][j] in row major and column major representations of A.
Q4. Explain with example how single variable polynomial can be represented using 1-D
array? What are advantage and disadvantage of this representation?
Representation using arrays:
Polynomial is the sum of terms where each term consists of variable, coefficient and exponent. For
representing a single variable polynomial one can make use of one-dimensional array. In single
dimensional array the index of an array will act as the exponent and the coefficient can be stored at that
particular index which can be represented as follows:
For example, 3x4 + 5x3 + 7x2 + 10x – 19
This polynomial can be stored in single dimensional array.
Advantages and Disadvantages of Representing Single Variable Polynomial Using 1D Array
Advantages Disadvantages
Easy to implement and manage due to its Wastes space for coefficients with zero values.
simplicity
Accessing coefficients using index is efficient Limited to polynomials of fixed degree
Useful for storing dense polynomials Insertion or deletion of terms is not flexible
Q5. Write an algorithm to add two sorted polynomials in single variable. Analyze its time
complexity?
Algorithm:
Step1:
Initialize three pointers: i for P1[ ], j for P2[ ], and k for the Result[ ] array.
Step2:
Compare the exponents of the current terms from P1[ ] and P2[ ]:
If the exponent in P1[ ] is greater, add the term to Result[ ] and increment i.
If the exponent in P2[ ] is greater, add the term to Result[ ] and increment j.
If the exponents are equal, add the coefficients. If the sum is not zero, add the resulting term to
Result[ ], and increment both i and j.
Step3:
Append any remaining terms from P1[ ] or P2[ ] to Result[ ].
Step4:
Return Result[ ].
Step 1: Start.
Step 2: Input the two polynomials P1[] and P2[], each containing pairs
of coefficients and exponents.
Step 3: Initialize an empty array result[] to store the result of the
multiplication.
Step 4: For each term in P1[] (with index i):
Step 4.1: For each term in P2[] (with index j):
Step 4.1.1: Multiply the coefficients:
coeff = P1[i].coefficient * P2[j].coefficient.
Step 4.1.2: Add the exponents:
expo = P1[i].exponent + P2[j].exponent.
Step 4.1.3: Check if a term with the same exponent already
exists in result[]:
If yes, add the new coefficient to the existing term.
If no, add a new term {coeff, expo} to result[].
Step 5: Combine like terms (if necessary).
Step 6: Output the result array result[].
Step 7: Stop.
Time Complexity:
The outer loop iterates over all terms in the first polynomial P1[], and the inner loop
iterates over all terms in the second polynomial P2[].
Time Complexity: O(n × m), where:
n is the number of terms in P1[],
m is the number of terms in P2[].
Q7. What is meant by sparse Matrix? Write an algorithm to perform addition of two sparse
matrices. And analyze its time complexity
A sparse matrix is a matrix that has a majority of its elements as zeroes. In other words, only a few
elements in the matrix are non-zero, and the rest are zero.
For example, if the matrix is of size 100 x 100 and only 10 elements are non-zero. Then for accessing
these 10 elements one has to make 10000 times scan. Also, only 10 spaces will be with non-zero
elements. The remaining spaces of matrix will be filled with zeros only. i.e. we have to allocate the
memory of 100 x 100 x 2 = 20000
Q8. Write an algorithm for multiplication of sparse matrix. comment on time and space
complexity for both.
Steps:
Step1: Validate Dimensions:
Ensure that the number of columns in matrix A equals the number of rows in matrix B. If not,
return an error.
Time Complexity:
Transpose 𝐵: 𝑂(𝑙)
Matrix Multiplication: 𝑂(𝑘⋅𝑙), where 𝑘 and 𝑙 are the non-zero elements in 𝐴 and 𝐵
Result Combination: 𝑂(𝑘.𝑙) in the worst case.
Overall Time Complexity: 𝑂(𝑘⋅𝑙)
Space Complexity:
Transpose of 𝐵: 𝑂(𝑙)
Intermediate Results: 𝑂(𝑘 ⋅𝑙)
Overall Space Complexity: 𝑂(𝑘⋅𝑙)
Q9. What is the difference between simple and fast transpose of sparse matrix? Write an
algorithm to find simple transpose of sparse matrix.
Example:
Unit 3
Q3 Explain in brief the different searching techniques. What is the time complexity of each of them?
1. Linear search:
Linear search is a method for searching for an element in a collection of elements. In linear search, each
element of the collection is visited one by one in a sequential fashion to find the desired element.
Time Complexity:
Best Case: 𝑂(1)
(if the target is at the first position).
Worst Case: 𝑂(𝑛)
(if the target is not found or at the last position).
2. Sentinel Search:
A variant of Linear Search where a "sentinel" (extra element) is added to the end of the array to
eliminate boundary checks during the search.
Time Complexity:
Best Case: 𝑂(1)
Worst Case: 𝑂(𝑛)
3. Binary search:
Binary search is an algorithm for sorted data, uses divide-and-conquer strategy for sorting. It compares
the middle element with the target: if they match, the index is returned; if the target is smaller, it
searches the left subarray; otherwise, the right. This continues until the target is found or the array size
becomes zero.
Time Complexity:
Best Case: 𝑂(1)
Worst Case: 𝑂(log𝑛)
4. Fibonacci Search:
Uses Fibonacci numbers to divide the array into sections for searching, similar to Binary Search but
with different partitioning logic.
Time Complexity:
Best Case: 𝑂(1)
Worst Case: 𝑂(log𝑛)
Sentinel search:
Sentinel Search is a variation of the linear search algorithm that slightly optimizes
performance by reducing the number of comparisons in the search loop. It does this by placing
a special "sentinel" element at the end of the array, which guarantees that the search will always
terminate without needing to check for the end of the list inside the loop.
Working of Sentinel Search:
A sentinel is placed at the end of the list, which is usually the element you're searching
for.
The algorithm searches for the target by moving sequentially through the list.
Because of the sentinel, the search loop doesn't need to check if the end of the list is
reached—it will always find the sentinel, allowing it to stop without extra checks.
After finding the sentinel, the algorithm checks if the actual target was found in the
original list (and not just the sentinel).
Q1. What is linked list? Write a pseudo-C++ code to sort the elements.
A linked list is a linear data structure which can store a collection of "nodes" connected together via
links i.e. pointers. Linked lists nodes are not stored at a contiguous location, rather they are linked using
pointers to the different memory locations. A node consists of the data value and a pointer to the address
of the next node within the linked list.
A linked list is a dynamic linear data structure whose memory size can be allocated or de-allocated at run
time based on the operation insertion or deletion, this helps in using system memory efficiently. Linked
lists can be used to implement various data structures like a stack, queue, graph, hash maps, etc.
FUNCTION SortLinkedList(head)
IF head IS NULL
RETURN // List is empty
DO
swapped = FALSE
current = head
current = [Link]
Q2. What is doubly linked list? Explain the process of deletion of an element fromdoubly linked
list with example.
A doubly linked list is a data structure that consists of a set of nodes, each of which contains a value
and two pointers, one pointing to the previous node in the list and one pointing to the next node in the
list. This allows for efficient traversal of the list in both directions, making it suitable for applications
where frequent insertions and deletions are required.
Example:
Initial list:
1 2 3 4
1 2 4
Q3. Write a pseudo code to insert new node in to singly link list
1. Pseudo code to insert at beginning:
FUNCTION InsertAtBeginning(head, value)
CREATE newNode
[Link] = value
[Link] = head
head = newNode
RETURN head
IF head IS NULL
head = newNode
RETURN head
current = head
WHILE [Link] IS NOT NULL
current = [Link]
END WHILE
[Link] = newNode
RETURN head
IF position = 1
[Link] = head
head = newNode
RETURN head
current = head
count = 1
IF current IS NULL
PRINT "Position out of range"
RETURN head
[Link] = [Link]
[Link] = newNode
RETURN head
Q4. What is dynamic data structure. Explain with circular linked list with its basic operations.
At the End:
1. Create a new node.
2. Traverse the list to the last node.
3. Set the next of the last node to the new node.
4. Set the next of the new node to the head.
[Link]
From the Beginning:
1. Update the head to the next node.
2. Update the last node's next to the new head.
3. Free the old head.
[Link]
Start from the head and move through the list, printing the data of each node until reaching the head
again.
Q5. Write and explain node structure of Circular Singly Linked List and DoublyLinked list.
Write pseudocode for concatenation of two doubly linked lists.
In a circular linked list, the next pointer of the last node points back to the first node, forming a
circle.
struct Node {
int data; // Value stored in the node
Node* next; // Pointer to the next node
};
struct Node {
int data; // Value stored in the node
Node* prev; // Pointer to the previous node
Node* next; // Pointer to the next node
};
Pseudo code steps for concatenation of two doubly linked list:
Steps(just for reference)
1. If list1 is empty, return list2 as the concatenated list.
2. If list2 is empty, return list1 as the concatenated list.
3. Traverse list1 to its last node.
4. Link the next pointer of the last node of list1 to the head of list2.
5. Link the prev pointer of the head node of list2 to the last node of list1.
6. Return the updated list1 as the concatenated list.
Pseudo code:
A generalized linked list (GLL) is an extension of a regular linked list where each node can store either
an atomic data element (such as an integer, character, etc.) or a pointer to another generalized linked
list. This structure allows representation of hierarchical or nested data.
Example:
Now temp1 node contains flag 1 which indicates it has another variable and it points down.
Temp2 node contains flag 0 which indicates it has a variable y and points right to next node temp3,
which contains flag 2 which represents coefficient and exponent of variable xy.
This entirely indicates 7x4y.
Now temp4 node contains flag1 which indicates a new variable z and down pointer.
temp5 contains flag 0 which indicates variable z and a next pointer.
Temp6 contains flag 2 which represents coefficients and exponent of variable xz.
and this entirely indicates 10xz.
Q8. Write and explain use of Generalized linked list for representation of multivariable polynomial with
suitable example. Explain node structure.
Generalized Linked List (GLL) is an effective way to represent multivariable polynomials, as it allows
hierarchical storage of terms and their associated variables with exponents.
Use of GLL for Multivariable Polynomials:
Dynamic Structure: GLL can handle polynomials with any number of variables and terms
dynamically.
Hierarchy: The main list stores terms, and each term can have a sublist to store variable-exponent
pairs.
Efficiency in Representation: Unlike arrays, GLL avoids fixed memory allocation and is more
space-efficient for sparse polynomials.
Flexibility: Easily represents polynomials with varying numbers of variables and degrees.
(same example)
Node structure:
// Node for exponents of variables
struct ExpNode {
char variable; // Name of the variable (e.g., x, y)
int exponent; // Power of the variable
ExpNode* next; // Pointer to the next variable in the sublist
};
Push(stack, element):
Add element to the top of the stack
[Link](element)
Pop(stack):
If stack is not empty:
element = [Link]()
Return element
Else:
Return "Stack is empty"
Peek(stack):
If stack is not empty:
Return the top element of the stack
Else:
Return "Stack is empty"
IsEmpty(stack):
If stack is empty:
Return True
Else:
Return False
Size(stack):
Return the number of elements in the stack
Q2. Write pseudo-C/C++ code to implement stack using Singly linked list withoverflow and underflow
conditions.
Node:
data // Holds the value of the node
next // Pointer to the next node
Stack:
top // Points to the top node of the stack
maxSize // Maximum size of the stack (for overflow check)
InitializeStack(maxSize):
top = NULL
maxSize = maxSize
Push(stack, element):
If stack is full (size >= maxSize):
Print "Stack Overflow"
Return
Create newNode with data = element
[Link] = [Link]
[Link] = newNode
Pop(stack):
If stack is empty (top == NULL):
Print "Stack Underflow"
Return
temp = [Link]
[Link] = [Link]
Print "Popped element: " + [Link]
Return [Link]
Peek(stack):
If stack is empty (top == NULL):
Print "Stack is empty"
Return
Return [Link]
IsEmpty(stack):
If [Link] == NULL:
Return True
Else:
Return False
Size(stack):
count = 0
current = [Link]
While current is not NULL:
count = count + 1
current = [Link]
Return count
Q3. Write rules to convert given infix expression to postfix expression using stack. Convert expression
(P * Q – (L + M * N) ^ (X * Y / Z) stepwise using the above rules. Where ^ is - exponential operator
1. Operands:
Directly add operands (e.g., variables or numbers) to the postfix expression.
2. Operators:
If the stack is empty, push the operator onto the stack.
If the stack is not empty, compare the precedence of the operator with the operator on top of
the stack:
• If the current operator has higher precedence: Push it onto the stack.
• If the current operator has lower or equal precedence: Pop operators from the
stack and add them to the postfix expression until the stack is empty or a lower-
precedence operator is found. Then, push the current operator onto the stack.
3. Parentheses:
Left Parenthesis (: Push it onto the stack.
Right Parenthesis ): Pop and add operators from the stack to the postfix expression until a left
parenthesis ( is found. Then, pop and discard the (.
4. End of Expression:
After processing the entire infix expression, pop any remaining operators from the stack and
add them to the postfix expression.
Expression: (P * Q – (L + M * N) ^ (X * Y / Z) )
The main need to convert an infix expression into postfix is to simplify the process of evaluating
expressions, particularly in computer systems and compilers.
Here’s why postfix (or Reverse Polish Notation, RPN) is useful:
1. No Parentheses: Postfix removes the need for parentheses by handling operator precedence
automatically.
2. Easy Evaluation: Postfix is processed sequentially using a stack, making it simpler for machines.
3. Efficient for Compilers: Compilers use postfix for intermediate code generation and faster
computation.
4. Stack-Based Compatibility: It aligns with stack-based architectures, ensuring smooth evaluation.
Q5. Explain procedure to convert infix expression to prefix expression and postfix
evaluation with example.
Example:
Steps to Evaluate Postfix Expression:
5. Result:
At the end of the evaluation, the stack will contain a single value, which is the
result of the postfix expression.
Example:
Q6. Write algorithm for postfix expression evaluation. Explain with suitable example.
Algorithm:
5. Final Result:
At the end, the stack will contain a single value, which is the result of the postfix expression.
Q7. What is the concept of recursion? Explain the use of stack in recursion with example.
Recursion is a programming technique in which a function calls itself to solve a problem. The function
typically divides the problem into smaller subproblems, solving each recursively until a base condition
(termination condition) is met. At that point, the function begins returning results back to the previous
calls, effectively "unwinding" the recursion.
Working:
Factorial(5) → 5 * Factorial(4)
Factorial(4) → 4 * Factorial(3)
Factorial(3) → 3 * Factorial(2)
Factorial(2) → 2 * Factorial(1)
Factorial(1) → 1 * Factorial(0)
Factorial(0) → 1 (base case)
Q8. What are the variants of recursion. Explain with example
1. Direct Recursion
A function directly calls itself to solve a smaller instance of the problem.
Example: Factorial function
Factorial(n):
If n == 0:
Return 1
Else:
Return n * Factorial(n - 1)
2. Indirect Recursion
A function calls another function, which in turn calls the original function.
Example:
Function A():
Call Function B()
Function B():
Call Function A()
3. Tail Recursion
The recursive call is the last operation performed in the function, with no additional work after it.
Optimized by compilers into iterative solutions.
Example:
TailRec(n, result):
If n == 0:
Return result
Else:
Return TailRec(n - 1, result * n)
4. Head Recursion
The recursive call is the first operation performed in the function, and any processing occurs after the
recursive call.
Example:
HeadRec(n):
If n > 0:
HeadRec(n - 1)
Print n
5. Tree Recursion
A function makes multiple recursive calls to itself, resulting in a tree-like structure of calls.
Example: Fibonacci sequence
Fibonacci(n):
If n <= 1:
Return n
Else:
Return Fibonacci(n - 1) + Fibonacci(n - 2)
Q9. What is backtracking algorithm design strategy? How stack is useful in backtracking?
4. Backtrack: undo the last step (partial solution) and try another path.
1. Remembering Decisions: Each step or choice is stored in the stack so you can revisit it if
needed.
2. Undoing Mistakes: If a decision doesn't work (violates constraints or leads to a dead end),
the stack "pops" the last choice, allowing the algorithm to backtrack and try another path.
3. Exploring All Paths: The stack helps the algorithm systematically explore all possible solutions
by revisiting earlier decisions.