0% found this document useful (0 votes)
46 views26 pages

DSA Program

The document discusses implementations of common data structures in JavaScript including stacks, queues, priority queues, circular queues, and singly linked lists. It provides class definitions and methods to perform operations like push, pop, enqueue, dequeue, peek, isEmpty etc. on each data structure. Examples are given to demonstrate how to use the classes and methods to add/remove elements and check properties.

Uploaded by

Varuna Nikam
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
46 views26 pages

DSA Program

The document discusses implementations of common data structures in JavaScript including stacks, queues, priority queues, circular queues, and singly linked lists. It provides class definitions and methods to perform operations like push, pop, enqueue, dequeue, peek, isEmpty etc. on each data structure. Examples are given to demonstrate how to use the classes and methods to add/remove elements and check properties.

Uploaded by

Varuna Nikam
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

Q1. Write a javaScript program to implement stack using arrays.

class Stack {
constructor() {
this.items = [];
}
push(element) {
this.items.push(element);
}
pop() {
if (this.isEmpty()) {
return "Underflow";
}
return this.items.pop();
}
peek() {
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
}
size() {
return this.items.length;
}
printStack() {
let result = "";
for (let i = 0; i < this.items.length; i++) {
result += this.items[i] + " ";
}
return result.trim();
} }
let stack = new Stack();
stack.push(10); stack.push(20); stack.push(30);
console.log("Stack after push operations:", stack.printStack()); // Output: 10 20 30
console.log("Popped element:", stack.pop()); // Output: 30
console.log("Stack after pop operation:", stack.printStack()); // Output: 10 20
console.log("Top element:", stack.peek()); // Output: 20
console.log("Is the stack empty?", stack.isEmpty()); // Output: false
console.log("Size of the stack:", stack.size()); // Output: 2
Q2. Write a javaScript program to implement queue using arrays.
class Queue {
constructor() {
this.items = [];
}
enqueue(element) {
this.items.push(element);
}
dequeue() {
if (this.isEmpty()) {
return "Underflow";
}
return this.items.shift();
}
front() {
if (this.isEmpty()) {
return "Queue is empty";
}
return this.items[0];
}
isEmpty() {
return this.items.length === 0;
}
size() {
return this.items.length;
}
printQueue() {
let result = "";
for (let i = 0; i < this.items.length; i++) {
result += this.items[i] + " ";
}
return result.trim();
} }
let queue = new Queue();
queue.enqueue(10); queue.enqueue(20); queue.enqueue(30);
console.log("Queue after enqueue operations:", queue.printQueue()); // Output: 10 20 30
console.log("Dequeued element:", queue.dequeue()); // Output: 10
console.log("Queue after dequeue operation:", queue.printQueue()); // Output: 20 30
console.log("Front element:", queue.front()); // Output: 20
console.log("Is the queue empty?", queue.isEmpty()); // Output: false
console.log("Size of the queue:", queue.size()); // Output: 2
Q3. Write a javaScript program implement the following Stack applications
a) infix into postfix
class Stack {
constructor() {
this.items = [];
}
push(element) {
this.items.push(element);
}
pop() {
if (this.isEmpty()) {
return "Underflow";
}
return this.items.pop();
}
peek() {
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
} }
function isOperator(char) {
return ['+', '-', '*', '/'].includes(char);
}
function precedence(operator) {
switch (operator) {
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
return 0;
} }
function infixToPostfix(infixExpression) {
let stack = new Stack();
let postfix = "";
for (let i = 0; i < infixExpression.length; i++) {
let char = infixExpression[i];
if (/[a-zA-Z0-9]/.test(char)) {
postfix += char;
} else if (char === '(') {
stack.push(char);
} else if (char === ')') {
while (!stack.isEmpty() && stack.peek() !== '(') {
postfix += stack.pop();
}
stack.pop(); // Pop '('
} else if (isOperator(char)) {
while (!stack.isEmpty() && precedence(stack.peek()) >= precedence(char)) {
postfix += stack.pop();
}
stack.push(char);
}
}
while (!stack.isEmpty()) {
postfix += stack.pop();
}
return postfix;
}
let infixExpression = "a+b*(c-d)/e";
let postfixExpression = infixToPostfix(infixExpression);
console.log("Infix Expression:", infixExpression);
console.log("Postfix Expression:", postfixExpression);

b) Evaluation of the postfix expression


