1.
algorithm to find and print the sum and average of elements in an array:
Algorithm: Sum and Average of Array Elements
Input: An array arr of size n.
Output: Sum and Average of the array elements.
1.
Start
2.
Initialize sum = 0.
3.
Read the size of the array, n.
4.
Repeat for each element in the array (from index i = 0 to n - 1):
a. Add the value of arr[i] to sum.
5.
Calculate the average: average = sum / n.
6.
Print sum and average.
7.
End
2. Write algorithms to perform following operations in an array
a) Insert element in an array.
b) Delete an element in an array.
c) Remove duplicate elements from an array
a) Insert an Element in an Array
Input: An array arr of size n, element x to insert, and position pos.
Output: Updated array after insertion.
1.
Start
2.
Read the size of the array n.
3.
Read the array elements.
4.
Read the element x and position pos.
5.
Shift all elements from position pos to the right by one position.
6.
Insert x at position pos.
7.
Increment the size of the array (n = n + 1).
8.
Print the updated array.
9.
End
b) Delete an Element from an Array
Input: An array arr of size n and position pos to delete.
Output: Updated array after deletion.
1.
Start
2.
Read the size of the array n.
3.
Read the array elements.
4.
Read the position pos to delete.
5.
Shift all elements from position pos + 1 to the left by one position.
6.
Decrease the size of the array (n = n - 1).
7.
Print the updated array.
8.
End
c) Remove Duplicate Elements from an Array
Input: An array arr of size n.
Output: Array with duplicates removed.
1.
Start
2.
Read the size of the array n.
3.
Read the array elements.
4.
Create an empty list unique.
5.
Repeat for each element in arr:
a. If the element is not in unique, add it to unique.
6.
Replace arr with unique.
7.
Print the updated array.
8.
End
3. Write an algorithm a) To find the smallest & largest elements in an array b) To merge the elements of two arrays in a third array in a sorted
manner
a) Find the Smallest and Largest Elements in an Array
Input: An array arr of size n.
Output: Smallest and largest elements in the array.
1.
Start
2.
Read the size of the array n.
3.
Read the elements of the array arr.
4.
Initialize smallest = arr[0] and largest = arr[0].
5.
Repeat for each element in arr (from index i = 1 to n - 1):
a. If arr[i] < smallest, update smallest = arr[i].
b. If arr[i] > largest, update largest = arr[i].
6.
Print smallest and largest.
7.
End
b) Merge Two Arrays in Sorted Order
Input: Two sorted arrays arr1 of size n1 and arr2 of size n2.
Output: A third array arr3 containing all elements in sorted order.
1.
Start
2.
Read the size of arrays n1 and n2.
3.
Read elements of arrays arr1 and arr2.
4.
Initialize pointers i = 0, j = 0, and k = 0 for arrays arr1, arr2, and arr3, respectively.
5.
Repeat until either i == n1 or j == n2:
a. If arr1[i] < arr2[j], assign arr3[k] = arr1[i] and increment i and k.
b. Else, assign arr3[k] = arr2[j] and increment j and k.
6.
Copy any remaining elements from arr1 to arr3.
7.
Copy any remaining elements from arr2 to arr3.
8.
Print arr3.
9.
End
4. Explain the memory representation of a 2D array & sparse matrix and write an algorithm to check if a matrix is sparse.
1. Memory Representation of a 2D Array
A 2D array is stored in contiguous memory locations in either row-major order or column-major order.
1.
Row-Major Order:
Elements are stored row by row.
Address(A[i][j]) = Base_Address + [ (i × Total_Columns) + j ] × Element_Size
2.Column-Major Order:
Elements are stored column by column.
Address(A[i][j]) = Base_Address + [ (j × Total_Rows) + i ] × Element_Size
Example
For a 2D array:
Copy code A = [ [10, 20, 30], [40, 50, 60]]
Row-Major Order Storage:
10, 20, 30, 40, 50, 60
Column-Major Order Storage:
10, 40, 20, 50, 30, 60
2. Memory Representation of a Sparse Matrix
A sparse matrix is a matrix in which most of the elements are zero. Instead of storing all elements, we only store non-zero elements using Triple
Representation:
Algorithm to Check if a Matrix is Sparse
Input: A matrix A of size m × n.
Output: Whether the matrix is sparse or not.
Algorithm
1.
Start
2.
Read the dimensions of the matrix m and n.
3.
Initialize a counter count = 0.
4.
Loop through each element of the matrix:
a. If the element is 0, increment count.
5.
Calculate total elements: total = m × n.
6.
If count > total / 2:
a. Print "Sparse Matrix".
7.
Else:
a. Print "Not Sparse".
8.
End
5. Write algorithms to perform following operations on a string. a) Reverse a string b) Check for a pattern in a string. c) Concatenate two strings
Algorithms for String Operations
a) Reverse a String
Input: A string S of length n.
Output: Reversed string.
Algorithm:
1.
Start
2.
Read the string S.
3.
Initialize an empty string Rev.
4.
Loop through the string from the last character to the first:
a. Append each character to Rev.
5.
Print Rev.
6.
End
b) Check for a Pattern in a String
Input: A string S and a pattern P.
Output: Position of the pattern if found, otherwise -1.
Algorithm:
1.
Start
2.
Read the string S and pattern P.
3.
Loop through S to find a match for P:
a. Compare substring of length len(P) with P.
4.
If a match is found, return the starting index.
5.
If no match is found, return -1.
6.
End
c) Concatenate Two Strings
Input: Two strings S1 and S2.
Output: Concatenated string S3.
Algorithm:
1.
Start
2.
Read strings S1 and S2.
3.
Concatenate S1 and S2 using the + operator.
4.
Print the result.
5.
End
6. Write an algorithms to insert and delete a node in a singly linked list at following positions. a) Beginning b) Middle c) End. d) Empty linked list
Algorithms for Insertion and Deletion in a Singly Linked List
A. Insertion in a Singly Linked List
a) Insert at the Beginning
Input: A linked list L and a node N with data.
Output: Updated linked list with N at the beginning.
Algorithm:
1.
Start
2.
Create a new node N.
3.
Set N.next = Head.
4.
Update Head = N.
5.
End
b) Insert in the Middle
Input: A linked list L, a position pos, and a node N with data.
Output: Updated linked list with N inserted at position pos.
Algorithm:
1.
Start
2.
Traverse the list to position pos - 1.
3.
Create a new node N.
4.
Set N.next = Current.next.
5.
Update Current.next = N.
6.
End
c) Insert at the End
Input: A linked list L and a node N with data.
Output: Updated linked list with N at the end.
Algorithm:
1.
Start
2.
Traverse the list until Current.next = NULL.
3.
Create a new node N.
4.
Set Current.next = N.
5.
Update N.next = NULL.
6.
End
d) Insert in an Empty Linked List
Input: An empty linked list L and a node N with data.
Output: Updated linked list with N as the first node.
Algorithm:
1.
Start
2.
Create a new node N.
3.
Set Head = N.
4.
Update N.next = NULL.
5.
End
B. Deletion in a Singly Linked List
a) Delete from the Beginning
Input: A linked list L.
Output: Updated linked list without the first node.
Algorithm:
1.
Start
2.
If the list is empty, print "Underflow" and exit.
3.
Set Head = Head.next.
4.
Delete the old first node. 5.End
b) Delete from the Middle
Input: A linked list L and a position pos.
Output: Updated linked list with the node at position pos deleted.
Algorithm:
1.
Start
2.
Traverse the list to position pos - 1.
3.
Set Current.next = Current.next.next.
4.
Delete the node at position pos.
5.
End
c) Delete from the End
Input: A linked list L.
Output: Updated linked list without the last node.
Algorithm:
1.
Start
2.
Traverse the list until Current.next.next = NULL.
3.
Set Current.next = NULL.
4.
Delete the last node.
5.
End
d) Delete from an Empty Linked List
Input: An empty linked list L.
Output: Print "Underflow".
Algorithm:
1.
Start
2.
If Head == NULL, print "Underflow" and exit.
3.
End
7. Write an algorithm to insert and delete a node on doubly and circular linked list at following positions. a) Beginning b) Middle c) End. d)
Empty linked list
A. Doubly Linked List (DLL)
1. Insertion in Doubly Linked List
a) Insert at the Beginning
Input: Doubly linked list L and a node N.
Output: Updated list with N at the beginning.
Algorithm:
1.
Start
2.
Create a new node N.
3.
Set N.next = Head.
4.
If Head ≠ NULL, set Head.prev = N.
5.
Update Head = N.
6.
Set N.prev = NULL.
7.
End
b) Insert in the Middle
Input: Doubly linked list L, position pos, and a node N.
Output: Updated list with N inserted at position pos.
Algorithm:
1.
Start
2.
Traverse to position pos - 1.
3.
Create a new node N.
4.
Set N.next = Current.next.
5.
Set N.prev = Current.
6.
If Current.next ≠ NULL, update Current.next.prev = N.
7.
Update Current.next = N.
8.
End
c) Insert at the End
Input: Doubly linked list L and a node N.
Output: Updated list with N at the end.
Algorithm:
1.
Start
2.
Traverse to the last node.
3.
Create a new node N.
4.
Set Last.next = N.
5.
Set N.prev = Last.
6.
Update N.next = NULL.
7.
End
d) Insert in an Empty List
Input: An empty DLL and a node N.
Output: List with N as the only node.
Algorithm:
1.
Start
2.
Create a new node N.
3.
Set Head = N.
4.
Update N.next = NULL and N.prev = NULL.
5.
End
2. Deletion in Doubly Linked List
a) Delete from the Beginning
Algorithm:
1.
Start
2.
If Head == NULL, print "Underflow" and exit.
3.
Update Head = Head.next.
4.
Set Head.prev = NULL.
5.
End
b) Delete from the Middle
Algorithm:
1.
Start
2.
Traverse to position pos.
3.
Set Current.prev.next = Current.next.
4.
If Current.next ≠ NULL, set Current.next.prev = Current.prev.
5.
Delete Current.
6.
End
c) Delete from the End
Algorithm:
1.
Start
2.
Traverse to the last node.
3.
Set Last.prev.next = NULL.
4.
Delete Last.
5.
End
d) Delete from an Empty List
Algorithm:
1.
Start
2.
If Head == NULL, print "Underflow" and exit.
3.
End
B. Circular Linked List (CLL)
1. Insertion in Circular Linked List
a) Insert at the Beginning
Algorithm:
1.
Start
2.
Create a new node N.
3.
If Head == NULL:
a. Set N.next = N.
b. Set Head = N.
4.
Else:
a. Traverse to the last node.
b. Set N.next = Head.
c. Set Last.next = N.
d. Update Head = N.
5.
End
b) Insert in the Middle
Algorithm:
1.
Start
2.
Traverse to position pos - 1.
3.
Create a new node N.
4.
Set N.next = Current.next.
5.
Update Current.next = N.
6.
End
c) Insert at the End
Algorithm:
1.
Start
2.
Create a new node N.
3.
Traverse to the last node.
4.
Set Last.next = N.
5.
Update N.next = Head.
6.
End
d) Insert in an Empty List
Algorithm:
1.
Start
2.
Create a new node N.
3.
Set N.next = N.
4.
Update Head = N.
5.
End
2. Deletion in Circular Linked List
a) Delete from the Beginning
Algorithm:
1.
Start
2.
If Head == NULL, print "Underflow" and exit.
3.
Traverse to the last node.
4.
Set Head = Head.next.
5.
Update Last.next = Head.
6.
End
b) Delete from the Middle
Algorithm:
1.
Start
2.
Traverse to position pos - 1.
3.
Set Current.next = Current.next.next.
4.
End
c) Delete from the End
Algorithm:
1.
Start
2.
Traverse to the second last node.
3.
Update Current.next = Head.
4.
End
d) Delete from an Empty List
Algorithm:
1.
Start
2.
If Head == NULL, print "Underflow" and exit.
3.
End
8. Write an algorithm for following operations a) To reverse a singly linked list. b) To merge two sorted linked lists into a third sorted list.
Algorithms for Linked List Operations
A) Reverse a Singly Linked List
Input: A singly linked list L with n nodes.
Output: Reversed linked list.
Algorithm:
1.
Start
2.
Initialize three pointers:
Prev = NULL
Current = Head
Next = NULL
4.
Repeat until Current != NULL:
a. Set Next = Current.next.
b. Update Current.next = Prev.
c. Move Prev = Current.
d. Move Current = Next.
5.
Update Head = Prev.
6.
End
B) Merge Two Sorted Linked Lists into a Third Sorted List
Input: Two sorted linked lists L1 and L2.
Output: A third sorted linked list L3.
Algorithm:
1.
Start
2.
Create a dummy node Dummy and set Tail = Dummy.
3.
Repeat until either L1 or L2 is NULL:
a. If L1.data ≤ L2.data:
Set Tail.next = L1.
Move L1 = L1.next.
b. Else:
Set Tail.next = L2.
Move L2 = L2.next.
c. Move Tail = Tail.next.
5.
Attach the remaining nodes of the non-empty list:
a. If L1 ≠ NULL, set Tail.next = L1.
b. If L2 ≠ NULL, set Tail.next = L2.
6.
Return Dummy.next as the head of the merged list.
7.
End
9. Let A and B be two sorted linked list. Write an algorithm to create a third linked list C, which will have the elements from both A and B but in a
sorted manner. If you run out of the elements of one list, then append the remaining elements of other list in C.
Algorithm
1.
Start
2.
Create a dummy node Dummy and initialize Tail = Dummy.
3.
While both A ≠ NULL and B ≠ NULL:
a. If A.data ≤ B.data:
Set Tail.next = A.
Move A = A.next.
b. Else:
Set Tail.next = B.
Move B = B.next.
c. Move Tail = Tail.next.
5.
Append remaining elements:
a. If A ≠ NULL:
Set Tail.next = A.
b. If B ≠ NULL:
Set Tail.next = B.
7.
Return Dummy.next as the head of the merged list C.
8.
End
10. Write an algorithms to perform stack operations (push, pop, peek, and traverse) using arrays and linked lists.
A. Stack Operations Using Arrays
A stack is a data structure that follows the Last In First Out (LIFO) principle. Using an array, the stack operations are performed as follows:
1. Push Operation (Insert element into stack)
Input: A stack S implemented using an array, an element x.
Output: Stack S with the element x added.
Algorithm:
1.
Start
2.
If the stack is full (i.e., index top == max_size - 1), print "Stack Overflow" and exit.
3.
Increment the top index by 1.
4.
Set S[top] = x.
5.
End
2. Pop Operation (Remove element from stack)
Input: A stack S implemented using an array.
Output: The element removed from the stack.
Algorithm:
1.
Start
2.
If the stack is empty (i.e., top == -1), print "Stack Underflow" and exit.
3.
Set element = S[top].
4.
Decrement the top index by 1.
5.
Return element.
6.
End
3. Peek Operation (View top element of stack)
Input: A stack S implemented using an array.
Output: The top element of the stack.
Algorithm:
1.
Start
2.
If the stack is empty (i.e., top == -1), print "Stack is empty" and exit.
3.
Return S[top].
4.
End
4. Traverse Operation (View all elements in the stack)
Input: A stack S implemented using an array.
Output: All elements in the stack.
Algorithm:
1.
Start
2.
If the stack is empty (i.e., top == -1), print "Stack is empty" and exit.
3.
For i = top to 0 (from top to bottom):
Print S[i].
5.
End
B. Stack Operations Using Linked Lists
In a linked list-based stack, each node holds an element and a reference to the next node in the stack.
1. Push Operation (Insert element into stack)
Input: A stack S implemented using a linked list, an element x.
Output: Stack S with the element x added.
Algorithm:
1.
Start
2.
Create a new node new_node with data x.
3.
Set new_node.next = Head (link it to the current top).
4.
Set Head = new_node.
5.
End
2. Pop Operation (Remove element from stack)
Input: A stack S implemented using a linked list.
Output: The element removed from the stack.
Algorithm:
1.
Start
2.
If the stack is empty (i.e., Head == NULL), print "Stack Underflow" and exit.
3.
Set element = Head.data.
4.
Set Head = Head.next (move the top to the next node).
5.
Return element.
6.
End
3. Peek Operation (View top element of stack)
Input: A stack S implemented using a linked list.
Output: The top element of the stack.
Algorithm:
1.
Start
2.
If the stack is empty (i.e., Head == NULL), print "Stack is empty" and exit.
3.
Return Head.data.
4.
End
4. Traverse Operation (View all elements in the stack)
Input: A stack S implemented using a linked list.
Output: All elements in the stack.
Algorithm:
1.
Start
2.
If the stack is empty (i.e., Head == NULL), print "Stack is empty" and exit.
3.
Set Current = Head.
4.
While Current != NULL:
Print Current.data.
Set Current = Current.next.
6.
End
11. Write an algorithms to perform all operations on queue and linked queue.
A. Queue Operations Using Array
For an array-based queue, we'll maintain an array Q and two pointers: front (points to the first element) and rear (points to the last element).
1. Enqueue Operation (Insert element into queue)
Input: A queue Q implemented using an array, an element x.
Output: Queue Q with the element x added at the rear.
Algorithm:
1.
Start
2.
If the queue is full (i.e., rear == max_size - 1), print "Queue Overflow" and exit.
3.
Increment rear by 1.
4.
Set Q[rear] = x.
5.
If the queue was empty (i.e., front == -1), set front = 0.
6.
End
2. Dequeue Operation (Remove element from queue)
Input: A queue Q implemented using an array.
Output: The element removed from the front of the queue.
Algorithm:
1.
Start
2.
If the queue is empty (i.e., front == -1), print "Queue Underflow" and exit.
3.
Set element = Q[front].
4.
If front == rear, set front = rear = -1 (queue is empty).
5.
Else, increment front by 1.
6.
Return element.
7.
End
3. Peek Operation (View front element of queue)
Input: A queue Q implemented using an array.
Output: The front element of the queue.
Algorithm:
1.
Start
2.
If the queue is empty (i.e., front == -1), print "Queue is empty" and exit.
3.
Return Q[front].
4.
End
4. Traverse Operation (View all elements in the queue)
Input: A queue Q implemented using an array.
Output: All elements in the queue from front to rear.
Algorithm:
1.
Start
2.
If the queue is empty (i.e., front == -1), print "Queue is empty" and exit.
3.
For i = front to rear:
Print Q[i].
5.
End
B. Queue Operations Using Linked List
For a linked list-based queue, we use a singly linked list where each node contains an element and a reference to the next node. We'll maintain
two pointers: front (points to the first node) and rear (points to the last node).
1. Enqueue Operation (Insert element into queue)
Input: A queue Q implemented using a linked list, an element x.
Output: Queue Q with the element x added at the rear.
Algorithm:
1.
Start
2.
Create a new node new_node with data x and new_node.next = NULL.
3.
If the queue is empty (i.e., front == NULL):
Set front = rear = new_node.
5.
Else:
Set rear.next = new_node.
Update rear = new_node.
7.
End
2. Dequeue Operation (Remove element from queue)
Input: A queue Q implemented using a linked list.
Output: The element removed from the front of the queue.
Algorithm:
1.
Start
2.
If the queue is empty (i.e., front == NULL), print "Queue Underflow" and exit.
3.
Set element = front.data.
4.
Update front = front.next.
5.
If front == NULL, set rear = NULL (queue is now empty).
6.
Return element.
7.
End
3. Peek Operation (View front element of queue)
Input: A queue Q implemented using a linked list.
Output: The front element of the queue.
Algorithm:
1.
Start
2.
If the queue is empty (i.e., front == NULL), print "Queue is empty" and exit.
3.
Return front.data.
4.
End
4. Traverse Operation (View all elements in the queue)
Input: A queue Q implemented using a linked list.
Output: All elements in the queue from front to rear.
Algorithm:
1.
Start
2.
If the queue is empty (i.e., front == NULL), print "Queue is empty" and exit.
3.
Set current = front.
4.
While current != NULL:
Print current.data.
Set current = current.next.
6.
End
12. Write the array representation of a tree in memory with proper example
Array Representation of a Tree in Memory
In an array-based representation of a binary tree, the tree is stored in an array where each element corresponds to a node in the tree. The
position of each node in the array is determined by the following rules:
Root is at index 0.
For any node at index i:
The left child is at index 2*i + 1.
The right child is at index 2*i + 2.
The parent is at index (i - 1) / 2 (integer division).
This method works well for complete binary trees or binary trees that are mostly balanced, as there are no gaps in the array representation.
Example
Consider the following binary tree:
markdown
/ \
2 3
/\ /\
4 56 7
Step-by-Step Array Representation
1.
Node 1 (Root): The root node 1 is at index 0.
2.
Node 2 (Left Child of 1): The left child of 1 is 2, which is at index 2*0 + 1 = 1.
3.
Node 3 (Right Child of 1): The right child of 1 is 3, which is at index 2*0 + 2 = 2.
4.
Node 4 (Left Child of 2): The left child of 2 is 4, which is at index 2*1 + 1 = 3.
5.
Node 5 (Right Child of 2): The right child of 2 is 5, which is at index 2*1 + 2 = 4.
6.
Node 6 (Left Child of 3): The left child of 3 is 6, which is at index 2*2 + 1 = 5.
7.
Node 7 (Right Child of 3): The right child of 3 is 7, which is at index 2*2 + 2 = 6.
Array Representation
Thus, the tree will be represented as:
csharp
Copy code
[1, 2, 3, 4, 5, 6, 7]
14. Create a binary search tree for given values and write recursive algorithms for insertion and searching. Print in-order , pre-order, post-order
traversals.
2. Recursive Algorithms for Insertion and Searching
a) Recursive Insertion in a BST
Algorithm:
1.
If the tree is empty, create a new node with the given value.
2.
If the value to insert is smaller than the current node, recursively insert into the left subtree.
3.
If the value to insert is greater than the current node, recursively insert into the right subtree.
Algorithm (Pseudocode):
plaintext
Copy code
Function Insert(root, value):
If root is NULL:
Return new Node(value)
If value < root.data:
root.left = Insert(root.left, value)
Else:
root.right = Insert(root.right, value)
Return root
b) Recursive Search in a BST
Algorithm:
1.
If the tree is empty, return NULL (value not found).
2.
If the value matches the current node, return the node.
3.
If the value is smaller, recursively search the left subtree.
4.
If the value is greater, recursively search the right subtree.
Algorithm (Pseudocode):
plaintext
Copy code
Function Search(root, value):
If root is NULL:
Return NULL
If root.data == value:
Return root
If value < root.data:
Return Search(root.left, value)
Else:
Return Search(root.right, value)
3. Tree Traversals
a) In-order Traversal (Left, Root, Right)
In this traversal, we visit the left subtree, the root node, and then the right subtree.
Algorithm:
plaintext
Copy code
Function InOrder(root):
If root is NULL:
Return
InOrder(root.left)
Print root.data
InOrder(root.right)
In-order Traversal of the Tree:
20, 30, 40, 50, 60, 70, 80
b) Pre-order Traversal (Root, Left, Right)
In this traversal, we visit the root node first, then the left subtree, and finally the right subtree.
Algorithm:
plaintext
Copy code
Function PreOrder(root):
If root is NULL:
Return
Print root.data
PreOrder(root.left)
PreOrder(root.right)
Pre-order Traversal of the Tree:
50, 30, 20, 40, 70, 60, 80
c) Post-order Traversal (Left, Right, Root)
In this traversal, we visit the left subtree, then the right subtree, and finally the root node.
Algorithm:
plaintext
Copy code
Function PostOrder(root):
If root is NULL:
Return
PostOrder(root.left)
PostOrder(root.right)
Print root.data
Post-order Traversal of the Tree:
20, 40, 30, 60, 80, 70, 50
15. Create a binary search tree for given values and write recursive algorithms for deletion and balancing process.
Binary Search Tree (BST) Operations: Deletion and Balancing
1. Create a Binary Search Tree for Given Values
Let's use the same set of values: [50, 30, 20, 40, 70, 60, 80]
BST Structure:
markdown
Copy code
50
/ \
30 70
/ \ / \
20 40 60 80
2. Recursive Deletion in a BST
Deletion Cases:
1.
Node to delete has no children (leaf node): Simply remove the node.
2.
Node to delete has one child: Replace the node with its child.
3.
Node to delete has two children: Find the in-order successor (smallest node in the right subtree) or in-order predecessor (largest node in the
left subtree), replace the node with the successor/predecessor, and delete the successor/predecessor recursively.
Algorithm (Pseudocode):
plaintext
Copy code
Function Delete(root, value):
If root is NULL:
Return NULL
If value < root.data:
root.left = Delete(root.left, value)
ElseIf value > root.data:
root.right = Delete(root.right, value)
Else:
If root.left is NULL:
Return root.right
ElseIf root.right is NULL:
Return root.left
Else:
successor = FindMin(root.right)
root.data = successor.data
root.right = Delete(root.right, successor.data)
Return root
3. Balancing a BST (AVL Tree Approach)
Balancing Factor:
The balance factor of a node is the height difference between the left and right subtrees.
If the balance factor is > 1, the tree is left-heavy (requires right rotation).
If the balance factor is < -1, the tree is right-heavy (requires left rotation).
Algorithm (Pseudocode):
plaintext
Copy code
Function Balance(root):
If root is NULL:
Return NULL
root.left = Balance(root.left)
root.right = Balance(root.right)
balance_factor = Height(root.left) - Height(root.right)
If balance_factor > 1:
If Height(root.left.left) > Height(root.left.right):
root = RightRotate(root)
Else:
root.left = LeftRotate(root.left)
root = RightRotate(root)
If balance_factor < -1:
If Height(root.right.right) > Height(root.right.left):
root = LeftRotate(root)
Else:
root.right = RightRotate(root.right)
root = LeftRotate(root)
Return root
16. For the given BST, Write a recursive algorithm to a) Count the total number of nodes in a BST. b) Find smallest node of a BST c) Find largest
node of a BST
Recursive Algorithms for Binary Search Tree (BST)
a) Count the Total Number of Nodes in a BST
Algorithm:
1.
If the root is NULL, return 0.
2.
Recursively count the nodes in the left subtree.
3.
Recursively count the nodes in the right subtree.
4.
Total nodes = 1 (current node) + left subtree count + right subtree count.
plaintext
Copy code
Function CountNodes(root):
If root is NULL:
Return 0
Return 1 + CountNodes(root.left) + CountNodes(root.right)
b) Find the Smallest Node in a BST
Algorithm:
1.
Start from the root.
2.
Keep traversing the left child until you reach a NULL left child.
3.
The node at the end is the smallest.
plaintext
Copy code
Function FindMin(root):
If root is NULL:
Return NULL
If root.left is NULL:
Return root
Return FindMin(root.left
c) Find the Largest Node in a BST
Algorithm:
1.
Start from the root.
2.
Keep traversing the right child until you reach a NULL right child.
3.
The node at the end is the largest.
plaintext
Copy code
Function FindMax(root):
If root is NULL:
Return NULL
If root.right is NULL:
Return root
Return FindMax(root.right)
17. Explain the representation of a graph in a memory with a proper example
Graph Representation in Memory Graphs can be represented in memory using two common methods: Adjacency Matrix and Adjacency List.
1. Adjacency Matrix:
A 2D matrix where rows and columns represent the vertices of the graph.
If there is an edge between vertex i and vertex j, the element at matrix position [i][j] is marked (usually with a 1 or the edge weight). If no
edge exists, it's marked as 0 or infinity (for weighted graphs).
Works well for dense graphs.
Example: Consider the following graph:
markdown
Copy code
/ \
0 2
\ /
Adjacency Matrix:
Css
0 1 2 3
0 [0, 1, 0, 1]
1 [1, 0, 1, 0]
2 [0, 1, 0, 1]
3 [1, 0, 1, 0]
2. Adjacency List:
An array of lists (or a hash map), where each list stores the neighbors of a vertex.
Each vertex has a list containing all its adjacent vertices.
Works well for sparse graphs.
Example (using the same graph as above):
markdown
Copy code
/ \
0 2
\ /
Adjacency List:
makefile
0: [1, 3]
1: [0, 2]
2: [1, 3]
3: [0, 2]
18. Write recursive algorithms for in-order, pre-order, and post-order traversals of a binary search tree.
Recursive Algorithms for Binary Search Tree (BST) Traversals
Given a Binary Search Tree (BST), here are the recursive algorithms for in-order, pre-order, and post-order traversals:
1. In-order Traversal (Left, Root, Right)
Algorithm:
1.
Traverse the left subtree.
2.
Visit the root node.
3.
Traverse the right subtree.
Recursive Algorithm:
plaintext
Copy code
Function InOrder(root):
If root is NULL:
Return
InOrder(root.left) // Traverse left subtree
Print root.data // Visit root node
InOrder(root.right) // Traverse right subtree
2. Pre-order Traversal (Root, Left, Right)
Algorithm:
1.
Visit the root node.
2.
Traverse the left subtree.
3.
Traverse the right subtree.
Recursive Algorithm:
plaintext
Copy code
Function PreOrder(root):
If root is NULL:
Return
Print root.data // Visit root node
PreOrder(root.left) // Traverse left subtree
PreOrder(root.right) // Traverse right subtree
3. Post-order Traversal (Left, Right, Root)
Algorithm:
1.
Traverse the left subtree.
2.
Traverse the right subtree.
3.
Visit the root node.
Recursive Algorithm:
plaintext
Copy code
Function PostOrder(root):
If root is NULL:
Return
PostOrder(root.left) // Traverse left subtree
PostOrder(root.right) // Traverse right subtree
Print root.data // Visit root node
19. Write an algorithm to perform breadth-first search (BFS) and depth-first search (DFS) on a given graph.
Breadth-First Search (BFS) and Depth-First Search (DFS) Algorithms
Given a graph with vertices and edges, here are the algorithms to perform Breadth-First Search (BFS) and Depth-First Search (DFS).
1. Breadth-First Search (BFS) BFS explores all neighbors of a node before moving to the next level of nodes. It uses a queue for traversal.
Algorithm:
1.
Start with the source node, mark it as visited, and enqueue it.
2.
While the queue is not empty:
Dequeue a node and print it.
For each unvisited neighbor of the node, mark it as visited and enqueue it.
Pseudocode
Function BFS(graph, start):
Create a queue Q
Create a set visited to keep track of visited nodes
Enqueue start node into Q
Mark start node as visited
While Q is not empty:
current = Dequeue from Q
Print current (or process current node)
For each neighbor of current in graph:
If neighbor is not visited:
Enqueue neighbor into Q
Mark neighbor as visited
mathematica
Copy code
A -- B -- D
| |
C -- E
BFS Traversal from A:
A B C D E
2. Depth-First Search (DFS)
DFS explores as far as possible along a branch before backtracking. It can be implemented using recursion or a stack.
DFS (Recursive)
Algorithm:
1.
Start with the source node, mark it as visited.
2.
Recursively visit all unvisited neighbors of the current node.
Function DFS(graph, node, visited):
Mark node as visited
Print node (or process the node)
For each neighbor of node in graph:
If neighbor is not visited:
DFS(graph, neighbor, visited)
DFS (Using Stack)
Algorithm:
1.
Start with the source node, mark it as visited, and push it onto the stack.
2.
While the stack is not empty:
Pop a node from the stack and print it.
For each unvisited neighbor of the node, mark it as visited and push it onto the stack.
Function DFS(graph, start):
Create a stack S
Create a set visited to keep track of visited nodes
Push start node onto S
Mark start node as visited
While S is not empty:
current = Pop from S
Print current (or process current node)
For each neighbor of current in graph:
If neighbor is not visited:
Push neighbor onto S
Mark neighbor as visited
20. Explain the memory representation of a graph with examples
Memory Representation of a Graph
Graphs can be represented in memory using two common methods: Adjacency Matrix and Adjacency List.
1. Adjacency Matrix:
A 2D array (matrix) where each row and column represent a vertex.
If there is an edge between vertex i and vertex j, matrix[i][j] is marked (1 for unweighted, or the edge weight for weighted graphs).
Suitable for dense graphs.
Example:Graph:
A -- B -- D
| |
C -- E
Adjacency Matrix:
ABCDE
A[01100]
B[10011]
C[10001]
D[01000]
E[01100]
2. Adjacency List:
An array (or linked list) of lists, where each list stores the neighbors of a vertex.
Suitable for sparse graphs.
Example:
mathematica
Copy code
Graph:
A -- B -- D
| |
C -- E
Adjacency List:
A: [B, C]
B: [A, D, E]
C: [A, E]
D: [B]
E: [B, C]
a) Write an algorithm to calculate sum of data of alternate nodes of doubly linked list. Algorithm:
SumOfAlternateNodes
Input: Head node of a doubly linked list
1. Initialize a variable sum to 0.
2. Set a flag variable isAlternate to true.
3. Traverse the doubly linked list:
a. If isAlternate is true, add the data of the current node to the sum.
b. Toggle the value of isAlternate.
c. Move to the next node.
4. The sum now contains the sum of data of alternate nodes in the doubly linked list.
Pseudocode:
Algorithm SumOfAlternateNodes(head): // Step 1 sum = 0 // Step 2 isAlternate = true //
Step 3 current = head while current is not null: //
Step 3 a if isAlternate: sum += current.data //
Step 3b isAlternate = not isAlternate //
Step 3c current = current.next // Step 4 return sum