23UCACCP03-DSA Using C++ Lab1
23UCACCP03-DSA Using C++ Lab1
COLLEGE
Affiliated to Periyar University, Salem.
CHITHALANDUR, TIRUCHENGODE, NAMAKKAL - 637 201
II BCA
1. Node Definition:
o Define a Node class with two members: data (to store the stack element)
and next (a pointer to the next node).
2. Stack Class:
o Create a Stack class with a private member top (a pointer to the top node).
o Initialize top to nullptr.
3. Push Operation:
o Create a new node with the given value.
o Set its next pointer to the current top.
o Update top to point to the new node.
4. Pop Operation:
o Check if the stack is empty (i.e., top is nullptr).
o If not empty:
▪ Create a temporary pointer (temp) to the top node.
▪ Move top to the next node.
▪ Delete the temp node.
5. Peek Operation:
o Check if the stack is empty.
o If not empty, return the value of the top node.
6. Display Operation:
o Traverse the stack from top to the end, printing each element.
Program:
#include <iostream>
class Node {
public:
int data;
Node* next;
Node(int value) {
data = value;
next = nullptr;
}
};
class Stack {
private:
Node* top;
public:
Stack() {
top = nullptr;
}
void push(int data) {
Node* newNode = new Node(data);
if (!newNode) {
std::cout << "\nStack Overflow\n";
exit(1);
}
newNode->next = top;
top = newNode;
}
bool isEmpty() {
return top == nullptr;
}
int peek() {
if (!isEmpty())
return top->data;
else {
std::cout << "\nStack is empty.\n";
exit(1);
}
}
void pop() {
if (top == nullptr) {
std::cout << "\nStack Underflow\n";
exit(1);
} else {
Node* temp = top;
top = top->next;
delete temp;
}
}
void display() {
Node* temp = top;
while (temp != nullptr) {
std::cout << temp->data << " ";
temp = temp->next;
}
std::cout << std::endl;
}
};
int main() {
Stack myStack;
myStack.push(10);
myStack.push(20);
myStack.push(30);
std::cout << "Elements in the stack: ";
myStack.display();
std::cout << "Top element: " << myStack.peek() << "\n";
myStack.pop();
std::cout << "After popping: ";
myStack.display();
return 0;
}
Sample Input and Output:
Suppose we push elements 10, 20, and 30 into the stack. After popping an element, the output
will be:
Elements in the stack: 30 20 10
Top element: 30
After popping: 20 10
Aim:
The aim of this implementation is to create a queue using a singly linked list, allowing efficient
enqueue and dequeue operations.
Prerequisites:
1. Node Definition:
o Define a Node class with two members: data (to store the queue element)
and next (a pointer to the next node).
2. Queue Class:
o Create a Queue class with a private member front (a pointer to the front node)
and rear (a pointer to the rear node).
o Initialize both front and rear to nullptr.
3. Enqueue Operation:
o Create a new node with the given value.
o If the queue is empty (i.e., rear is nullptr), set both front and rear to the new
node.
o Otherwise, set the next pointer of the current rear to the new node and
update rear to point to the new node.
4. Dequeue Operation:
o Check if the queue is empty (i.e., front is nullptr).
o If not empty:
▪ Create a temporary pointer (temp) to the front node.
▪ Move front to the next node.
▪ Delete the temp node.
5. Peek Operation:
o Check if the queue is empty.
o If not empty, return the value of the front node.
6. Display Operation:
o Traverse the queue from front to the end, printing each element.
Program:
#include <iostream>
class Node {
public:
int data;
Node* next;
Node(int value) {
data = value;
next = nullptr;
}
};
class Queue {
private:
Node* front;
Node* rear;
public:
Queue() {
front = nullptr;
rear = nullptr;
}
void enqueue(int value) {
Node* newNode = new Node(value);
if (rear == nullptr) {
front = rear = newNode;
} else {
rear->next = newNode;
rear = newNode;
}
}
void dequeue() {
if (front == nullptr) {
std::cout << "Queue is empty. Cannot dequeue.\n";
return;
}
Node* temp = front;
front = front->next;
delete temp;
if (front == nullptr) {
rear = nullptr;
}
}
int peek() {
if (front == nullptr) {
std::cout << "Queue is empty.\n";
return -1; // Error value
}
return front->data;
}
void display() {
Node* temp = front;
while (temp != nullptr) {
std::cout << temp->data << " ";
temp = temp->next;
}
std::cout << std::endl;
}
};
int main() {
Queue myQueue;
myQueue.enqueue(10);
myQueue.enqueue(20);
myQueue.dequeue();
myQueue.enqueue(30);
std::cout << "Elements in the queue: ";
myQueue.display();
std::cout << "Front element: " << myQueue.peek() << "\n";
return 0;
}
Sample Input and Output:
Suppose we enqueue elements 10, 20, and 30 into the queue. After dequeuing an element, the
output will be:
Elements in the queue: 20 30
Front element: 20
Experiment 3: Write a program that reads an infix expression, converts the expression
to postfix form and then evaluates the postfix expression (use stack ADT)
Aim:
The aim of this program is to read an infix expression, convert it to postfix form, and then
evaluate the postfix expression using a stack.
Prerequisites:
A basic understanding of C++ programming concepts, including stacks and string
manipulation.
Algorithm:
1. Infix to Postfix Conversion:
o Create an empty stack for storing operators and a string for storing the result
(postfix expression).
o Scan the infix expression from left to right.
o If the scanned character is an operand (digit or variable), append it to the result.
o If the scanned character is an operator:
▪ Pop operators from the stack to the result until the top of the stack has
an operator of lower precedence or the stack is empty.
▪ Push the scanned operator onto the stack.
o If the scanned character is ‘(’, push it onto the stack.
o If the scanned character is ‘)’, pop operators from the stack to the result until ‘(’
is encountered, and pop ‘(’ from the stack.
o After all characters are scanned, pop the remaining operators from the stack to
the result.
2. Postfix Evaluation:
o Create an empty stack for storing operands.
o Iterate through the postfix expression:
▪ If the element is an operand, push it onto the stack.
▪ If the element is an operator, pop two operands from the stack, apply the
operator, and push the result back into the stack.
o The final result will be the top element of the stack.
Program:
#include <iostream>
#include <stack>
#include <string>
#include <cctype>
using namespace std;
int precedence(char op) {
if (op == '+' || op == '-')
return 1;
if (op == '*' || op == '/')
return 2;
return 0;
}
string infixToPostfix(string infix) {
stack<char> st;
string postfix = "";
for (char c : infix) {
if (isalnum(c))
postfix += c;
else if (c == '(')
st.push(c);
else if (c == ')') {
while (!st.empty() && st.top() != '(') {
postfix += st.top();
st.pop();
}
st.pop(); // Pop '('
} else {
while (!st.empty() && precedence(c) <= precedence(st.top())) {
postfix += st.top();
st.pop();
}
st.push(c);
}
}
while (!st.empty()) {
postfix += st.top();
st.pop();
}
return postfix;
}
int evaluatePostfix(string postfix) {
stack<int> operands;
for (char c : postfix) {
if (isdigit(c))
operands.push(c - '0');
else {
int op2 = operands.top();
operands.pop();
int op1 = operands.top();
operands.pop();
switch (c) {
case '+': operands.push(op1 + op2); break;
case '-': operands.push(op1 - op2); break;
case '*': operands.push(op1 * op2); break;
case '/': operands.push(op1 / op2); break;
}
}
}
return operands.top();
}
int main() {
string infix = "2+3*1-9";
cout << "Infix Expression: " << infix << endl;
string postfix = infixToPostfix(infix);
cout << "Postfix Expression: " << postfix << endl;
int result = evaluatePostfix(postfix);
cout << "Result: " << result << endl;
return 0;
}
Sample Input and Output:
Suppose we input the infix expression “2+3*1-9”. The program will output:
Infix Expression: 2+3*1-9
Postfix Expression: 231*+9-
Result: -4
Experiment 4: Write a program to implement priority queue ADT
Aim:
The aim of this program is to create a priority queue (max heap by default) using the C++
Standard Template Library (STL).
Prerequisites:
A basic understanding of C++ programming concepts.
Algorithm:
1. Priority Queue Implementation:
o We’ll use the std::priority_queue class from the STL.
o By default, it creates a max heap (largest element at the top).
o To create a min heap (smallest element at the top), we’ll use a custom
comparison function.
o The syntax for creating a min heap is: std::priority_queue<int, vector<int>,
greater<int>> pq;
o Here, int is the type of elements you want to store in the priority queue. You can
replace int with any other data type you need.
o vector<int> is the type of internal container used to store these elements.
o greater<int> is a custom comparison function that sets up a min-heap. It means
that the smallest element will be at the top of the queue.
o In the case of a max heap (default), we don’t need to specify the comparison
function.
Program:
#include <iostream>
#include <queue>
int main() {
std::priority_queue<int> pq; // Max heap by default
// Insert elements into the priority queue
pq.push(10);
pq.push(20);
pq.push(5);
pq.push(15);
std::cout << "Priority Queue (Max Heap): ";
while (!pq.empty()) {
std::cout << pq.top() << " ";
pq.pop();
}
std::cout << std::endl;
return 0;
}
Sample Output:
Priority Queue (Max Heap): 20 15 10 5
Experiment 5: Write a program to perform the following operations
• Insert an element into a binary search tree.
• Delete an element from a binary search tree.
• Search for a key element in a binary search tree.
Aim:
The aim of this program is to perform basic operations on a binary search tree (BST), including
insertion, deletion, and searching.
Prerequisites:
A basic understanding of C++ programming concepts.
Algorithm:
1. Insertion into a Binary Search Tree (BST):
1. If the tree is empty, create a new node with the given value and make it the root.
2. Otherwise, traverse the tree:
▪ If the value is less than the current node’s value, move to the left subtree.
▪ If the value is greater than the current node’s value, move to the right
subtree.
▪ Repeat until an empty position is found.
3. Insert the new node at the appropriate position.
2. Deletion from a Binary Search Tree (BST):
1. Find the node to be deleted.
2. If the node has no children, simply delete it.
3. If the node has one child, replace it with its child.
4. If the node has two children, find the in-order successor (or predecessor), copy
its value to the node, and recursively delete the successor (or predecessor).
3. Searching for a Key Element in a Binary Search Tree (BST):
1. Start from the root.
2. If the current node’s value matches the key, return true.
3. If the key is less than the current node’s value, move to the left subtree.
4. If the key is greater than the current node’s value, move to the right subtree.
5. Repeat until a match is found or the tree is exhausted.
Program:
#include <iostream>
struct TreeNode {
int key;
TreeNode* left;
TreeNode* right;
};
TreeNode* newNode(int value) {
TreeNode* temp = new TreeNode;
temp->key = value;
temp->left = temp->right = nullptr;
return temp;
}
TreeNode* insert(TreeNode* root, int value) {
if (root == nullptr)
return newNode(value);
if (value < root->key)
root->left = insert(root->left, value);
else if (value > root->key)
root->right = insert(root->right, value);
return root;
}
TreeNode* findMin(TreeNode* root) {
while (root->left != nullptr)
root = root->left;
return root;
}
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr)
return root;
if (key < root->key)
root->left = deleteNode(root->left, key);
else if (key > root->key)
root->right = deleteNode(root->right, key);
else {
if (root->left == nullptr) {
TreeNode* temp = root->right;
delete root;
return temp;
} else if (root->right == nullptr) {
TreeNode* temp = root->left;
delete root;
return temp;
}
TreeNode* temp = findMin(root->right);
root->key = temp->key;
root->right = deleteNode(root->right, temp->key);
}
return root;
}
bool search(TreeNode* root, int key) {
if (root == nullptr)
return false;
if (root->key == key)
return true;
else if (key < root->key)
return search(root->left, key);
else
return search(root->right, key);
}
void inorderTraversal(TreeNode* root) {
if (root == nullptr)
return;
inorderTraversal(root->left);
std::cout << root->key << " ";
inorderTraversal(root->right);
}
int main() {
TreeNode* root = nullptr;
int choice, key;
do {
std::cout << "\n1. Insert\n2. Delete\n3. Search\n4. Display (Inorder)\n5. Exit\n";
std::cout << "Enter your choice: ";
std::cin >> choice;
switch (choice) {
case 1:
std::cout << "Enter key to insert: ";
std::cin >> key;
root = insert(root, key);
break;
case 2:
std::cout << "Enter key to delete: ";
std::cin >> key;
root = deleteNode(root, key);
break;
case 3:
std::cout << "Enter key to search: ";
std::cin >> key;
std::cout << (search(root, key) ? "Found" : "Not found") << std::endl;
break;
case 4:
std::cout << "Inorder traversal: ";
inorderTraversal(root);
std::cout << std::endl;
break;
case 5:
std::cout << "Exiting program.\n";
break;
default:
std::cout << "Invalid choice. Try again.\n";
}
} while (choice != 5);
return 0;
}
Sample Input and Output:
Suppose we perform the following operations:
1. Insert 50, 30, 20, 40, 70, 60, and 80.
2. Delete 30.
3. Search for 60.
The program will output:
1. Insert
2. Delete
3. Search
4. Display (Inorder)
5. Exit
Enter your choice: 1
Enter key to insert: 50
1. Insert
2. Delete
3. Search
4. Display (Inorder)
5. Exit
Enter your choice: 1
Enter key to insert: 30
...
1. Insert
2. Delete
3. Search
4. Display (Inorder)
5. Exit
Enter your choice: 4
Inorder traversal: 20 40 50 60 70 80
1. Insert
2. Delete
3. Search
4. Display (Inorder)
5. Exit
Enter your choice: 2
Enter key to delete: 30
1. Insert
2. Delete
3. Search
4. Display (Inorder)
5. Exit
Enter
Experiment 6: Write a program to perform the following operations
• Insertion into an AVL-tree
• Deletion from an AVL-tree
Aim:
The aim of this program is to implement insertion and deletion operations on an AVL tree in
C++ using switch-case statements.
Prerequisites:
1. Understanding of AVL trees and their balancing criteria.
2. Basic knowledge of C++ programming language.
3. Familiarity with binary search trees (BSTs) and their operations.
Algorithm:
1. Insertion:
● Start with a recursive insertion function.
● Perform normal BST insertion.
● Update the height of each node after insertion.
● Check for balance factor of each node to ensure AVL property is maintained.
● If the balance factor is violated, perform rotations (left-left, left-right, right-
right, right-left) to balance the tree.
2. Deletion:
● Start with a recursive deletion function.
● Perform normal BST deletion.
● Update the height of each node after deletion.
● Check for balance factor of each node to ensure AVL property is maintained.
● If the balance factor is violated, perform rotations (left-left, left-right, right-
right, right-left) to balance the tree.
Program:
#include <iostream>
using namespace std;
// AVL Tree Node Structure
struct Node {
int key;
Node *left;
Node *right;
int height;
};
// Function to create a new AVL tree node
Node* newNode(int key) {
Node* node = new Node();
node->key = key;
node->left = nullptr;
node->right = nullptr;
node->height = 1;
return node;
}
// Function to get the height of a node
int height(Node* node) {
if (node == nullptr)
return 0;
return node->height;
}
// Function to get the balance factor of a node
int balanceFactor(Node* node) {
if (node == nullptr)
return 0;
return height(node->left) - height(node->right);
}
// Function to right rotate a subtree rooted with y
Node* rightRotate(Node* y) {
Node* x = y->left;
Node* T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right)) + 1;
x->height = max(height(x->left), height(x->right)) + 1;
// Return new root
return x;
}
// Function to left rotate a subtree rooted with x
Node* leftRotate(Node* x) {
Node* y = x->right;
Node* T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right)) + 1;
y->height = max(height(y->left), height(y->right)) + 1;
// Return new root
return y;
}
// Function to perform AVL tree insertion
Node* insert(Node* root, int key) {
// Perform normal BST insertion
if (root == nullptr)
return newNode(key);
if (key < root->key)
root->left = insert(root->left, key);
else if (key > root->key)
root->right = insert(root->right, key);
else // Duplicate keys not allowed
return root;
// Update height of this ancestor node
root->height = 1 + max(height(root->left), height(root->right));
// Get the balance factor to check if this node became unbalanced
int balance = balanceFactor(root);
// Left Left Case
if (balance > 1 && key < root->left->key)
return rightRotate(root);
// Right Right Case
if (balance < -1 && key > root->right->key)
return leftRotate(root);
// Left Right Case
if (balance > 1 && key > root->left->key) {
root->left = leftRotate(root->left);
return rightRotate(root);
}
// Right Left Case
if (balance < -1 && key < root->right->key) {
root->right = rightRotate(root->right);
return leftRotate(root);
}
// Return the unchanged node pointer
return root;
}
// Function to find the node with minimum key value in a tree
Node* minValueNode(Node* node) {
Node* current = node;
// Loop down to find the leftmost leaf
while (current->left != nullptr)
current = current->left;
return current;
}
// Function to perform AVL tree deletion
Node* deleteNode(Node* root, int key) {
// Perform normal BST deletion
if (root == nullptr)
return root;
if (key < root->key)
root->left = deleteNode(root->left, key);
else if (key > root->key)
root->right = deleteNode(root->right, key);
else {
// Node with only one child or no child
if (root->left == nullptr || root->right == nullptr) {
Node* temp = root->left ? root->left : root->right;
// No child case
if (temp == nullptr) {
temp = root;
root = nullptr;
} else // One child case
*root = *temp; // Copy the contents of the non-empty child
delete temp;
} else {
// Node with two children, get the inorder successor
Node* temp = minValueNode(root->right);
// Copy the inorder successor's data to this node
root->key = temp->key;
// Delete the inorder successor
root->right = deleteNode(root->right, temp->key);
}
}
// If the tree had only one node then return
if (root == nullptr)
return root;
// Update height of the current node
root->height = 1 + max(height(root->left), height(root->right));
// Get the balance factor to check if this node became unbalanced
int balance = balanceFactor(root);
// Left Left Case
if (balance > 1 && balanceFactor(root->left) >= 0)
return rightRotate(root);
// Left Right Case
if (balance > 1 && balanceFactor(root->left) < 0) {
root->left = leftRotate(root->left);
return rightRotate(root);
}
// Right Right Case
if (balance < -1 && balanceFactor(root->right) <= 0)
return leftRotate(root);
// Right Left Case
if (balance < -1 && balanceFactor(root->right) > 0) {
root->right = rightRotate(root->right);
return leftRotate(root);
}
return root;
}
// Function to perform inorder traversal of the AVL tree
void inorder(Node* root) {
if (root != nullptr) {
inorder(root->left);
cout << root->key << " ";
inorder(root->right);
}
}
int main() {
Node* root = nullptr;
int choice, key;
do {
cout << "\nAVL Tree Operations:";
cout << "\n1. Insertion";
cout << "\n2. Deletion";
cout << "\n3. Inorder Traversal";
cout << "\n4. Exit";
cout << "\nEnter your choice: ";
cin >> choice;
switch (choice) {
case 1:
cout << "Enter key to insert: ";
cin >> key;
root = insert(root, key);
cout << "Inserted " << key << " into the AVL tree.\n";
break;
case 2:
cout << "Enter key to delete: ";
cin >> key;
root = deleteNode(root, key);
cout << "Deleted " << key << " from the AVL tree.\n";
break;
case 3:
cout << "Inorder traversal of AVL tree: ";
inorder(root);
cout << endl;
break;
case 4:
cout << "Exiting...";
break;
default:
cout << "Invalid choice! Please enter a valid option.\n";
}
} while (choice != 4);
return 0;
}
Sample Input/Output:
1. BFS
2. DFS
3. Exit
Enter your choice: 2
Enter the starting vertex for DFS: 0
DFS traversal starting from vertex 0: 0 2 4 5 3 1
1. BFS
2. DFS
3. Exit
Enter your choice: 3
Exiting program.
Experiment 8: Write a program for implementing the following searching methods.
(a) Linear Search
(b) Binary Search
(a) Linear Search
Aim:
The aim of this program is to search for a given element in an array using linear search.
Prerequisites:
Before proceeding, ensure you have a basic understanding of C++ programming concepts.
Algorithm:
1. Start from the leftmost element of the array.
2. Compare the search key with each element of the array.
3. If the key matches an element, return the index.
4. If the key doesn’t match any element, return -1.
Program:
#include <iostream>
using namespace std;
int linearSearch(int arr[], int n, int x) {
for (int i = 0; i < n; i++) {
if (arr[i] == x)
return i;
}
return -1;
}
int main() {
int arr[] = {2, 3, 4, 10, 40};
int x = 10;
int n = sizeof(arr) / sizeof(arr[0]);
int result = linearSearch(arr, n, x);
if (result == -1)
cout << "Element is not present in the array";
else
cout << "Element is present at index " << result;
return 0;
}
Sample Output:
Element is present at index 3