class Stack {
constructor() {
this.items = [];
}
push(element) {
this.items.push(element);
}
pop() {
if (this.isEmpty()) {
return "Underflow";
}
return this.items.pop();
}
peek() {
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
} }
function evaluatePostfix(expression) {
let stack = new Stack();
for (let i = 0; i < expression.length; i++) {
let char = expression[i];
if (!isNaN(char)) {
stack.push(Number(char));
} else {
let operand2 = stack.pop();
let operand1 = stack.pop();
switch (char) {
case '+':
stack.push(operand1 + operand2);
break;
case '-':
stack.push(operand1 - operand2);
break;
case '*':
stack.push(operand1 * operand2);
break;
case '/':
stack.push(operand1 / operand2);
break;
} } }
return stack.pop();
}// Example usage:
let postfixExpression = "23*5+";
let result = evaluatePostfix(postfixExpression);
console.log("Result of postfix expression", postfixExpression, ":", result); // Output: 11
Q4. Write a JavaScript program to implement the following types of queues
a) Priority queue
class PriorityQueue {
constructor() {
this.items = [];
}
enqueue(element, priority) {
let queueElement = { element, priority };
let added = false;
for (let i = 0; i < this.items.length; i++) {
if (queueElement.priority < this.items[i].priority) {
this.items.splice(i, 0, queueElement);
added = true;
break;
} }
if (!added) {
this.items.push(queueElement);
} }
dequeue() {
return this.items.shift();
}
peek() {
return this.items[0];
}
isEmpty() {
return this.items.length === 0;
}
size() {
return this.items.length;
} }// Example usage:
let priorityQueue = new PriorityQueue();
priorityQueue.enqueue("Task 1", 2); priorityQueue.enqueue("Task 2", 1);
priorityQueue.enqueue("Task 3", 3);

console.log("Dequeued task:", priorityQueue.dequeue()); // Output: { element: 'Task


2', priority: 1 }
console.log("Front task:", priorityQueue.peek()); // Output: { element: 'Task 1',
priority: 2 }
console.log("Is the priority queue empty?", priorityQueue.isEmpty()); // Output: false
console.log("Size of the priority queue:", priorityQueue.size()); // Output: 2

