DS Model paper
DS Model paper
2 Marks
1. Define Stack and its operations
• A Stack is a linear data structure that follows the Last In First Out (LIFO) principle,
where the last element inserted is the first to be removed.
• Operations include push (to insert an element), pop (to remove the top element),
and peek (to view the top element without removing it).
Example:
If we push 10, 20, 30 into a stack, popping once will remove 30.
8. Write any two differences between Linear Search and Binary Search
• Linear Search: Scans each element one by one until the target is found; it works on
both sorted and unsorted data.
• Binary Search: Repeatedly divides the sorted list in half to search for the target; it
only works on sorted data.
Example:
To find 3 in [1, 2, 3, 4],
• Linear search checks 1→2→3;
• Binary search checks middle elements directly.
Diagram:
Example:
• In linear search, the time complexity is O(n) because in the worst case we might have
to check all n elements.
2. Omega Notation (Ω-notation)
Definition:
• Omega Notation provides a lower bound for an algorithm's running time or resource
consumption based on input size.
• It describes the best-case scenario performance, meaning that the algorithm will
take at least a certain amount of time or space as the input size grows.
• Omega notation is particularly useful to understand the minimum work an algorithm
must perform, regardless of any optimizations.
Advantage:
• Helps to know the minimum time an algorithm will take under the best conditions.
• Useful in optimistic analysis where best performance matters.
Disadvantage:
• Tells only about best-case, so it might hide poor performance in average or worst
cases.
• Not sufficient alone for critical applications where worst-case matters.
Equation:
• f(n) = Ω(g(n))
if there exist constants c > 0 and n₀ ≥ 0 such that
f(n) ≥ c × g(n) for all n ≥ n₀.
Diagram:
Example:
• In bubble sort, the best case (already sorted array) has time complexity Ω(n) — we
just scan once.
Diagram:
Example:
• In insertion sort for random input, the time complexity is Θ(n²) — both upper and
lower bounds grow like n².
Type of Linked
Description
List
Singly Linked Each node points to the next node and the last node points to NULL. (One-
List way traversal)
Doubly Linked Each node contains two pointers: one pointing to the next node and one to
List the previous node. (Two-way traversal)
Circular
In this list, the last node points back to the first node, forming a circle.
Linked List
Insertion in Linked List
Definition
Insertion in a linked list means adding a new node to the list. It can be done at different
locations depending on the requirement:
• At the beginning
• At the end
• At a specific position
Insertion in a linked list is more efficient than arrays because it does not require shifting
elements.
Types of Insertion
1. Insertion at the Beginning:
o Create a new node.
o Set its next pointer to the current head.
o Update the head to point to the new node.
2. Insertion at the End:
o Traverse the list until the last node (whose next is NULL).
o Set its next to point to the new node.
3. Insertion at a Specific Position:
o Traverse to the node after which the new node should be inserted.
o Adjust the pointers accordingly to link the new node.
class Node {
public:
int data;
Node* next;
};
// Function to insert node at the beginning
void insertAtBeginning(Node*& head, int newData) {
Node* newNode = new Node();
newNode->data = newData;
newNode->next = head;
head = newNode;
}
int main() {
Node* head = NULL;
insertAtBeginning(head, 30);
insertAtBeginning(head, 20);
insertAtBeginning(head, 10);
return 0;
}
Output:
rust
CopyEdit
Linked List after insertion at beginning: 10 -> 20 -> 30 -> NULL
class Node {
public:
int data;
Node* next;
};
int main() {
Node* head = new Node();
Node* second = new Node();
Node* third = new Node();
head->data = 10;
second->data = 20;
third->data = 30;
head->next = second;
second->next = third;
third->next = NULL;
deleteAtBeginning(head);
return 0;
}
Output:
rust
CopyEdit
Original Linked List: 10 -> 20 -> 30 -> NULL
Linked List after deletion at beginning: 20 -> 30 -> NULL
A stack is a linear data structure that follows the Last In, First Out (LIFO) principle. This
means the last element inserted into the stack will be the first one to be removed.
In simpler terms, think of a stack like a pile of plates: you add (push) plates on top, and
remove (pop) plates from the top only.
When implemented using an array, the stack operations are done using an array and a top
variable:
• The array stores the stack elements.
• The top variable keeps track of the index of the last inserted element (topmost
element).
If the top is -1, it means the stack is empty. If top == size - 1, it means the stack is full.
2. Pop Operation
Pop means removing the topmost element from the stack.
Steps:
• Check if the stack is empty (underflow condition).
• If not empty, remove and return the element at stack[top], then decrement top.
If pop is done on an empty stack, it causes stack underflow.
Applications of Pop
• Function calls: When a function returns, the corresponding call is popped from the
stack, and control goes back to the previous function.
• Undo operations: In applications like text editors, you can pop the last action to undo
it.
• Expression evaluation: When evaluating postfix expressions, operands are popped
from the stack for operations.
3. Peek Operation
Peek (or Top) means viewing the topmost element without removing it from the stack.
Steps:
• Check if the stack is empty.
• If not empty, return the value at stack[top].
Applications of Peek
• Inspect top element: In situations where you want to see the most recent item
added to the stack without modifying it (e.g., checking the top of a function call
stack).
• Expression evaluation: Peek can be used to view the top element in an expression
evaluation algorithm to decide the next step (like checking the operator precedence).
• Browser History: In browsers, peek is used to see the last visited URL without
navigating away.
#define SIZE 5
class Stack {
private:
int arr[SIZE];
int top;
public:
Stack() {
top = -1; // Initialize stack as empty
}
// Push operation
void push(int value) {
if (top == SIZE - 1) {
cout << "Stack Overflow! Cannot push " << value << endl;
return;
}
top++;
arr[top] = value;
cout << value << " pushed into stack." << endl;
}
// Pop operation
void pop() {
if (top == -1) {
cout << "Stack Underflow! Cannot pop." << endl;
return;
}
cout << arr[top] << " popped from stack." << endl;
top--;
}
// Peek operation
void peek() {
if (top == -1) {
cout << "Stack is empty!" << endl;
} else {
cout << "Top element is: " << arr[top] << endl;
}
}
int main() {
Stack s;
s.push(10);
s.push(20);
s.push(30);
s.display();
s.peek();
s.pop();
s.display();
return 0;
}
Output
csharp
CopyEdit
10 pushed into stack.
20 pushed into stack.
30 pushed into stack.
Stack elements: 30 20 10
Top element is: 30
30 popped from stack.
Stack elements: 20 10
4 in ct 2 pdf
A Heap is a special type of complete binary tree that satisfies a specific ordering property
called the heap property.
It means:
• Every level of the tree is completely filled except possibly the last.
• The last level has all keys as left as possible.
• Depending on the type of heap, the value of a parent node is either greater (in Max
Heap) or smaller (in Min Heap) than its children.
In a heap, elements are organized such that the highest-priority element can be accessed
efficiently.
Heaps are usually implemented using arrays because:
• In a complete binary tree, for a node at index i,
o Left child is at 2*i + 1
o Right child is at 2*i + 2
o Parent is at (i-1)/2 (integer division)
Thus, heaps provide a very efficient structure for managing ordered data.
Types of Heaps
Type Definition
Min The value of each node is smaller than or equal to the values of its children.
Heap Minimum element at root.
Max The value of each node is greater than or equal to the values of its children.
Heap Maximum element at root.
Applications of Heap
• Priority queues (heap is the standard way to implement them).
• Heap Sort algorithm (based on heap structure).
• Finding the kth largest/smallest elements in a dataset.
• Scheduling CPU jobs, printer jobs, network packets (based on priorities).
• Graph algorithms like Dijkstra's shortest path, Prim’s Minimum Spanning Tree.
if (smallest != i) {
swap(heap[i], heap[smallest]);
minHeapify(heap, n, smallest); // Recursively heapify the affected subtree
}
}
int main() {
vector<int> heap = {40, 20, 30, 10, 50, 60, 15};
buildMinHeap(heap);
return 0;
}
Output
yaml
CopyEdit
Original Array: 40 20 30 10 50 60 15
Min Heap: 10 20 15 40 50 60 30
#include<iostream>
#include<vector>
using namespace std;
if (largest != i) {
swap(heap[i], heap[largest]);
maxHeapify(heap, n, largest); // Recursively heapify the affected subtree
}
}
int main() {
vector<int> heap = {40, 20, 30, 10, 50, 60, 15};
buildMaxHeap(heap);
return 0;
}
Output
yaml
CopyEdit
Original Array: 40 20 30 10 50 60 15
Max Heap: 60 50 30 10 20 40 15
7 and 8 in ct 2 pdf
class Edge {
public:
int src, dest, weight;
Edge(int s, int d, int w) : src(s), dest(d), weight(w) {}
};
DisjointSet(int n) {
parent.resize(n);
rank.resize(n, 0);
for (int i = 0; i < n; i++)
parent[i] = i;
}
if (rootU != rootV) {
if (rank[rootU] < rank[rootV])
parent[rootU] = rootV;
else if (rank[rootU] > rank[rootV])
parent[rootV] = rootU;
else {
parent[rootV] = rootU;
rank[rootU]++;
}
}
}
};
vector<Edge> mst;
int totalWeight = 0;
cout << "Total Weight of MST: " << totalWeight << endl;
}
int main() {
int V = 6;
vector<Edge> edges = {
{0, 1, 4}, {0, 2, 4}, {1, 2, 2}, {1, 3, 6},
{2, 3, 8}, {2, 4, 5}, {3, 4, 9}, {3, 5, 10},
{4, 5, 3}
};
kruskalMST(edges, V);
return 0;
}
6.1. Output
yaml
CopyEdit
Minimum Spanning Tree Edges:
1-2:2
4-5:3
0-1:4
2-4:5
1-3:6
Total Weight of MST: 20
Prim's Algorithm is a greedy algorithm used to find the Minimum Spanning Tree (MST) of a
connected, weighted, and undirected graph. It constructs the MST by starting from an
arbitrary node and iteratively adding the smallest edge that connects to an unvisited node.
Characteristics of Prim's Algorithm
4.1. Advantages
✔ Works well for dense graphs (where edges ≈ vertices²).
✔ Ensures optimal solution for MST.
✔ Uses fewer edge comparisons than Kruskal’s Algorithm.
4.2. Disadvantages
✘ Slower for sparse graphs compared to Kruskal’s Algorithm.
✘ Implementation complexity is higher due to priority queues.
✘ Requires extra data structures (priority queue, adjacency list) for efficiency.
5. Applications of Prim's Algorithm
✔ Network Design – Laying out electrical grids, communication networks, and pipelines.
✔ Graph Theory Problems – Finding an MST in weighted graphs.
✔ Cluster Analysis – Identifying relationships in datasets.
✔ Image Processing – Used in segmentation and pattern recognition.
✔ Flight Route Optimization – Finding the cheapest flight connections.
key[0] = 0;
pq.push({0, 0});
while (!pq.empty()) {
int u = pq.top().second;
pq.pop();
inMST[u] = true;
int main() {
int V = 6;
vector<vector<pii>> graph(V);
graph[0].push_back({1, 4});
graph[0].push_back({2, 4});
graph[1].push_back({2, 2});
graph[1].push_back({3, 6});
graph[2].push_back({3, 8});
graph[2].push_back({4, 5});
graph[3].push_back({4, 9});
graph[3].push_back({5, 10});
graph[4].push_back({5, 3});
primMST(graph, V);
return 0;
}
Output
Minimum Spanning Tree Edges:
0-1:4
1-2:2
2-4:5
4-5:3
1-3:6
cpp
CopyEdit
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
// Activity structure
struct Activity {
int start, finish;
};
int main() {
vector<Activity> activities = { {5, 9}, {1, 2}, {3, 4}, {0, 6}, {5, 7}, {8, 9} };
activitySelection(activities);
return 0;
}
Output
Selected activities are:
(1, 2)
(3, 4)
(5, 7)
(8, 9)