Data Structure and Algorithm
Data Structure and Algorithm
INDIVIDUAL ASSIGNMENT
Id no mdr/1634/19
Department SE(R)
add
1. Explain the differences between arrays and linked lists in terms of memory allocation,
insertion/deletion efficiency, and traversal. Provide examples where each data structure is more suitable
-It is necessary to specify the number -it is not necessary to specify z number
-It occupies less memory tgan linked list for is allocated during run time)
-Inserting new elements at the front is potentially - inserting a new element at any posit-
-Use an array when you need fast access by index -use a linked list when u expect freqent
and know the size ahead of time inseriton/deletion (e.g implementing
2. Compare recursion and iteration. Write a C++ function to calculate the Fibonacci sequence using both
approaches and discuss their time/space complexities.
• Recursion involves a function calling itself to solve smaller instances of the problem. It can be more
elegant but may lead to stack overflow if too deep.
• Iteration uses loops to repeat a block of code until a condition is met. It is usually more memory-
efficient.
// Recursive Fibonacci
int fibonacci_recursive(int n) {
if (n <= 1) return n;
// Iterative Fibonacci
int fibonacci_iterative(int n) {
if (n <= 1) return n;
int a = 0, b = 1;
int temp = a + b;
a = b;
b = temp;
return b;
• Time/Space Complexity:
3. Define hash table collisions and explain two resolution strategies (e.g., chaining, open addressing).
Provide code snippets illustrating each method.
• A hash table collision occurs when two keys hash to the same index in the hash table.
• Resolution Strategies:
• Chaining: Each slot in the hash table contains a linked list of entries that hash to the same index.
struct Node {
int key;
Node* next;
};
class HashTable {
Node** table;
int size;
public:
table[index] = newNode;
};
• Open Addressing: All elements are stored in the array itself, and a probing sequence is used to find
an empty slot.
class HashTable {
int* table;
int size;
public:
table[index] = key;
};
4. Tree Traversals:
Describe in-order, pre-order, and post-order traversal algorithms for binary trees. Manually traverse the
following tree and list the nodes in each order:
BC
/\\ In-order: D, B, E, A, C, F
DEF Pre-order: A, B, D, E, C, F
Post-order: D, E, B, F, C, A
5. Analyze the time complexity of the following code using Big-O notation:
• The outer loop runs as long as i is less than n. However, i starts at 0 and never changes due to i *= 2,
which means the loop never executes.
6. Implement a stack using a singly linked list in C++. Include push, pop, and peek operations. Handle
edge cases like underflow
struct Node
int data;
Node* next;
};
class Stack {
Node* top;
public:
Stack() : top(nullptr) {}
top = newNode;
void pop() {
top = top->next;
delete temp;
int peek() {
return top->data;
};
7. Create a BST in C++ with functions to insert nodes, delete nodes, and search for a value. Demonstrate
inserting [15, 10, 20, 8, 12, 17, 25] and deleting the node with value 15.
struct TreeNode {
int value;
TreeNode* left;
TreeNode* right;
};
class BST {
TreeNode* root;
if (!node) {
node = new TreeNode(value);
insert(node->left, value);
} else {
insert(node->right, value);
} else {
node->value = minNode->value;
return node;
}
public:
BST() : root(nullptr) {}
};
// Demonstration
BST tree;
tree.deleteValue(15)
8. Implement a graph using an adjacency list in C++. Include functions to add edges and perform BFS
traversal starting from a given node.
#include <iostream>
#include <vector>
#include <queue>
class Graph {
std::vector<std::vector<int>> adjList;
public:
adjList[u].push_back(v);
std::queue<int> q;
visited[start] = true;
q.push(start);
while (!q.empty()) {
q.pop();
if (!visited[neighbor]) {
visited[neighbor] = true;
q.push(neighbor);
};
9. Write a C++ program to sort an array using the merge sort algorithm. Explain the divide-and-conquer
approach and provide a step-by-step breakdown for sorting [9, 3, 7, 5, 6, 4, 8, 2].
#include <iostream>
#include <vector>
int i = 0, j = 0, k = left;
// Example usage:
int main() {
• Divide-and-Conquer Approach: Merge sort divides the array into halves recursively until single
elements are reached and then merges them back together in sorted order.
10.Design a C++ program to dynamically create a 2D array, populate it with user input, and deallocate
memory properly. Explain pointer arithmetic in your code.
#include <iostream>
int main() {
}
// Deallocate memory
delete[] array[i];
delete[] array;
return 0;
• Pointer Arithmetic: In C++, pointer arithmetic allows you to navigate through memory locations. For
example:
Solve the "Coin Change" problem using a greedy approach (e.g., coins = [1, 5, 10]). Explain why this
method works for the given denominations but fails for others like [1, 3, 4]
Problem Statement: Given a set of coin denominations, determine the minimum number of coins
needed to make a specific amount.
Greedy Approach:
1. Start with the largest denomination and use as many of those coins as possible without exceeding the
target amount.
2. Move to the next largest denomination and repeat until the amount is reached.
• For any amount, you can always use the largest coin available first. This ensures that you minimize the
total number of coins used because larger denominations cover more value with fewer coins.
Example:
• To make 28:
• Consider making 6 with denominations [1, 3, 4]: • Greedy would choose one 4 (leaving 2), then it
would need two 1s (total of 3 coins).
Implement the N-Queens problem using backtracking in C++. Print one valid configuration for a 4x4
chessboard and explain how backtracking avoids invalid placements Problem Statement: Place N queens
on an N x N chessboard such that no two queens threaten each other.
C++ Implementation:
#include <iostream>
#include <vector>
return true;
board[i][col] = 0; // Backtrack
return false;
void solveNQueens(int N) {
if (!solveNQueensUtil(board, 0, N)) {
return;
for (int val : row) cout << val << " ";
int main() {
solveNQueens(4);
return 0;
Explanation:
• The function isSafe checks if placing a queen at a specific position is safe from attacks.
• The function solveNQueensUtil uses recursion to place queens in columns one by one.
• If placing a queen leads to a solution, it returns true; otherwise, it backtracks by removing the queen.
Use dynamic programming to solve the Fibonacci sequence problem. Compare the time complexity of
your solution with the recursive approach and explain memoization.
#include <iostream>
#include <vector>
int fibonacci(int n) {
fib[0] = 0;
fib[1] = 1;
return fib[n];
int main() {
cout << "Fibonacci(" << n << ") = " << fibonacci(n) << endl;
return 0;
Memoization Explanation:
• Memoization involves storing the results of expensive function calls and returning the cached result
when the same inputs occur again. This avoids redundant calculations and speeds up the execution
significantly.
Design a queue using two stacks. Provide C++ code for enqueue and dequeue operations and analyze
the time complexity.
Designing a Queue Using Two Stacks:
#include <iostream>
#include <stack>
class QueueUsingStacks {
private:
public:
void enqueue(int x) {
stack1.push(x);
int dequeue() {
if (stack2.empty()) {
while (!stack1.empty()) {
stack2.push(stack1.top());
stack1.pop();
}
if (stack2.empty()) throw runtime_error("Queue is empty");
stack2.pop();
return front;
};
int main() {
QueueUsingStacks q;
q.enqueue(1);
q.enqueue(2);
q.enqueue(3);
return 0;
• Dequeue Operation: Amortized O(1). If stack2 is empty, we transfer elements from stack1 to stack2,
which takes O(n), but this happens infrequently.
Write a C++ function to perform binary search on a sorted array. Test it with the input [2, 5, 8, 12, 16,
23, 38, 56] and search for 23. Explain why binary search requires a sorted dataset.
#include <iostream>
int main() {
if (result != -1)
cout << "Element found at index: " << result << endl;
else
return 0;