b) Circular queue
class CircularQueue {
constructor(size) {
this.size = size;
this.queue = new Array(size).fill(null);
this.front = -1;
this.rear = -1;
}
enqueue(element) {
if ((this.rear + 1) % this.size === this.front) {
console.log("Queue is full. Cannot enqueue element:", element);
} else {
if (this.isEmpty()) {
this.front = 0;
}
this.rear = (this.rear + 1) % this.size;
this.queue[this.rear] = element;
console.log("Enqueued element:", element);
} }
dequeue() {
if (this.isEmpty()) {
console.log("Queue is empty. Cannot dequeue.");
return null;
} else {
let removedElement = this.queue[this.front];
if (this.front === this.rear) {
this.front = -1;
this.rear = -1;
} else {
this.front = (this.front + 1) % this.size;
}
console.log("Dequeued element:", removedElement);
return removedElement;
} }
peek() {
if (this.isEmpty()) {
console.log("Queue is empty. Cannot peek.");
return null;
} else {
return this.queue[this.front];
} }
isEmpty() {
return this.front === -1 && this.rear === -1;
}
isFull() {
return (this.rear + 1) % this.size === this.front;
}
display() {
if (this.isEmpty()) {
console.log("Queue is empty.");
} else {
let result = "Queue elements: ";
let i = this.front;
while (i !== this.rear) {
result += this.queue[i] + " ";
i = (i + 1) % this.size;
}
result += this.queue[this.rear];
console.log(result);
} } } // Example usage:
let circularQueue = new CircularQueue(5);
circularQueue.enqueue(1); circularQueue.enqueue(2); circularQueue.enqueue(3);
circularQueue.display(); // Output: Queue elements: 1 2 3
circularQueue.dequeue();circularQueue.display(); // Output: Queue elements: 2 3
circularQueue.enqueue(4); circularQueue.enqueue(5);
circularQueue.enqueue(6); // Output: Queue is full. Cannot enqueue element: 6
console.log("Front element:", circularQueue.peek()); // Output: Front element: 2
Q5 Write a JavaScript program to implement the Singly Linked List
class Node {
constructor(data) {
this.data = data;
this.next = null;
}}
class SinglyLinkedList {
constructor() {
this.head = null;
}
append(data) {
let newNode = new Node(data);
if (!this.head) {
this.head = newNode;
return;
}
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = newNode;
}
prepend(data) {
let newNode = new Node(data);
newNode.next = this.head;
this.head = newNode;
}
delete(data) {
if (!this.head) {
return;
}
if (this.head.data === data) {
this.head = this.head.next;
return; }

let current = this.head;


while (current.next && current.next.data !== data) {
current = current.next;
}
if (current.next) {
current.next = current.next.next;
} }
search(data) {
let current = this.head;
while (current) {
if (current.data === data) {
return true;
}
current = current.next;
}
return false;
}
display() {
let result = [];
let current = this.head;
while (current) {
result.push(current.data);
current = current.next;
}
console.log("Linked List:", result.join(" -> "));
} }
let linkedList = new SinglyLinkedList();
linkedList.append(1); linkedList.append(2); linkedList.append(3);
linkedList.display(); // Output: Linked List: 1 -> 2 -> 3
linkedList.prepend(0); linkedList.display(); // Output: Linked List: 0 -> 1 -> 2 -> 3
linkedList.delete(2); linkedList.display(); // Output: Linked List: 0 -> 1 -> 3
console.log("Is 2 in the linked list?", linkedList.search(2)); // Output: Is 2 in the linked
list? false
Q6. Write a JavaScript program to implement the doubly Linked List
Mc class Node {
constructor(data) {
this.data = data;
this.next = null;
this.prev = null;
} }
class DoublyLinkedList {
constructor() {
this.head = null;
this.tail = null;
} // Insert a new node at the end of the doubly linked list
append(data) {
let newNode = new Node(data);

if (!this.head) {
this.head = newNode;
this.tail = newNode;
} else {
newNode.prev = this.tail;
this.tail.next = newNode;
this.tail = newNode;
} } // Insert a new node at the beginning of the doubly linked list
prepend(data) {
let newNode = new Node(data);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
} else {
newNode.next = this.head;
this.head.prev = newNode;
this.head = newNode;
} } // Delete a node with the given data from the doubly linked list
delete(data) {
let current = this.head;
while (current) {
if (current.data === data) {
if (current.prev) {
current.prev.next = current.next;
} else {
this.head = current.next;
}
if (current.next) {
current.next.prev = current.prev;
} else {
this.tail = current.prev;
}
return;
} current = current.next;
} } // Search for a node with the given data in the doubly linked list
search(data) {
let current = this.head;
while (current) {
if (current.data === data) {
return true;
}
current = current.next;
}
return false;
} // Display the elements of the doubly linked list
display() {
let result = [];
let current = this.head;
while (current) {
result.push(current.data);
current = current.next;
} console.log("Doubly Linked List:", result.join(" <-> "));
} }// Example usage:
let doublyLinkedList = new DoublyLinkedList();
doublyLinkedList.append(1); doublyLinkedList.append(2); doublyLinkedList.append(3);
doublyLinkedList.display(); // Output: Doubly Linked List: 1 <-> 2 <-> 3
doublyLinkedList.prepend(0);
doublyLinkedList.display(); // Output: Doubly Linked List: 0 <-> 1 <-> 2 <-> 3
doublyLinkedList.delete(2);
doublyLinkedList.display(); // Output: Doubly Linked List: 0 <-> 1 <-> 3
console.log("Is 2 in the doubly linked list?", doublyLinkedList.search(2)); // Output: Is 2 in
the doubly linked list? False
Q7. Write a javaScript program to implement the following search algorithms.
i) Linear search
function linearSearch(arr, target) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === target) {
return i; // Return the index if the target is found
} }
return -1; // Return -1 if the target is not found
}// Example usage:
let array = [5, 2, 8, 1, 3, 7, 9, 4, 6];
let targetValue = 7;let result = linearSearch(array, targetValue);
if (result !== -1) {
console.log(`Target ${targetValue} found at index ${result}.`);
} else {
console.log(`Target ${targetValue} not found in the array.`);
}
ii). Binary search
// Binary Search function
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
let mid = Math.floor((left + right) / 2);
if (arr[mid] === target) {
return mid; // Element found, return its index
} else if (arr[mid] < target) {
left = mid + 1; // Adjust the search range to the right half
} else {
right = mid - 1; // Adjust the search range to the left half
} }
return -1; // Element not found
}// Example usage:
let sortedArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let targetElement = 6;
let result = binarySearch(sortedArray, targetElement);
if (result !== -1) {
console.log(`Element ${targetElement} found at index ${result}.`);
} else {
console.log(`Element ${targetElement} not found in the array.`);
}
ii) Fibonacci search
function fibonacciSearch(arr, x) {
let fibMMinus2 = 0;
let fibMMinus1 = 1;
let fib = fibMMinus1 + fibMMinus2;
// Find the smallest Fibonacci Number greater than or equal to the length of
the array
while (fib < arr.length) {
fibMMinus2 = fibMMinus1;
fibMMinus1 = fib;
fib = fibMMinus1 + fibMMinus2;
} let offset = -1;
while (fib > 1) {
let i = Math.min(offset + fibMMinus2, arr.length - 1);
if (arr[i] < x) {
fib = fibMMinus1;
fibMMinus1 = fibMMinus2;
fibMMinus2 = fib - fibMMinus1;
offset = i;
} else if (arr[i] > x) {
fib = fibMMinus2;
fibMMinus1 -= fibMMinus2;
fibMMinus2 = fib - fibMMinus1;
} else {
return i; // Element found
} } // Compare the last element with x
if (fibMMinus1 && arr[offset + 1] === x) {
return offset + 1;
} return -1; // Element not found
}// Example usage:
let sortedArray = [10, 22, 35, 40, 45, 50, 80, 82, 85, 90, 100];
let searchElement = 85;
let result = fibonacciSearch(sortedArray, searchElement);
if (result !== -1) {
console.log(`${searchElement} found at index ${result}`);
} else {
console.log(`${searchElement} not found in the array`);
}
Q8 Write a C program to implement the sorting algorithms.
bubbleSort
function bubbleSort(arr) {
const n = arr.length;
for (let i = 0; i < n - 1; i++) {
for (let j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// Swap arr[j] and arr[j+1]
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
} } }
return arr;
}// Example usage:
let arrayToSort = [64, 34, 25, 12, 22, 11, 90];
let sortedArrayBubbleSort = bubbleSort(arrayToSort.slice());
console.log("Bubble Sort Result:", sortedArrayBubbleSort);
mergeSort
function mergeSort(arr) {
if (arr.length <= 1) {
return arr;
}
const mid = Math.floor(arr.length / 2);
const left = mergeSort(arr.slice(0, mid));
const right = mergeSort(arr.slice(mid));
return merge(left, right);
}function merge(left, right) {
let result = [];
let i = 0;
let j = 0;
while (i < left.length && j < right.length) {
if (left[i] < right[j]) {
result.push(left[i]);
i++;
} else {
result.push(right[j]);
j++;
} } return result.concat(left.slice(i)).concat(right.slice(j));
}// Example usage:
let arrayToSortMergeSort = [64, 34, 25, 12, 22, 11, 90];
let sortedArrayMergeSort = mergeSort(arrayToSortMergeSort.slice());
console.log("Merge Sort Result:", sortedArrayMergeSort);

