Data Structure (Imp-Questions)_copy
Data Structure (Imp-Questions)_copy
[8×2=16]
3. realloc() (Reallocation) :
• Syntax : void* realloc(void* ptr, size_t new_size);
• Description : Changes the size of previously allocated memory blocks. If the ptr is NULL,
realloc() behaves like malloc(). If the new_size is zero, realloc() frees the memory.
• Use Case : Used when you need to resize an already allocated memory block, either to
expand or shrink the allocated space.
• Return Value : Returns a pointer to the reallocated memory, which may be a new memory
address if the block was moved. If allocation fails, NULL is returned, and the original memory
block remains unchanged.
4. free() (Deallocation) :
• Syntax : void free(void* ptr);
• Description : Frees the dynamically allocated memory, releasing it back to the system. After
calling free(), the pointer is no longer valid, and it should not be used.
• Use Case : Used to deallocate memory that was previously allocated by malloc(), calloc(), or
realloc() to avoid memory leaks.
• Return Value : free() does not return any value.
b) Explain Linear Data structure with examples.
Ans:
1. A linear data structure is a type of data structure in which elements are arranged in a
sequential or linear order, where each element is connected to the previous and next element.
In a linear data structure, the elements are stored one after the other, and there is a clear
starting and ending point.
2. In simple terms, linear data structures can be thought of as a collection of elements arranged
in a straight line, where each element has a single predecessor and a single successor (except
the first and last elements).
1. Arrays :
• Definition : An array is a collection of elements stored at contiguous memory locations. Each
element can be accessed using its index.
• Example : An array of integers : int numbers[ ] = {10, 20, 30, 40};
Accessing the second element : numbers[1] returns 20.
2. Linked Lists :
• Definition : A linked list consists of nodes, where each node contains data and a reference (or
pointer) to the next node in the sequence.
• Example : Node1 -> Node2 -> Node3
This structure allows for dynamic memory allocation and efficient insertions/deletions.
3. Stacks :
• Definition : A stack is a collection that follows the Last In First Out (LIFO) principle, meaning
the last element added is the first one to be removed.
• Example : Push: 10, 20, 30
Stack: [30] (top), [20], [10]
Pop: Removes 30, stack becomes [20] (top), [10]
4. Queues :
• Definition : A queue is a collection that follows the First In First Out (FIFO) principle, where the
first element added is the first to be removed.
• Example : Enqueue : 10, 20, 30
Queue : [10] (front), [20], [30] (rear)
Dequeue : Removes 10, queue becomes [20] (front), [30] (rear)
c) What is stack ? Explain different operations used in stack.
Ans: A stack is a linear data structure that follows the Last In First Out (LIFO) principle. This
means that the last element added to the stack is the first one to be removed. Stacks are used
in various applications, including function call management, expression evaluation, and
backtracking algorithms.
• Operations on a Stack :
1. Push : This operation adds an element to the top of the stack. If the stack is full (in case of a
fixed-size stack), it may lead to an overflow condition.
2. Pop : This operation removes the top element from the stack and returns it. If the stack is
empty, it may lead to an underflow condition.
3. Peek (or Top) : This operation retrieves the top element of the stack without removing it. This
is useful for checking the value of the top element.
4. isEmpty : This operation checks if the stack is empty. It returns true if there are no elements in
the stack.
5. isFull : This operation checks if the stack is full, applicable in the case of fixed-size stacks. It
returns true if no more elements can be added.
• Characteristics of Algorithms :
1. Finiteness : An algorithm must always terminate after a finite number of steps. It cannot go on
indefinitely.
2. Definiteness : Each step of the algorithm must be precisely defined, with clear and
unambiguous instructions.
3. Input : An algorithm should have clearly defined inputs, which are the data provided before
the algorithm begins.
4. Output : It should produce one or more outputs, which are the results after processing the
inputs.
5. Effectiveness : All operations must be basic enough to be carried out in a finite amount of
time and with available resources.
6. Generality : An algorithm should be general enough to solve all problems of a specific type,
not just a particular instance. It should apply to a wide range of inputs.
e) Explain selection sort technique with example.
Ans: Selection Sort is a simple comparison-based sorting algorithm. It works by repeatedly
finding the minimum (or maximum) element from the unsorted portion of the list and swapping it
with the element at the current position. The algorithm divides the list into two parts: the sorted
part and the unsorted part. Initially, the sorted part is empty, and the unsorted part contains all
the elements. The algorithm progresses by selecting the smallest (or largest) element from the
unsorted part and moving it to the sorted part.
1. First Pass :
• The unsorted list is [64, 25, 12, 22, 11].
• Find the minimum element in the entire list: 11.
• Swap 11 with the first element (64).
• The array now becomes: [11, 25, 12, 22, 64].
2. Second Pass :
• The unsorted portion is [25, 12, 22, 64].
• Find the minimum element in this part: 12.
• Swap 12 with the first element of the unsorted part (25).
• The array now becomes: [11, 12, 25, 22, 64].
3. Third Pass :
• The unsorted portion is [25, 22, 64].
• Find the minimum element: 22.
• Swap 22 with the first element of the unsorted part (25).
• The array now becomes: [11, 12, 22, 25, 64].
4. Fourth Pass :
• The unsorted portion is [25, 64].
• The minimum element is 25, which is already in the correct position, so no swap is needed.
• The array remains : [11, 12, 22, 25, 64].
5. Fifth Pass :
• Only one element is left (64), and it is already in the correct position.
Now, at the end of the sorting process, the array is sorted : [11, 12, 22, 25, 64]
1. First Pass (i = 1) :
• Compare the second element (2) with the first element (5).
• Since 2 < 5, we shift 5 to the right and place 2 in its correct position.
• The array becomes : [2, 5, 9, 1, 5, 6].
2. Second Pass (i = 2) :
• Compare the third element (9) with the previous element (5).
• Since 9 > 5, no shifting is required. 9 stays in its position.
• The array remains : [2, 5, 9, 1, 5, 6].
3. Third Pass (i = 3) :
• Compare the fourth element (1) with the previous elements.
• Since 1 < 9, we shift 9 to the right.
• Since 1 < 5, we shift 5 to the right.
• Since 1 < 2, we shift 2 to the right.
• Insert 1 in the first position.
• The array becomes : [1, 2, 5, 9, 5, 6].
4. Fourth Pass (i = 4) :
• Compare the fifth element (5) with the previous elements.
Since 5 < 9, we shift 9 to the right.
• Since 5 == 5, no further shifting is needed, and 5 stays in its position.
• The array becomes : [1, 2, 5, 5, 9, 6].
5. Fifth Pass (i = 5) :
• Compare the sixth element (6) with the previous elements.
• Since 6 < 9, we shift 9 to the right.
• Since 6 > 5, no further shifting is needed, and 6 is inserted in its correct position.
• The array becomes : [1, 2, 5, 5, 6, 9].
A Static Queue (also known as a regular or linear queue) is a queue where the elements are
arranged in a linear fashion. The main difference between a Circular Queue and a Static Queue
lies in how they manage the available space and how elements are added and removed.
• Key Differences :
Points Circular Queue Static Queue (Linear Queue)
2. Queue Overflow occurs only when the Overflow occurs when the queue is
Overflow queue is full, considering the full, regardless of available empty
circular nature. spaces at the front.
3. Wrap Around The rear wraps around to the front The rear cannot wrap around. Once
when it reaches the end of the the queue is full, no new elements
queue. can be added, even if space is
available at the front.
5. Queue Size Fixed size, but with efficient usage Fixed size, but space is wasted as
of space (no wasted space when elements are dequeued and no
elements are removed). longer reused.
• Types of AVL Rotations : There are four types of AVL rotations used to balance the tree when
it becomes unbalanced :
1. Right Rotation (Single Rotation) : This is performed when the left subtree of the left child is
too tall (Left-Left case).
2. Left Rotation (Single Rotation) : This is performed when the right subtree of the right child is
too tall (Right-Right case).
3. Left-Right Rotation (Double Rotation) : This is performed when the right subtree of the left
child is too tall (Left-Right case).
4. Right-Left Rotation (Double Rotation) : This is performed when the left subtree of the right
child is too tall (Right-Left case).
Q3) Attempt any Four of the following. [4 × 4 = 16]
class SinglyLinkedList:
def __init__(self):
self.head = None
def display(self):
current = self.head
while current:
print(current.data, end=" -> ")
current = current.next
print("None")
# Example usage
ll = SinglyLinkedList()
ll.insert(10)
ll.insert(20)
ll.insert(30)
ll.display()
def display(self):
if self.front == -1:
print("Queue is empty")
else:
for i in range(self.front, self.rear + 1):
print(self.queue[i], end=" ")
print()
# Example usage
q = Queue(5)
q.enqueue(10)
q.enqueue(20)
q.enqueue(30)
q.display() # Output: 10 20 30
Output :
Enqueued: 10
Enqueued: 20
Enqueued: 30
10 20 30
c) Explain BFS traversing technique with an example.
Ans:
• BFS (Breadth-First Search) Traversing Technique : BFS is a graph traversal algorithm that
explores all the vertices of a graph level by level. It starts from the root (or any arbitrary node)
and explores all its neighbors first, before moving on to the next level of nodes. BFS is
implemented using a queue data structure to manage the exploration order.
• BFS Algorithm :
1. Initialize an empty queue and enqueue the starting node.
2. Mark the starting node as visited.
3. While the queue is not empty :
• Dequeue a node.
• Visit the node (process or print).
• Enqueue all its unvisited neighbors and mark them as visited.
1. Start at A :
• Queue : [A]
• Visited : {A}
• Process A and enqueue its neighbors B and C.
• Queue : [B, C]
2. Dequeue B :
• Dequeue : [C]
• Visited : {A, B}
• Process B and enqueue its neighbors D and E (A is already visited).
• Queue : [C, D, E]
3. Dequeue C :
• Queue : [D, E]
• Visited : {A, B, C}
• Process C and enqueue its neighbor F.
• Queue : [D, E, F]
4. Dequeue D :
• Queue : [E, F]
• Visited : {A, B, C, D}
• D has no unvisited neighbors.
5. Dequeue E :
• Queue : [F]
• Visited : {A, B, C, D, E}
• E has no unvisited neighbors.
6. Dequeue F :
• Queue : [ ]
• Visited : {A, B, C, D, E, F}
• F has no unvisited neighbors.
class SinglyLinkedList:
def __init__(self):
self.head = None
def delete_first_node(self):
if self.head:
self.head = self.head.next
else:
print("List is empty.")
def display(self):
current = self.head
while current:
print(current.data, end=" -> ")
current = current.next
print("None")
# Example usage
ll = SinglyLinkedList()
ll.head = Node(10)
ll.head.next = Node(20)
ll.head.next.next = Node(30)
print("Before deletion:")
ll.display()
ll.delete_first_node()
print("After deletion:")
ll.display()
Output :
Before deletion : 10 -> 20 -> 30 -> None
After deletion : 20 -> 30 -> None
f) Write a function to reverse a string using stack.
Ans:
def reverse_string(s):
stack = [] # Stack to store characters
# Pop characters from the stack and build the reversed string
reversed_str = ""
while stack:
reversed_str += stack.pop()
return reversed_str
# Example usage
string = "Hello, World!"
reversed_string = reverse_string(string)
print("Original String:", string)
print("Reversed String:", reversed_string)
Output :
Original String : Hello, World!
Reversed String : !dlroW ,olleH
g) Write a ‘C’ Program for evaluation of polynomials.
Ans:
#include <stdio.h>
• Key Characteristics :
1. Fixed Size : A circular queue has a fixed size.
2. Front and Rear Pointers : It maintains two pointers—front (points to the first element) and rear
(points to the last element).
3. Wrap-around : When the rear pointer reaches the end of the queue, it wraps around to the
beginning, allowing for efficient use of space.
1. Adjacency Matrix : An adjacency matrix is a 2D array (or matrix) used to represent a graph.
The rows and columns represent the vertices, and the values in the matrix represent the
presence or absence of edges.
• In a directed graph, if there is an edge from vertex to vertex , then the matrix entry is 1 (or the
weight of the edge). Otherwise, it is 0.
• In an undirected graph, the matrix is symmetric, meaning if there is an edge from vertex to
vertex , both will be 1.
2. Adjacency List : An adjacency list is a collection of lists or arrays where each list represents a
vertex and contains a list of its adjacent vertices (neighbors).
• For a directed graph, the list at index will contain all the vertices to which vertex has directed
edges.
• For an undirected graph, each edge is stored twice, once for each vertex involved.
3. Incidence Matrix : An incidence matrix represents a graph using a matrix where rows
represent vertices and columns represent edges. The entry at is 1 if vertex is incident to edge ,
and 0 otherwise.
• For a directed graph, if vertex is the starting point of edge , then , and if vertex is the
endpoint, then .
• For an undirected graph, if the vertex is incident to edge , then .
4. Edge List : An edge list is a simple list of all the edges in the graph. Each edge is represented
by a pair (or triplet, if the graph is weighted) of vertices.
i) Write a C- program to display a linked list in Reverse order.
Ans:
#include <stdio.h>
#include <stdlib.h>
// Define the structure for the node
struct Node {
int data;
struct Node *next;
};
// Function to insert a node at the end of the linked list
void insertEnd(struct Node **head, int data) {
struct Node *newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
if (*head == NULL) *head = newNode;
else {
struct Node *temp = *head;
while (temp->next) temp = temp->next;
temp->next = newNode;
} }
// Function to print the linked list in reverse order using recursion
void printReverse(struct Node *head) {
if (head) {
printReverse(head->next);
printf("%d ", head->data);
} }
int main() {
struct Node *head = NULL;
int n, val;
// Input number of nodes and the values
printf("Enter number of nodes: ");
scanf("%d", &n);
while (n--) {
scanf("%d", &val);
insertEnd(&head, val);
}
// Display the list in reverse order
printReverse(head);
printf("\n");
return 0; }
ii) (A + B * C - D) / E $ F :
-
Infix expression : (A + B * C - D) / E $ F
1. B * C : First multiplication.
2. A + (B * C) : Addition.
3. (A + B * C - D) : Subtraction.
4. / E : Division.
5. $ F : Exponentiation.
Postfix expression : A B C * + D - E / F $
c) Convert the following expression into prefix
i) A+B/C*(D – A) ^ F ^ H
ii) A* (B*C+D*E) + F
Ans:
i) A+B/C*(D – A) ^ F ^ H :
-
Infix expression : A + B / C * (D - A) ^ F ^ H
1. B / C : Division.
2. D - A : Subtraction.
3. (D - A) ^ F : Exponentiation.
4. (D - A) ^ F ^ H : Exponentiation (right to left).
5. B / C * (D - A) ^ F ^ H : Multiplication.
6. A + (result from step 5) : Addition.
Prefix expression : + A * / B C ^ - D A ^ F H
ii) A * (B * C + D * E) + F :
-
Infix expression : A * (B * C + D * E) + F
1. B * C : Multiplication.
2. D * E : Multiplication.
3. B * C + D * E : Addition.
4. A * (result from step 3) : Multiplication.
5. A * (B * C + D * E) + F : Addition.
Prefix expression : + * A + * B C * D E F