Q9 Write a javascriptprogram to implement binary tree using arrays and to perform


binary traversals. i) Inorder ii) preorder iii) post order
class BinaryTree {
constructor() {
this.tree = [];
} // Insert a node into the binary tree
insertNode(value) {
this.tree.push(value);
} // Inorder traversal
inorderTraversal(rootIndex) {
if (rootIndex < this.tree.length) {
// Left subtree
this.inorderTraversal(2 * rootIndex + 1);
// Root node
console.log(this.tree[rootIndex]);
// Right subtree
this.inorderTraversal(2 * rootIndex + 2);
} } // Preorder traversal
preorderTraversal(rootIndex) {
if (rootIndex < this.tree.length) {
// Root node
console.log(this.tree[rootIndex]);
// Left subtree
this.preorderTraversal(2 * rootIndex + 1);
// Right subtree
this.preorderTraversal(2 * rootIndex + 2);
} } // Postorder traversal
postorderTraversal(rootIndex) {
if (rootIndex < this.tree.length) {
// Left subtree
this.postorderTraversal(2 * rootIndex + 1);
// Right subtree
this.postorderTraversal(2 * rootIndex + 2);
// Root node
console.log(this.tree[rootIndex]);
} } }
// Example usage:
let binaryTree = new BinaryTree();// Insert nodes into the binary tree
binaryTree.insertNode(1); binaryTree.insertNode(2); binaryTree.insertNode(3);
binaryTree.insertNode(4); binaryTree.insertNode(5); binaryTree.insertNode(6);
console.log("Inorder Traversal:"); binaryTree.inorderTraversal(0);
console.log("\nPreorder Traversal:"); binaryTree.preorderTraversal(0);
console.log("\nPostorder Traversal:"); binaryTree.postorderTraversal(0);

Q10. Write a javascript program to balance a given tree


class TreeNode {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
} }
class BinaryTree {
constructor() {
this.root = null;
} // Insert a node into the binary search tree
insert(value) {
this.root = this._insert(this.root, value);
}
_insert(root, value) {
if (root === null) {
return new TreeNode(value);
}
if (value < root.value) {
root.left = this._insert(root.left, value);
} else {
root.right = this._insert(root.right, value);
}
return root;
} // Convert the binary search tree to a sorted array
toArray() {
const result = [];
this._inorderTraversal(this.root, (node) => result.push(node.value));
return result;
} inorderTraversal(root, callback) {
if (root !== null) {
this._inorderTraversal(root.left, callback);
callback(root);
this._inorderTraversal(root.right, callback);
} } // Convert a sorted array to a balanced binary search tree
balanceTree(sortedArray) {
this.root = this._balanceTree(sortedArray, 0, sortedArray.length - 1);
} _balanceTree(sortedArray, start, end) {
if (start > end) {
return null;
}
const mid = Math.floor((start + end) / 2);
const newNode = new TreeNode(sortedArray[mid]);
newNode.left = this._balanceTree(sortedArray, start, mid - 1);
newNode.right = this._balanceTree(sortedArray, mid + 1, end);
return newNode;
} // Inorder traversal for verification
inorderTraversal() {
const result = [];
this._inorderTraversal(this.root, (node) => result.push(node.value));
return result;
} }// Example usage:
let binarySearchTree = new BinaryTree();// Insert nodes into the binary search tree
binarySearchTree.insert(3); binarySearchTree.insert(1); binarySearchTree.insert(5);
binarySearchTree.insert(2); binarySearchTree.insert(4);
console.log("Original Inorder Traversal:", binarySearchTree.inorderTraversal());
// Convert the binary search tree to a sorted array
let sortedArray = binarySearchTree.toArray();
// Balance the tree using the sorted array
binarySearchTree.balanceTree(sortedArray);
console.log("Balanced Inorder Traversal:", binarySearchTree.inorderTraversal());

Q11. Write an algorithm to count number of nodes in singly linked list.


class Node {
constructor(data) {
this.data = data;
this.next = null;
} }
class SinglyLinkedList {
constructor() {
this.head = null;
} // Function to insert a node at the end of the linked list
append(data) {
let newNode = new Node(data);
if (!this.head) {
this.head = newNode;
return;
}
let current = this.head;
while (current.next) {
current = current.next;
} current.next = newNode;
} // Function to count the number of nodes in the linked list
countNodes() {
let count = 0;
let current = this.head;
while (current) {
count++;
current = current.next;
}
return count; } }
// Example usage:
let linkedList = new SinglyLinkedList();
// Insert nodes into the linked list
linkedList.append(1); linkedList.append(2);
linkedList.append(3); linkedList.append(4);
// Count the number of nodes
let numberOfNodes = linkedList.countNodes();
console.log("Number of nodes in the linked list:", numberOfNodes);
Q12. Write an algorithm delete element from linked list whose sum is equal to
zero.
class Node {
constructor(data) {
this.data = data;
this.next = null;
} }
class SinglyLinkedList {
constructor() {
this.head = null;
} // Function to insert a node at the end of the linked list
append(data) {
let newNode = new Node(data);
if (!this.head) {
this.head = newNode;
return;
}
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = newNode;
} // Function to delete elements whose sum is equal to zero
deleteElementsWithZeroSum() {
let dummy = new Node(0); // Dummy node to handle edge cases
dummy.next = this.head;
let current = dummy;
let sum = 0;
let seenSums = new Set();
while (current) {
sum += current.data;
if (seenSums.has(sum)) {
// The sum has been seen before, remove nodes from previous occurrence
let temp = seenSums;
let prev = dummy;
while (temp.has(sum)) {
prev = prev.next;
sum -= prev.data;
}
prev.next = current.next;
} else {
seenSums.add(sum);
current = current.next;
} }
this.head = dummy.next;
} // Function to display the linked list
display() {
let result = [];
let current = this.head;
while (current) {
result.push(current.data);
current = current.next;
}
console.log(result.join(" -> "));
} }// Example usage:
let linkedList = new SinglyLinkedList();
// Insert nodes into the linked list
linkedList.append(4); linkedList.append(2); linkedList.append(-3); linkedList.append(1);
linkedList.append(6); linkedList.append(-1); linkedList.append(-2);
console.log("Original Linked List:");
linkedList.display();
// Delete elements with zero sum
linkedList.deleteElementsWithZeroSum();
console.log("Linked List after deleting elements with zero sum:");
linkedList.display();
Algorithm: Delete Elements Whose Sum is Equal to Zero
Input: Head of the linked list
Output: Linked list with elements whose sum is not zero
1. Initialize a variable sum to 0.
2. Create a dummy node and set its next pointer to the head of the linked list.
3. Set a variable current to the dummy node.
4. Iterate through the linked list:
a. Add the data of the current node to the sum.
b. If the sum becomes zero, update the next pointer of the previous node to the next
pointer of the current node.
c. Move the current node to the next node.
5. Return the next pointer of the dummy node as the new head of the linked list.
Q13. Write on algorithm for knight’s Tour
class KnightTour {
constructor(boardSize) {
this.boardSize = boardSize;
this.board = Array.from({ length: boardSize }, () => Array(boardSize).fill(-1));
this.moveX = [2, 1, -1, -2, -2, -1, 1, 2];
this.moveY = [1, 2, 2, 1, -1, -2, -2, -1];
this.moveCount = 0;
}
isSafe(x, y) {
return x >= 0 && y >= 0 && x < this.boardSize && y < this.boardSize &&
this.board[x][y] === -1;
}
solveKT() {
this.board[0][0] = 0;
if (!this.solveKTUtil(0, 0, 1)) {
console.log("Solution does not exist");
} else {
this.printSolution();
} }
solveKTUtil(x, y, moveNumber) {
if (moveNumber === this.boardSize * this.boardSize) {
return true; // All squares are visited
} for (let i = 0; i < 8; i++) {
let nextX = x + this.moveX[i];
let nextY = y + this.moveY[i];
if (this.isSafe(nextX, nextY)) {
this.board[nextX][nextY] = moveNumber;
if (this.solveKTUtil(nextX, nextY, moveNumber + 1)) {
return true;
} else {
// Backtrack
this.board[nextX][nextY] = -1;
} } }
return false; // No valid moves from the current position
}
printSolution() {
for (let i = 0; i < this.boardSize; i++) {
let row = "";
for (let j = 0; j < this.boardSize; j++) {
row += this.board[i][j] + "\t";
} console.log(row);
} } }// Example usage:
const boardSize = 8;
const knightTour = new KnightTour(boardSize);
knightTour.solveKT();
Algorithm::-
Algorithm: Knight's Tour
Input: Size of the chessboard, starting position of the knight
Output: Solution matrix with the knight's tour path
1. Create a chessboard matrix of size n x n and initialize it with all zeros.
2. Set the initial position of the knight on the chessboard.
3. Call the recursive function KnightTour() with the current position and the chessboard.
4. Inside the recursive function KnightTour():
a. If all squares on the chessboard are visited (value is not zero), return true.
b. For each possible move of the knight:
i. Check if the move is within the chessboard and not visited.
ii. If true, mark the square as visited and make the move.
iii. If the move leads to a solution (recursive call returns true), return true.
iv. If the move does not lead to a solution, backtrack by marking the square as
unvisited.
c. If no move leads to a solution, return false.
5. Print the solution matrix.
Function KnightTour(position, chessboard):
a. If all squares on the chessboard are visited, return true.
b. For each possible move of the knight:
i. Check if the move is within the chessboard and not visited.
ii. If true, mark the square as visited and make the move.
iii. If the move leads to a solution (recursive call returns true), return true.
iv. If the move does not lead to a solution, backtrack by marking the square as
unvisited.
c. If no move leads to a solution, return false.
Q15 Give the explicit and implicit constraints in 8 queen’s problem.
The 8-Queens problem involves placing eight queens on an 8x8 chessboard in such a way
that no two queens threaten each other. In this context, "threaten" means that no two
queens are in the same row, column, or diagonal. The constraints in the 8-Queens problem
can be categorized as explicit and implicit.
Explicit Constraints:
Non-Overlap Constraint: Explicitly, no two queens can occupy the same cell on the
chessboard.
Row Constraint: Each row must contain exactly one queen.
Column Constraint: Each column must contain exactly one queen.
Implicit Constraints:
Diagonal Constraint: Queens cannot threaten each other diagonally. This means that for
any two queens (i, j) and (k, l), the absolute difference between |i - k| must not be equal to
the absolute difference between |j - l|.
Equality Constraint: Each queen is unique and cannot be equal to any other queen.
Chessboard Size Constraint:
The problem is defined on an 8x8 chessboard. Queens must be placed within the bounds
of the chessboard.
Additional Constraints (depending on the specific problem formulation or requirements):
One-Solution Constraint:
Some formulations of the problem may require finding only one solution, while others
might ask for all possible solutions.
Symmetry Constraint:
Some formulations might disallow symmetric solutions to be counted separately (e.g.,
rotating or mirroring a solution).
Efficiency Constraint:
Solutions that are rotations or reflections of each other may be considered equivalent,
reducing the number of unique solutions.
Objective Function (Optional):
If the problem has an associated cost or objective (e.g., minimizing the number of attacks
between queens), an additional constraint or objective function may be present.
Q16 Explain need of circular queve.
m A circular queue, also known as a ring buffer, is a type of data structure that represents a
queue with a fixed-size buffer. In a regular queue, once the last position in the queue is
reached, subsequent insertions are not allowed even if there are empty spaces at the
beginning of the queue. However, a circular queue addresses this limitation by allowing the
front and rear pointers to wrap around to the beginning of the queue, forming a circular
structure. The need for a circular queue arises in various scenarios due to its specific
advantages:
Efficient Use of Memory:Circular queues are particularly useful when a fixed-size buffer is
allocated in memory. The circular nature allows efficient use of the available memory space
without wasting any slots. This is crucial in scenarios where memory utilization is a concern.
Efficient Implementation of Queues in Resource-Constrained Systems:In embedded
systems or other resource-constrained environments, circular queues offer an efficient way
to implement queues without the need for dynamic memory allocation, which may be
limited or not desirable in such systems.
Efficient Implementation of Buffers and Buffers in I/O Systems:Circular queues are
commonly used in scenarios where data is continuously flowing, such as data buffers in
communication systems or I/O buffers. The circular nature allows for continuous data
processing without the need to resize the buffer.
Circular Rotations and Circular Buffers:In applications involving circular rotations or
circular buffers (e.g., rotating a set of tasks, circular buffers in audio processing), a circular
queue is a natural and efficient choice.
Simulation and Modeling:Circular queues find applications in simulation and modeling,
where a set of entities or events are processed in a circular fashion. For example, in a
discrete event simulation, circular queues can represent event queues.
Avoiding Frequent Memory Allocation and Deallocation:In scenarios where dynamic
memory allocation and deallocation are expensive operations, circular queues offer a fixed-
size structure that can be reused without the need for frequent memory operations.
Implementation of Certain Algorithms:
Some algorithms, especially those related to circular movements or cyclic patterns, benefit
from the use of circular queues. For example, solving problems involving circular
permutations or rotations.
Avoiding Fragmentation:Circular queues help avoid memory fragmentation issues that
might occur when using a regular queue with a fixed size.
Q17 What is the purpose of Linked List.
linked list is a linear data structure where elements are stored in nodes, and each node
points to the next node in the sequence. Linked lists have several purposes and
advantages, making them suitable for various scenarios:
Dynamic Memory Allocation:Unlike arrays, linked lists do not require a fixed-size
allocation of memory. Nodes in a linked list can be dynamically allocated, allowing for
flexible and efficient memory usage.
Dynamic Size:Linked lists can easily grow or shrink in size during program execution. This
dynamic sizing is particularly useful when the exact size of the data structure is not known
in advance or changes frequently.
Insertions and Deletions: Inserting or deleting elements in a linked list can be more
efficient than in an array. In a linked list, adding or removing a node typically involves
adjusting a few pointers, while in an array, elements may need to be shifted to
accommodate the change.
No Pre-allocation of Memory: Linked lists do not require pre-allocation of memory for a
fixed number of elements, as opposed to arrays. This makes linked lists suitable for
scenarios where the number of elements is not known in advance.
Ease of Implementation: Implementing certain algorithms or data structures is often
more straightforward with linked lists. For example, implementing a stack or a queue is
simpler with linked lists than with arrays.
Efficient Memory Utilization: Linked lists can efficiently utilize memory by allocating
space for each element only when needed. This is in contrast to arrays, where a contiguous
block of memory is allocated for all elements, even if some slots remain unused.
No Memory Wastage: Linked lists do not suffer from the "memory wastage" problem that
can occur in arrays when allocating a fixed-size array but using only a small portion of it.
Ease of Implementation of Algorithms: Certain algorithms are more easily implemented
with linked lists. For example, reversing a linked list or finding the middle element.
Support for Cyclic Data Structures: Linked lists can be easily adapted to create cyclic data
structures (circular linked lists) where the last node points to the first node, providing a
useful structure for certain applications.
No Need for Contiguous Memory: Linked lists do not require contiguous memory
locations, which allows for more flexible memory allocation and reduces memory
fragmentation.
Dynamic Data Structures:Linked lists are dynamic data structures that can be easily
adapted to changing requirements during runtime.
Q18 Write an algorithm to implement queue using linked list.
Algorithm: Queue using Linked List
Structure Node:
- data: Element of the node
- next: Pointer to the next node
Structure Queue:
- front: Pointer to the front (head) of the queue
- rear: Pointer to the rear (tail) of the queue
Function InitializeQueue():
Create an empty linked list
Set front and rear pointers to null
Function Enqueue(element):
Create a new node with data = element
If the queue is empty (front is null), set front and rear to the new node
Otherwise, set the next pointer of the current rear to the new node and update rear to the
new node
Function Dequeue():
If the queue is empty (front is null), return an error (underflow)
Store the data of the front node in a variable
If front is the same as rear (single node in the queue), set front and rear to null
Otherwise, update front to the next node
Return the stored data
Function IsEmpty():
Return true if front is null (queue is empty), otherwise return false
Function DisplayQueue():
Initialize a temporary pointer as front
While the pointer is not null:
Print the data of the current node
Move the pointer to the next node
Q18 Explain Rules for Tower of Hanoi with an suitable example.
The Tower of Hanoi is a classic problem in computer science and mathematics that involves
moving a set of disks of different sizes from one peg (rod) to another, subject to certain
constraints. The problem was introduced by the French mathematician Edouard Lucas in
1883. The rules for the Tower of Hanoi are simple but lead to a surprisingly complex and
elegant solution. Here are the rules:
Rules for Tower of Hanoi:
Three Pegs (Rods):The Tower of Hanoi consists of three pegs or rods, often denoted as A,
B, and C.
Disks of Different Sizes:There are several disks of different sizes, initially stacked in
decreasing order of size on one peg (source peg).
Objective:The goal is to move all the disks to another peg (destination peg), adhering to
the rules, using the third peg as an auxiliary or intermediate peg.
Only One Disk at a Time:
At any move, only one disk can be moved from the top of one of the stacks to the top of
another stack.
Larger Disk Cannot be Placed on Smaller Disk:A larger disk cannot be placed on top of a
smaller disk. The disks must be kept in decreasing order of size from bottom to top on any
peg.
Recursive Solution:
The Tower of Hanoi problem can be elegantly solved using recursion. The recursive
algorithm follows these steps:
Base Case:
If there is only one disk, move it directly from the source peg to the destination peg.
Recursive Step:Move the top n-1 disks from the source peg to the auxiliary peg, using the
destination peg as a temporary peg.
Move Largest Disk:Move the largest remaining disk from the source peg to the
destination peg.
Recursive Step (Again):Move the n-1 disks from the auxiliary peg to the destination peg,
using the source peg as a temporary peg.
function towerOfHanoi(n, sourceRod, targetRod, auxiliaryRod) {
if (n === 1) {
console.log(Move disk 1 from ${sourceRod} to ${targetRod});
return;
}
towerOfHanoi(n - 1, sourceRod, auxiliaryRod, targetRod);
console.log(Move disk ${n} from ${sourceRod} to ${targetRod});
towerOfHanoi(n - 1, auxiliaryRod, targetRod, sourceRod);
}// Example usage with 3 disks on rods A, B, and C
towerOfHanoi(3, 'A', 'C', 'B');
Q19 What is Jump Game algorithm?
The Jump Game algorithm is a classic problem in computer science and algorithms that
involves determining if it's possible to reach the last index of an array (representing a game
board) starting from the first index. Each element in the array represents the maximum
number of positions you can jump forward from that position.
The problem statement is as follows:
Jump Game Problem:
Given an array of non-negative integers nums, you are initially positioned at the first index
of the array. Each element in the array represents your maximum jump length from that
position. Determine if you can reach the last index.
Example
Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
function canJump(nums) {
let maxReach = 0;
for (let i = 0; i < nums.length; i++) {
if (i > maxReach) {
return false;
}
maxReach = Math.max(maxReach, i + nums[i]);
if (maxReach >= nums.length - 1) {
return true;
} } return false; }
// Example usage:
const nums = [2, 3, 1, 1, 4];
console.log(canJump(nums)); // Output: true
Q20 What is Hamiltonian cycle?
A Hamiltonian cycle, also known as a Hamiltonian circuit, is a cycle that visits every vertex
in a graph exactly once and returns to the starting vertex. In other words, it is a closed loop
that travels through every vertex in the graph without revisiting any vertex (except for the
starting and ending vertices).
Key Properties of Hamiltonian Cycle:
A Hamiltonian cycle is a cycle that contains every vertex of the graph.It starts and ends at
the same vertex.It visits each vertex exactly once, except for the starting and ending vertex,
which are the same.
A graph that contains a Hamiltonian cycle is called a Hamiltonian graph. Not all graphs are
Hamiltonian, and determining whether a graph has a Hamiltonian cycle is a known NP-
complete problem. Therefore, finding a Hamiltonian cycle in a graph is generally a
computationally challenging problem.
Example:
Consider the following graph:
A -- B
| |
C -- D
In this graph, a Hamiltonian cycle could be: A -> B -> D -> C -> A.
Hamiltonian Path:
If a path visits every vertex exactly once but does not necessarily form a cycle (i.e., it does
not return to the starting vertex), it is called a Hamiltonian path.
Hamiltonian cycles and paths have applications in various fields, including optimization
problems, network design, and the study of graph theory. The Traveling Salesman Problem
(TSP), which involves finding the shortest Hamiltonian cycle in a weighted graph, is a well-
known optimization problem with practical applications.
Q21 Define Hash function 2 collision.
A hash function is a function that takes an input (or 'message') and produces a fixed-size
string of characters, which is typically a hash value. Hash functions are commonly used in
computer science for various applications, such as indexing data in hash tables or ensuring
data integrity through hash-based message authentication codes (HMACs).
A hash collision occurs when two different inputs produce the same hash value. In other
words, if two distinct inputs (messages) result in the same hash value when processed by a
hash function, a collision has occurred.
Hash Function Properties:
Deterministic: A hash function must produce the same hash value for the same input
consistently.
Fixed Output Length: The hash function produces a fixed-length output, regardless of the
size or length of the input.
Efficient to Compute: The hash function should be computationally efficient to calculate
the hash value for any given input.
Avalanche Effect: A small change in the input should produce a significantly different hash
value.
Collision in Hash Functions:
While hash functions aim to distribute hash values uniformly across the output space,
collisions can still occur due to the finite size of the output space (the range of possible
hash values) compared to the potentially infinite input space.
Hash collisions are typically undesirable because they can lead to various issues, such as:
Data Integrity: Collisions may compromise the integrity of data stored using hash
functions.
Security: In cryptographic applications, hash collisions can potentially be exploited for
malicious purposes.
Efficiency: Hash collisions can impact the efficiency of hash-based data structures, such as
hash tables.
Authentication: Collisions can pose challenges in hash-based message authentication
codes (HMACs) and digital signatures.

You might also like