Java programming

Download as pdf or txt
Download as pdf or txt
You are on page 1of 69

WEEK-1 Date:

AIM: Assume that you are working for a company that manages a large library of books.
Each book has a unique identifier (ID), title, author, genre, and publication year. The
company wants to implement a system that allows for efficient retrieval of information about
the books based on different criteria such as ID, author, genre, or a combination of
these(dictionaries).
DESCRIPTION:
Use of unordered_map:
 libraryByID: Maps book IDs to Book objects. This allows for quick lookup by ID.
libraryByAuthor: Maps author names to vectors of Book objects. This allows
grouping books by author.
 libraryByGenre: Maps genres to vectors of Book objects. This allows grouping
books by genre.
Dictionary Functions:
 Find (): Used to search for keys in the unordered_map. This function returns an
iterator to the element if found, or end () if the key is not found.
 Operator []: Used to access elements in the unordered_map. If the key does not exist,
it inserts anew key-value pair with a default-constructed value.
 push_back(): Used to add a book to the vector of books under a specific author or
genre.
Encapsulation:
The Library class encapsulates all operations related to managing the collection of books.
The Book class represents individual books.
Vector: vector in C++ is a sequence container that can dynamically resize itself to
accommodate moreelements.
It is part of the C++ Standard Template Library (STL) and is one of the most commonly used
containers. vector provides a way to store elements of a specific type in dynamic array that
can grow or shrink in size as needed.
Range of Operations:
Vector supports various operations, such as:
 push_back(): Add an element to the end of the vector.
 pop_back(): Remove the last element.
 size(): Get the current number of elements in the vector.
 empty(): Check if the vector is empty.
 clear(): Remove all elements from the vector.
 at(): Access an element with bounds checking.
 operator[]: Access an element without bounds checking.
ALGORITHM:
1. Initializing a Dictionary
1. Input: A list of key-value pairs, or an empty dictionary if none are provided.
2. Process: Create a dictionary using the input.
3. Output: A dictionary with the specified key-value pairs.
2. Checking if a Key Exists
1. Input: A dictionary and a key to check.
1
2. Process:
o Use the in operator to check if the key exists in the dictionary.
3. Output: True if the key exists, False otherwise.
3. Adding or Updating a Key-Value Pair
1. Input: A dictionary, a key, and a value.
2. Process:
o Assign the value to the dictionary using dictionary[key] = value.
3. Output: Updated dictionary.
4. Removing a Key
1. Input: A dictionary and a key to remove.
2. Process:
o Check if the key exists using in.
o If it exists, remove it using pop().
3. Output: Updated dictionary.
5. Iterating Over a Dictionary
1. Input: A dictionary.
2. Process:
o Use a for loop to iterate through items() for keys and values.
3. Output: Processed key-value pairs.
6. Sorting a Dictionary
1. Input: A dictionary.
2. Process:
o Use sorted() to sort the dictionary by keys or values.
o Reconstruct the dictionary from the sorted items.
3. Output: Sorted dictionary.
7. Filtering a Dictionary
1. Input: A dictionary and a filtering condition (a function).
2. Process:
o Use a dictionary comprehension to keep only the items that satisfy the
condition.
3. Output: Filtered dictionary.
IMPLEMENTATION:
#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
using namespace std;
struct Book
{

2
string id;
string title;
string author;
string genre;
int publicationYear;
};
// Function to add a book to the library
void addBook(unordered_map<string, Book>& libraryByID, unordered_map<string,
vector<Book>>& libraryByAuthor, unordered_map<string, vector<Book>>&
libraryByGenre, const Book& book)
{
libraryByID[book.id] = book;
libraryByAuthor[book.author].push_back(book);
libraryByGenre[book.genre].push_back(book);
}
// Function to retrieve a book by ID
void getBookByID(const unordered_map<string, Book>& libraryByID, const string& id)
{
auto it = libraryByID.find(id);
if (it != libraryByID.end())
{
const Book& book = it->second;
cout << "Book found: " << book.title << " by " << book.author << " (" <<
book.publicationYear
<< ")\n";
}
Else
{
cout << "Book not found.\n";
}
}
// Function to retrieve books by author
void getBooksByAuthor(const unordered_map<string, vector<Book>>& libraryByAuthor,
const
string& author)
{
auto it = libraryByAuthor.find(author);
if (it != libraryByAuthor.end())
{
cout << "Books by " << author << ":\n";

3
for (const Book& book : it->second)
{
cout << "- " << book.title << " (" << book.publicationYear << ")\n";
}
}
else
{
cout << "No books found by this author.\n";
}
}
// Function to retrieve books by genre
void getBooksByGenre(const unordered_map<string, vector<Book>>& libraryByGenre,
const
string& genre)
{
auto it = libraryByGenre.find(genre);
if (it != libraryByGenre.end())
{
cout << "Books in genre " << genre << ":\n";
for (const Book& book : it->second)
{
cout << "- " << book.title << " by " << book.author << " (" << book.publicationYear << ")\n";
}
}
Else
{
cout << "No books found in this genre.\n";
}
}
// Function to read book details from user
Book readBookDetails()
{
Book book;
cout << "Enter book ID: ";
getline(std::cin, book.id);
cout << "Enter title: ";
getline(std::cin, book.title);
cout << "Enter author: ";
getline(std::cin, book.author);

4
cout << "Enter genre: ";
getline(std::cin, book.genre);
cout << "Enter publication year: ";
cin >> book.publicationYear;
cin.ignore(); // To clear the newline character from the input buffer
return book;
}
int main()
{
unordered_map<string, Book> libraryByID;
unordered_map<string, vector<Book>> libraryByAuthor;
unordered_map<string, vector<Book>> libraryByGenre;
int choice;
do
{
cout << "\nBook Management System\n";
cout << "1. Add a book\n";
cout << "2. Retrieve book by ID\n";
cout << "3. Retrieve books by Author\n";
cout << "4. Retrieve books by Genre\n";
cout << "5. Exit\n";
cout << "Enter your choice: ";
cin >> choice;
cin.ignore(); // To clear the newline character from the input buffer
switch (choice)
{
case 1:
{
Book book = readBookDetails();
addBook(libraryByID, libraryByAuthor, libraryByGenre, book);
cout << "Book added successfully!\n";
break;
}
case 2: {
string id;
cout << "Enter book ID: ";
getline(cin, id);
getBookByID(libraryByID, id);
break;

5
}
case 3:
{
string author;
cout << "Enter author: ";
getline(cin, author);
getBooksByAuthor(libraryByAuthor, author);
break;
}
case 4:
{
string genre;
cout << "Enter genre: ";
getline(cin, genre);
getBooksByGenre(libraryByGenre, genre);
break;
}
case 5: {
cout << "Exiting...\n";
break;
}
default:
cout << "Invalid choice. Please try again.\n";
break;
}
} while (choice != 5);
return 0;
}
USING CLASSES AND OBJECTS:
#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
using namespace std;
class Book {
public:
string id;
string title;
string author;

6
string genre;
int publicationYear;
Book() {} //Default constructor
Book(const string& id, const string& title, const string& author, const string& genre, int
publicationYear) : id(id),title(title),
author(author),genre(genre),publicationYear(publicationYear)
{} // parameterized constructor
};
class Library
{
private:
unordered_map<string, Book> libraryByID;
unordered_map<string, vector<Book>> libraryByAuthor;
unordered_map<string, vector<Book>> libraryByGenre;
public:
void addBook(const Book& book)
{
libraryByID[book.id] = book;
libraryByAuthor[book.author].push_back(book);
libraryByGenre[book.genre].push_back(book);
cout << "Book added successfully!\n";
}
void getBookByID(const string& id) const
{
auto it = libraryByID.find(id);
if (it != libraryByID.end())
{
const Book& book = it->second;
cout << "Book found: " << book.title << " by " << book.author << " (" <<
book.publicationYear << ")\n";
} else {
cout << "Book not found.\n";
}
}
void getBooksByAuthor(const string& author) const
{
auto it = libraryByAuthor.find(author);
if (it != libraryByAuthor.end())
{

7
cout << "Books by " << author << ":\n";
for (const Book& book : it->second)
{
cout << "- " << book.title << " (" << book.publicationYear << ")\n";
}
} else
{
cout << "No books found by this author.\n";
}
}
void getBooksByGenre(const string& genre) const
{
auto it = libraryByGenre.find(genre);
if (it != libraryByGenre.end())
{
cout << "Books in genre " << genre << ":\n";
for (const Book& book : it->second)
{
cout << "- " << book.title << " by " << book.author << " (" << book.publicationYear
<< ")\n";
}
} else
{
cout << "No books found in this genre.\n";
}
}
Book readBookDetails() const
{
Book book;
cout << "Enter book ID: ";
getline(cin, book.id);
cout << "Enter title: ";
getline(cin, book.title);
cout << "Enter author: ";
getline(cin, book.author);
cout << "Enter genre: ";
getline(cin, book.genre);
cout << "Enter publication year: ";
cin >> book.publicationYear;

8
cin.ignore(); // To clear the newline character from the input buffer
return book;
}
};
int main()
{
Library library;
int choice;
do {
cout << "\nBook Management System\n";
cout << "1. Add a book\n";
cout << "2. Retrieve book by ID\n";
cout << "3. Retrieve books by Author\n";
cout << "4. Retrieve books by Genre\n";
cout << "5. Exit\n";
cout << "Enter your choice: ";
cin >> choice;
cin.ignore(); // To clear the newline character from the input buffer
switch (choice)
{
case 1:
{
Book book = library.readBookDetails();
library.addBook(book);
break;
}
case 2:
{
string id;
cout << "Enter book ID: ";
getline(std::cin, id);
library.getBookByID(id);
break;
}
case 3:
{
string author;
cout << "Enter author: ";
getline(cin, author);

9
library.getBooksByAuthor(author);
break;
}
case 4:
{
string genre;
cout << "Enter genre: ";
getline(cin, genre);
library.getBooksByGenre(genre);
break;
}
case 5: {
cout << "Exiting...\n";
break;
}
default:
cout << "Invalid choice. Please try again.\n";
break;
}
} while (choice != 5);
return 0;

10
OUTPUT:

11
WEEK-2 Date:
AIM: Imagine that you are a software engineer at an e-commerce company that manages a
large online store. The store’s inventory system needs to handle a variety of operations
efficiently, including adding new products, removing discontinued products, and searching
for specific products based on their unique IDs. The current implementation using a balanced
binary search tree is proving to be a bottleneck as the inventory grows. Design and implement
a skip list to manage the inventory of the online store. The skiplist should support the
following operations efficiently: – CO1
● Search(ProductID): Return the details of the product with the given ProductID.
● Insert(ProductID, ProductDetails): Add a new product to the inventory.
● Delete(ProductID): Remove a product from the inventory.
● Update(ProductID, ProductDetails): Update the details of an existing product
ALGORITHM:
1. Initialization
1. Input: Define the maximum number of levels (max_level) and a probability factor (p)
to determine how levels are created.
2. Process:
o Create a header node with references for all levels.
o Initialize the current level to 0 (start with one level).
3. Output: An empty skip list ready for operations.
2. Search in Skip List
1. Input: The skip list and the value to search for.
2. Process:
o Start at the highest level.
o Move forward in the current level until the next node’s value is greater than or
equal to the target.
o Drop down a level and repeat until the lowest level is reached.
o Check the value at the last node.
3. Output: The node if found, otherwise None.
3. Insertion in Skip List
1. Input: The skip list and the value to insert.
2. Process:
o Generate a random level for the new node using the probability p.
o If the new level is higher than the current list's level, update the header to
include the new level.
o For each level up to the new node’s level:
 Move forward in the current level until the correct insertion point is
found.
 Update the pointers to include the new node.
3. Output: Updated skip list.

12
4. Deletion in Skip List
1. Input: The skip list and the value to delete.
2. Process:
o Traverse through each level, updating pointers to skip the node to be deleted.
o Remove the node from memory if it exists.
o Adjust the current level if the highest levels become empty.
3. Output: Updated skip list.
IMPLEMENTATION:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cstring>
using namespace std;
const int MAX_LEVEL = 10; // Maximum level for the skip list
// Structure to represent product details
struct Product {
int id;
string details;
Product(int id, string details) : id(id), details(details)
{
}
};
// Node in the skip list
struct Node
{
Product* product;
Node** forward;
Node(int level, Product* product = nullptr)
{
this->product = product;
forward = new Node*[level + 1];
memset(forward, 0, sizeof(Node*) * (level + 1));
}
~Node()
{
delete[] forward;
if (product) delete product;
}
};

13
// Skip list class
class SkipList
{
private:
int level;
Node* header;
public:
SkipList()
{
level = 0;
header = new Node(MAX_LEVEL);
}
~SkipList()
{
Node* current = header;
while (current)
{
Node* next = current->forward[0];
delete current;
current = next;
}
}
int randomLevel()
{
int lvl = 0;
while (rand() % 2 && lvl < MAX_LEVEL)
{
lvl++;
}
return lvl;
}
Node* search(int id)
{
Node* current = header;
for (int i = level; i >= 0; i--)
{
while (current->forward[i] && current->forward[i]->product->id < id)
{
current = current->forward[i];

14
}
}
current = current->forward[0];
if (current && current->product->id == id)
{
return current;
}
return nullptr;
}
void insert(int id, string details)
{
Node* update[MAX_LEVEL + 1];
Node* current = header;
for (int i = level; i >= 0; i--)
{
while (current->forward[i] && current->forward[i]->product->id < id)
{
current = current->forward[i];
}
update[i] = current;
}
int newLevel = randomLevel();
if (newLevel > level)
{
for (int i = level + 1; i <= newLevel; i++)
{
update[i] = header;
}
level = newLevel;
}
Node* newNode = new Node(newLevel, new Product(id, details));
for (int i = 0; i <= newLevel; i++)
{
newNode->forward[i] = update[i]->forward[i];
update[i]->forward[i] = newNode;
}
}
void remove(int id)
{

15
Node* update[MAX_LEVEL + 1];
Node* current = header;
for (int i = level; i >= 0; i--)
{
while (current->forward[i] && current->forward[i]->product->id < id)
{
current = current->forward[i];
}
update[i] = current;
}
current = current->forward[0];
if (current && current->product->id == id)
{
for (int i = 0; i <= level; i++)
{
if (update[i]->forward[i] != current)
{
break;
}
update[i]->forward[i] = current->forward[i];
}
delete current;
while (level > 0 && header->forward[level] == nullptr)
{
level--;
}
}
}
void update(int id, string details)
{
Node* node = search(id);
if (node)
{
node->product->details = details;
}
else
{
cout << "Product not found. Inserting new product." << endl;
insert(id, details);

16
}
}
void display()
{
cout << "\nSkip List (Level-wise):\n";
for (int i = level; i >= 0; i--)
{
Node* node = header->forward[i];
cout << "Level " << i << ": ";
while (node)
{
cout << node->product->id << "(" << node->product->details << ") ";
node = node->forward[i];
}
cout << endl;
}
}
};
int main()
{
srand((unsigned)time(0));
SkipList inventory;
int choice, id;
string details;
while (true)
{
cout << "\n1. Insert Product\n2. Search Product\n3. Delete Product\n4. Update Product\n5.
Display
Inventory\n6. Exit\nEnter your choice: ";
cin >> choice;
switch (choice)
{
case 1:
cout << "Enter Product ID: ";
cin >> id;
cout << "Enter Product Details: ";
cin.ignore();
getline(cin, details);
inventory.insert(id, details);

17
break;
case 2:
cout << "Enter Product ID to search: ";
cin >> id;
if (auto node = inventory.search(id))
{
cout << "Product Found: " << node->product->id << " - " << node->product->details << endl;
}
else
{
cout << "Product not found!" << endl;
}
break;
case 3:
cout << "Enter Product ID to delete: ";
cin >> id;
inventory.remove(id);
break;
case 4:
cout << "Enter Product ID to update: ";
cin >> id;
cout << "Enter new Product Details: ";
cin.ignore();
getline(cin, details);
inventory.update(id, details);
break;
case 5:
inventory.display();
break;
case 6:
return 0;
default:
cout << "Invalid choice!" << endl;
}
}
return 0;
}

18
OUTPUT:

19
WEEK-3 Date:
AIM: If you are a software engineer tasked with implementing a contact management system. The
system must efficiently handle insertions, deletions, and lookups of contacts. Each contact is identified
by a unique name. Write a program ensuring that the contact list is always balanced and operations
remain efficient (AVL tree).
ALGORITHM:
1. Initialization
1. Input: No input initially, just a tree structure with a root node.
2. Process:
o Define an AVL tree node structure.
o Create an AVL tree class to manage the nodes and operations.
3. Output: An empty AVL tree ready for operations.
2. Insertion
1. Input: A value to insert into the tree.
2. Process:
o Insert the value like in a regular binary search tree (BST).
o Update the height of the affected nodes.
o Check the balance factor at each node.
o Perform rotations (single or double) to restore balance if needed.
3. Output: Updated AVL tree.
3. Deletion
1. Input: A value to delete from the tree.
2. Process:
o Locate the node to delete like in a BST.
o Delete the node and handle cases:
 Leaf node.
 One child.
 Two children (replace with in-order successor).
o Update heights and balance factors.
o Perform rotations if needed.
3. Output: Updated AVL tree.
4. Search
1. Input: A value to search for.
2. Process:
o Traverse the tree using BST rules (go left if smaller, right if larger).
o Stop when the value is found or reach a None node.
3. Output: The node if found, or None.
IMPLEMENTATION:
#include <iostream>

20
#include <string>
using namespace std;
// Node structure for AVL Tree
struct Node
{
string name; // Contact name (acts as the key)
string phoneNumber; // Contact phone number
Node* left; // Pointer to the left child
Node* right; // Pointer to the right child
int height; // Height of the node
Node(string n, string p) : name(n), phoneNumber(p), left(nullptr), right(nullptr), height(1) {}
};

// AVL Tree class


class AVLTree
{
private:
Node* root;

// Utility function to get the height of the tree


int height(Node* node)
{
return node ? node->height : 0;
}
// Utility function to get the balance factor of the node
int getBalance(Node* node)
{
return node ? height(node->left) - height(node->right) : 0;
}
// Right rotate 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;

21
x->height = max(height(x->left), height(x->right)) + 1;
return x;
}
// Left rotate 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 y;
}
Node* insert(Node* node, string name, string phoneNumber)
{
// 1. Perform the normal BST insertion
if (!node)
return new Node(name, phoneNumber);
if (name < node->name)
node->left = insert(node->left, name, phoneNumber);
else if (name > node->name)
node->right = insert(node->right, name, phoneNumber);
else
return node;
node->height = 1 + max(height(node->left), height(node->right));
int balance = getBalance(node);
// Left Left Case
if (balance > 1 && name < node->left->name)
return rightRotate(node);
// Right Right Case
if (balance < -1 && name > node->right->name)
return leftRotate(node);
// Left Right Case
if (balance > 1 && name > node->left->name)
{
node->left = leftRotate(node->left);

22
return rightRotate(node);
}
// Right Left Case
if (balance < -1 && name < node->right->name)
{
node->right = rightRotate(node->right);
return leftRotate(node);
}
return node;
}
Node* minValueNode(Node* node)
{
Node* current = node;
while (current->left != nullptr)
current = current->left;
return current;
}
Node* deleteNode(Node* root, string name)
{
if (root == nullptr)
return root;
if (name < root->name)
root->left = deleteNode(root->left, name);
else if (name > root->name)
root->right = deleteNode(root->right, name);
else
{
if ((root->left == nullptr) || (root->right == nullptr))
{
Node* temp = root->left ? root->left : root->right;
if (temp == nullptr)
{
temp = root;
root = nullptr;
}
else // One child case
*root = *temp; // Copy the contents of the non-empty child
delete temp;
}

23
Else
{
Node* temp = minValueNode(root->right);
root->name = temp->name;
root->phoneNumber = temp->phoneNumber;
root->right = deleteNode(root->right, temp->name);
}
}
if (root == nullptr)
return root;
root->height = 1 + max(height(root->left), height(root->right));
int balance = getBalance(root);
// Left Left Case
if (balance > 1 && getBalance(root->left) >= 0)
return rightRotate(root);
// Left Right Case
if (balance > 1 && getBalance(root->left) < 0)
{
root->left = leftRotate(root->left);
return rightRotate(root);
}
// Right Right Case
if (balance < -1 && getBalance(root->right) <= 0)
return leftRotate(root);
// Right Left Case
if (balance < -1 && getBalance(root->right) > 0)
{
root->right = rightRotate(root->right);
return leftRotate(root);
}
return root;
}
// Recursive function to search for a contact by name
Node* search(Node* root, string name)
{
if (root == nullptr || root->name == name)
return root;
if (root->name < name)
return search(root->right, name);

24
return search(root->left, name);
}
// Function to print the tree (inorder traversal)
void inorder(Node* root)
{
if (root != nullptr)
{
inorder(root->left);
cout << root->name << ": " << root->phoneNumber << endl;
inorder(root->right);
}
}
public:
AVLTree() : root(nullptr)
{
}
void insert(string name, string phoneNumber)
{
root = insert(root, name, phoneNumber);
}
void deleteContact(string name)
{
root = deleteNode(root, name);
}
void searchContact(string name)
{
Node* result = search(root, name);
if (result != nullptr)
cout << "Found contact: " << result->name << " - " << result->phoneNumber << endl;
else
cout << "Contact not found." << endl;
}
void displayContacts()
{
cout << "Contacts (in-order traversal):" << endl;
inorder(root);
}
};
int main()

25
{
AVLTree contacts;
int choice;
string name, phoneNumber;
while (true)
{
cout<<”AVL Operations:”;
cout << "\n1. Insert Contact\n2. Delete Contact\n3. Search Contact\n4. Display Contacts\n5.
Exit\nEnter your choice: ";
cin >> choice;
switch (choice)
{
case 1:
cout << "Enter Contact Name: ";
cin.ignore();
getline(cin, name);
cout << "Enter Phone Number: ";
getline(cin, phoneNumber);
contacts.insert(name, phoneNumber);
break;
case 2:
cout << "Enter Contact Name to delete: ";
cin.ignore();
getline(cin, name);
contacts.deleteContact(name);
break;
case 3:
cout << "Enter Contact Name to search: ";
cin.ignore();
getline(cin, name);
contacts.searchContact(name);
break;
case 4:
contacts.displayContacts();
break;
case 5:
cout << "Exiting program..." << endl;
// 0;
default:

26
return 0;
}
}
}
OUTPUT:

27
WEEK -4 Date:
AIM: Imagine that you are tasked with designing an event scheduling system where events are added
dynamically. Each event is identified by a unique time stamp. Design and implement a program to
ensure that the schedule remains balanced and that operations like insertion, deletion, and lookup are
efficiently(Red-BlackTree)
DESCRIPTION:
Properties of a Red-Black Tree
1. Every node is either red or black.
2. The root node is always black.
3. All leaves (NIL or null nodes) are black.
4. If a node is red, its children must be black (no two consecutive red nodes).
5. Every path from a node to its descendant NIL nodes contains the same number of
black nodes (black height).
ALGORITHM:
1. Initialization
1. Input: A new Red-Black Tree instance.
2. Process:
o Define a node structure with a color attribute.
o Create a Red-Black Tree class to manage the tree operations.
3. Output: An empty Red-Black Tree.
2. Insertion
1. Input: A value to insert into the tree.
2. Process:
o Insert the node as in a regular BST, initially coloring it red.
o Fix any violations of Red-Black Tree properties:
 Case 1: Parent is black (no violation).
 Case 2: Parent is red (requires rebalancing through recoloring and
rotations).
o Ensure the root remains black.
3. Output: Updated Red-Black Tree.
3. Deletion
1. Input: A value to delete.
2. Process:
o Perform standard BST deletion.
o Fix any violations of Red-Black Tree properties:
 Handle cases where a double black occurs due to the deletion.
 Use recoloring and rotations to restore balance.
3. Output: Updated Red-Black Tree.
4. Search
1. Input: A value to search for.

28
2. Process:
o Traverse the tree using BST rules.
o Stop when the value is found or reach a NIL node.
3. Output: The node if found, or None.
IMPLEMENTATION:
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std;
enum Color { RED, BLACK };
// Structure to represent an event node in the Red-Black Tree
struct Event
{
time_t timestamp; // UNIX timestamp
Event *left, *right, *parent;
Color color;
Event(time_t t) : timestamp(t)
{
parent = left = right = nullptr;
color = RED; // New nodes are initially red
}
};
// Class representing the Red-Black Tree
class RBTree
{
private:
Event* root;
// Left rotation
void leftRotate(Event* &pt)
{
Event* pt_right = pt->right;
pt->right = pt_right->left;
if (pt->right != nullptr)
pt->right->parent = pt;
pt_right->parent = pt->parent;
if (pt->parent == nullptr)
root = pt_right;
else if (pt == pt->parent->left)
pt->parent->left = pt_right;

29
else
pt->parent->right = pt_right;
pt_right->left = pt;
pt->parent = pt_right;
}
// Right rotation
void rightRotate(Event* &pt)
{
Event* pt_left = pt->left;
pt->left = pt_left->right;
if (pt->left != nullptr)
pt->left->parent = pt;
pt_left->parent = pt->parent;
if (pt->parent == nullptr)
root = pt_left;
else if (pt == pt->parent->left)
pt->parent->left = pt_left;
else
pt->parent->right = pt_left;
pt_left->right = pt;
pt->parent = pt_left;
}
// Fix violations after insertion
void balanceInsert(Event* &pt)
{
Event* parent_pt = nullptr;
Event* grand_parent_pt = nullptr;
while (pt != root && pt->color != BLACK && pt->parent->color == RED)
{
parent_pt = pt->parent;
grand_parent_pt = pt->parent->parent;
if (parent_pt == grand_parent_pt->left)
{
Event* uncle_pt = grand_parent_pt->right;
if (uncle_pt != nullptr && uncle_pt->color == RED)
{
grand_parent_pt->color = RED;
parent_pt->color = BLACK;
uncle_pt->color = BLACK;

30
pt = grand_parent_pt;
}
else
{
if (pt == parent_pt->right)
{
leftRotate(parent_pt);
pt = parent_pt;
parent_pt = pt->parent;
}
rightRotate(grand_parent_pt);
swap(parent_pt->color, grand_parent_pt->color);
pt = parent_pt;
}
}
else
{
Event* uncle_pt = grand_parent_pt->left;
if (uncle_pt != nullptr && uncle_pt->color == RED)
{
grand_parent_pt->color = RED;
parent_pt->color = BLACK;
uncle_pt->color = BLACK;
pt = grand_parent_pt;
}
else
{
if (pt == parent_pt->left)
{
rightRotate(parent_pt);
pt = parent_pt;
parent_pt = pt->parent;
}
leftRotate(grand_parent_pt);
swap(parent_pt->color, grand_parent_pt->color);
pt = parent_pt;
}
}
}

31
root->color = BLACK;
}
// Insert a new event into the Red-Black Tree
Event* insertEvent(Event* root, Event* pt)
{
if (root == nullptr)
return pt;
if (pt->timestamp < root->timestamp)
{
root->left = insertEvent(root->left, pt);
root->left->parent = root;
}
else if (pt->timestamp > root->timestamp)
{
root->right = insertEvent(root->right, pt);
root->right->parent = root;
}
return root;
}
// Helper function for in-order traversal
void inorderHelper(Event* root)
{
if (root == nullptr)
return;
inorderHelper(root->left);
cout << formatTimestamp(root->timestamp) << " ";
inorderHelper(root->right);
}
// Helper function to search for an event by timestamp
Event* searchHelper(Event* root, time_t timestamp)
{
if (root == nullptr || root->timestamp == timestamp)
return root;
if (timestamp < root->timestamp)
return searchHelper(root->left, timestamp);
return searchHelper(root->right, timestamp);
}
// Helper to format the timestamp into readable date and time
string formatTimestamp(time_t timestamp)

32
{
struct tm * dt;
char buffer[30];
dt = localtime(&timestamp);
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", dt);
return string(buffer);
}
public:
// Constructor
RBTree()
{
root = nullptr;
}
// Function to insert an event
void insert(time_t timestamp)
{
Event* pt = new Event(timestamp);
root = insertEvent(root, pt);
balanceInsert(pt);
}
// Function to search for an event by timestamp
bool search(time_t timestamp)
{
return searchHelper(root, timestamp) != nullptr;
}
// Function to display the events in sorted order
void displaySchedule()
{
if (root == nullptr)
{
cout << "No events scheduled.\n";
}
Else
{
inorderHelper(root);
cout << endl;
}
}
};

33
// Function to read a timestamp in "YYYY-MM-DD HH:MM:SS" format
time_t getTimeStampFromInput()
{
string date, time;
cout << "Enter event date (YYYY-MM-DD): ";
cin >> date;
cout << "Enter event time (HH:MM:SS): ";
cin >> time;
stringstream ss(date + " " + time);
struct tm tm;
ss >> get_time(&tm, "%Y-%m-%d %H:%M:%S");
time_t timestamp = mktime(&tm);
return timestamp;
}
// Main function
int main()
{
RBTree eventScheduler;
int choice;
time_t timestamp;
while (true)
{
cout << "\nEvent Scheduling System\n";
cout << "1. Add Event\n";
cout << "2. Search Event\n";
cout << "3. Display Schedule\n";
cout << "4. Exit\n";
cout << "Enter your choice: ";
cin >> choice;
switch (choice)
{
case 1:
timestamp = getTimeStampFromInput();
eventScheduler.insert(timestamp);
cout << "Event scheduled at " << timestamp << " added.\n";
break;
case 2:
timestamp = getTimeStampFromInput();
if (eventScheduler.search(timestamp))

34
cout << "Event scheduled at " << timestamp << " found.\n";
else
cout << "Event not found.\n";
break;
case 3:
cout << "Scheduled events (in sorted order): ";
eventScheduler.displaySchedule();
break;
case 4:
cout << "Exiting...\n";
return 0;
default:
cout << "Invalid choice! Please select a valid option.\n";
}
}
return 0;
}

35
OUTPUT:

36
WEEK-5 Date:
AIM: Write a program to implement job scheduling, where tasks with higher priority need to
be executed before others.
Hint: A min-heap can be used to always retrieve the task with the highest priority Efficiently
DESCRIPTION:
In this case, tasks with higher priority (i.e., lower numeric priority value) should be
executed before others. The min-heap data structure ensures that tasks with the smallest
priority value are always retrieved first, achieving the desired behavior efficiently.
 Task structure: Each task has a priority and a name.
 The operator< is overloaded so that the priority_queue behaves like a min-heap.
Lower priority numbers represent higher priority tasks.
 priority_queue: A priority queue is used to store tasks. It sorts them based on the
priority such that the task with the lowest priority number is at the top.
 scheduleTasks function: This function executes tasks in order of their priority by
continuously popping the highest-priority task from the heap.
A heap is a binary tree-based data structure that satisfies the heap property:
 For a max-heap, every parent node is greater than or equal to its children.
 For a min-heap, every parent node is less than or equal to its children.
Heaps are commonly implemented as arrays for efficiency.
ALGORITHM:
1. Initialization
1. Input: An empty heap.
2. Process:
o Define an array to store the elements.
o Decide the type of heap (max-heap or min-heap).
3. Output: An empty heap ready for operations.
2. Insertion
1. Input: A value to insert into the heap.
2. Process:
o Add the new value to the end of the array.
o Perform heapify-up (bubble up) to restore the heap property:
 Compare the new node with its parent.
 Swap if the heap property is violated.
 Repeat until the heap property is restored or the node becomes the root.
3. Output: Updated heap.
3. Deletion
1. Input: The root node (for heaps, typically the maximum or minimum element).
2. Process:
o Replace the root with the last element in the array.
o Remove the last element.
o Perform heapify-down (sink down) to restore the heap property:

37
 Compare the node with its children.
 Swap with the larger child (max-heap) or smaller child (min-heap) if
the heap property is violated.
 Repeat until the heap property is restored or the node becomes a leaf.
3. Output: Updated heap.
4. Search
1. Input: A value to search for.
2. Process:
o Perform a linear search on the array (heaps do not support efficient search
beyond the root).
3. Output: Index of the element if found, or None.
IMPLEMENTATION:
#include <iostream>
#include <queue>
#include <vector>
#include <string>
using namespace std;
// Structure to represent a task with priority
struct Task
{
int priority;
string taskName;
// Constructor
Task(int p, string t) : priority(p), taskName(t)
{
}
// Overload the less-than operator to make priority queue work as a min-heap
bool operator<(const Task& other) const
{
return priority > other.priority; // Min-Heap (lower priority value is higher priority)
}
};
// Function to simulate job scheduling
void scheduleTasks(priority_queue<Task> &pq)
{
cout << "\nExecuting tasks in order of priority:\n";
while (!pq.empty())
{
Task currentTask = pq.top(); // Get the task with highest priority

38
pq.pop(); // Remove the task
cout << "Task: " << currentTask.taskName << ", Priority: " << currentTask.priority <<
endl;
}
}
int main()
{
// Create a priority queue (min-heap) for storing tasks
priority_queue<Task> taskQueue;
int numTasks;
cout << "Enter the number of tasks: ";
cin >> numTasks;
// Get tasks and priorities from user
for (int i = 0; i < numTasks; ++i)
{
int priority;
string taskName;
cout << "Enter task name: ";
cin >> ws; // to ignore any leftover newline characters
getline(cin, taskName);
cout << "Enter priority for task \"" << taskName << "\": ";
cin >> priority;
// Add task to the priority queue
taskQueue.push(Task(priority, taskName));
}
// Schedule and execute tasks based on priority
scheduleTasks(taskQueue);
return 0;
}

39
OUTPUT:

40
WEEK-6 Date:
AIM: Assume that you are a software engineer developing a navigation system for a city's
public transportation network. The city map is represented as a graph where each node is a
bus stop and each edge is a direct bus route between stops. You need to implement two
features: finding the shortest path (in terms of the number of stops) from one bus stop to
another using BFS, and checking if there's any path between two bus stops using DFS. –CO2
Description:
❖ Finding the shortest path using Breadth-First Search (BFS): This approach is ideal for
finding the shortest path in an unweighted graph, as BFS explores each node level by level.
❖ Checking if there’s any path between two bus stops using Depth-First Search (DFS): This
will allow us to confirm whether a route exists, regardless of the number of stops.
ALGORITHM:
BFS:
Step 1: Initialize Structures:
 Create a queue q and enqueue the starting node.
 Initialize a visited map to keep track of nodes that have already been visited.
 Initialize a distance map to store the shortest distance from the start node to each other
node.
 Set the distance to the start node as 0.
Step 2:BFS Loop:
1. While the queue is not empty:
2. Dequeue a node current from the front of the queue.
3. For each neighbor of current:
■ If neighbor has not been visited:
■ Mark neighbor as visited.
■ Set the distance to neighbor as distance[current] + 1.
■ Enqueue neighbor.
■ If neighbor is the destination node, return distance[neighbor] as the shortest path.
Step 3: End of BFS:
● If the queue becomes empty without finding the destination, return -1 (indicating no
path exists).
PSEUDO CODE:
Step 1: Initialize queue q
Enqueue start into q
Initialize visited[start] as true
Initialize distance[start] = 0
Step 2: while q is not empty:
current = Dequeue from q
Step 3:for each neighbor in graph[current]:
Step 4: if neighbor is not visited:
visited[neighbor] = true

41
distance[neighbor] = distance[current] + 1
Enqueue neighbor into q
Step 5: if neighbor == destination:
return distance[neighbor] // Shortest path found
return -1 // No path found
DFS:
Step 1:Initialize Structures:
○ Create a visited set (or map) to keep track of nodes that have already been visited.
○ Start from the initial node and mark it as visited.
Step 2:Recursive DFS Function:
○ If the current node is the destination, return true (indicating that a path exists).
○ For each neighbor of the current node:
■ If the neighbor has not been visited:
■ Mark the neighbor as visited.
■ Recursively call the DFS function with the neighbor.
■ If the recursive call returns true, propagate that result back up.
Step 3: End of DFS:
○ If all neighbors have been explored and the destination hasn't been reached, return
false.
PSEUDO CODE:
Algorithm DFS(graph, current, destination, visited):
Step 1: if current == destination:
return true // Path found
visited[current] = true
Step 2:for each neighbor in graph[current]:
Step 3:if neighbor is not visited:
Step 4: if DFS(graph, neighbor, destination, visited) is true:
return true // Path found through neighbor
return false // No path found through this branch
Step 5:Algorithm isPath(graph, start, destination):
Initialize visited as an empty set
return DFS(graph, start, destination, visited)
IMPLEMENTATION:
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_map>
#include <list>

42
using namespace std;
class BusNetwork
{
private:
// Adjacency list to represent the graph
unordered_map<int, list<int>> adjList;
public:
// Method to add a direct route between two stops
void addRoute(int stop1, int stop2)
{
adjList[stop1].push_back(stop2);
adjList[stop2].push_back(stop1); // Assuming undirected routes for simplicity
}
// BFS to find the shortest path in terms of the number of stops
int shortestPath(int source, int destination)
{
if (source == destination)
return 0;
unordered_map<int, bool> visited;
unordered_map<int, int> distance;
queue<int> q;
visited[source] = true;
distance[source] = 0;
q.push(source);
while (!q.empty())
{
int current = q.front();
q.pop();
for (int neighbor : adjList[current])
{
if (!visited[neighbor])
{
visited[neighbor] = true;
distance[neighbor] = distance[current] + 1;
q.push(neighbor);
if (neighbor == destination)
{
return distance[neighbor];
}

43
}
}
}
return -1; // No path found
}
// DFS to check if there's any path between two stops
bool isPath(int source, int destination)
{
unordered_map<int, bool> visited;
return dfs(source, destination, visited);
}
private:
// Helper function for DFS
bool dfs(int current, int destination, unordered_map<int, bool> &visited)
{
if (current == destination)
return true;
visited[current] = true;
for (int neighbor : adjList[current])
{
if (!visited[neighbor])
{
if (dfs(neighbor, destination, visited))
{
return true;
}}
}
return false;
}
};
int main()
{
BusNetwork cityNetwork;
int numRoutes;
cout << "Enter the number of routes to add: ";
cin >> numRoutes;
cout << "Enter each route as two bus stops (stop1 stop2):\n";
for (int i = 0; i < numRoutes; ++i)
{

44
int stop1, stop2;
cin >> stop1 >> stop2;
cityNetwork.addRoute(stop1, stop2);
}
int source, destination;
cout<<"start and end stops for finding shortest path between two stops"<<endl;
cout << "Enter the start stop: ";
cin >> source;
cout<<"enter the destination stop:";
cin>> destination;
int shortest = cityNetwork.shortestPath(source, destination);
if (shortest != -1)
{
cout << "Shortest path from stop " << source<< " to stop " << destination << " is " <<
shortest << " stops.\n";
}
else
{
cout << "No path exists between stop " << source << " and stop " << destination << ".\n";
}
cout << "Enter the start and destination stops to check for any path: ";
cin >> source>> destination;
bool pathExists = cityNetwork.isPath(source, destination);
cout << "Is there a path between stop " << source << " and stop " << destination << "? "
<< (pathExists ? "Yes" : "No") << endl;
return 0;
}
OUTPUT:

45
WEEK -7 Date:
AIM: If you are a civil engineer planning to build a network of roads to connect several
towns.Each town is represented as a node in a graph, and each road between towns is
represented as an edge with a weight (cost) indicating the distance between them. Use Prim's
algorithm to find the minimum cost to connect all towns with roads.
Description:
Graph Representation: The graph is represented as an adjacency list where each town (node)
is connected by roads (edges) with associated costs (weights).
Priority Queue: We use a priority queue (min-heap) to pick the next edge with the smallest
weight efficiently.
MST Construction: Starting from a random node, Prim’s algorithm builds the MST by
adding the edge with the minimum cost that connects a new node to the MST.
Edge Selection and Update: For each node added to the MST, update the minimum costs of
the remaining nodes, ensuring they are connected via the lowest possible cost.
ALGORITHM:
Step 1: Initialize:
minCost[] = [∞, ∞, ..., ∞] // Minimum cost to connect each town
inMST[] = [false, false, ..., false] // Track if town is in MST
totalCost = 0 // Accumulate MST cost
pq = priority_queue (min-heap)
Step 2: Set starting town's minCost to 0:
minCost[0] = 0
pq.push((0, 0)) // Push (cost, town) into priority queue
Step 3: While pq is not empty:
a. cost, town = pq.top()
b. pq.pop() // Remove the town with the smallest cost
c. If town is already in MST:
continue
d. Mark town as included in MST:
inMST[town] = true
totalCost += cost
e. For each neighbor of town:
i. If neighbor is not in MST and edge_cost < minCost[neighbor]:
- Update minCost[neighbor] to edge_cost
- Push (edge_cost, neighbor) into pq
Step 4: Output totalCost as the minimum cost to connect all towns.
IMPLEMENTATION:
#include <iostream>
#include <vector>
#include <climits>
#include <queue>
46
using namespace std;
struct Edge
{
int to;
int weight;
Edge(int to, int weight) : to(to), weight(weight)
{}
};
// Function to calculate the minimum cost to connect all towns
int primMST(int n, vector<vector<Edge>>& graph)
{
vector<int> minCost(n, INT_MAX); // Store the minimum cost to add each town to the MST
vector<bool> inMST(n, false); // Track nodes included in the MST
int totalCost = 0;
// Priority queue to select edges with minimum weight
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
minCost[0] = 0; // Start from node 1 (1-based, shifted to 0-based for indexing)
pq.push({0, 0}); // {cost, node}
while (!pq.empty())
{
int cost = pq.top().first;
int u = pq.top().second;
pq.pop();
if (inMST[u]) continue; // Skip if already in MST
inMST[u] = true;
totalCost += cost;
for (Edge& edge : graph[u])
{
int v = edge.to;
int weight = edge.weight;
if (!inMST[v] && weight < minCost[v])
{
minCost[v] = weight;
pq.push({weight, v});
}
}
}
return totalCost;
}

47
int main()
{
int n, m;
cout << "Enter the number of towns (nodes):";
cin>>n;
cout<<"enter the number of roads (edges): ";
cin >>m;
vector<vector<Edge>> graph(n);
cout << "Enter the roads (edges) with towns (nodes) and their costs (distances):" << endl;
for (int i = 0; i < m; i++)
{
int u, v, weight;
cin >> u >> v >> weight;
u--; // Shift to 0-based indexing
v--; // Shift to 0-based indexing
graph[u].push_back(Edge(v, weight));
graph[v].push_back(Edge(u, weight)); // Undirected graph
// cout << "Added edge: " << u << " <-> " << v<< " with cost " << weight << endl;
}
int result = primMST(n, graph);
cout << "Minimum cost to connect all towns: " << result << endl;
return 0;
}
OUTPUT:

48
WEEK-8 Date:
AIM: If you are a project manager overseeing the construction of a network of bridges to
connect several islands. Each island is represented as a node in a graph, and each potential
bridge between islands is represented as an edge with a weight (cost) indicating the
construction cost. Use Kruskal's algorithm to find the minimum cost to connect all islands
with bridges. – CO2
DESCRIPTION:
1. Sorting all edges by their weight.
2. Iteratively adding edges with the smallest weights to the MST, ensuring no cycles are
formed.
3. Using a Union-Find (Disjoint Set Union) data structure to efficiently manage and detect
cycles.
ALGORITHM:
Step 1: Sort all edges in ascending order by their weights.
Step 2: Initialize MST as empty and set total cost to 0.
Step 3: Use Union-Find to check if adding an edge creates a cycle:
 For each edge (u, v) in sorted order:
 If u and v are not in the same set, add the edge to the MST and unite u and v in the
Union-Find structure.
 Add the edge’s weight to the total cost.
Step 4: Repeat until all nodes are connected or we have added n-1 edges (where n is the
number of
nodes).
IMPLEMENTATION:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Edge
{
int u, v, weight;
Edge(int u, int v, int weight) : u(u), v(v), weight(weight)
{}
};
// Compare function to sort edges by weight
bool compareEdge(const Edge& e1, const Edge& e2)
{
return e1.weight < e2.weight;
}
// Disjoint Set Union-Find with path compression and union by rank

49
class UnionFind
{
vector<int> parent, rank;
public:
UnionFind(int n)
{
parent.resize(n);
rank.resize(n, 0);
for (int i = 0; i < n; i++)
{
parent[i] = i;
}
}
int find(int x)
{
if (parent[x] != x)
{
parent[x] = find(parent[x]);
}
return parent[x];
}
void unite(int x, int y)
{
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY)
{
if (rank[rootX] > rank[rootY])
{
parent[rootY] = rootX;
}
else if (rank[rootX] < rank[rootY])
{
parent[rootX] = rootY;
}
else
{
parent[rootY] = rootX;
rank[rootX]++;

50
}
}
}
};
// Function to calculate minimum cost to connect all islands
int kruskalMST(int n, vector<Edge>& edges)
{
// Sort all edges by weight
sort(edges.begin(), edges.end(), compareEdge);
UnionFind uf(n);
int totalCost = 0;
int edgesUsed = 0;
// Iterate over sorted edges and add to MST if no cycle
for (const Edge& edge : edges)
{
if (uf.find(edge.u) != uf.find(edge.v))
{
uf.unite(edge.u, edge.v);
totalCost += edge.weight;
edgesUsed++;
if (edgesUsed == n - 1)
break; // Stop if we have enough edges
}
}
return totalCost;
}
int main()
{
int n, m;
cout << "Enter the number of islands (nodes):";
cin>>n;
cout<<"Enter the potential bridges (edges): ";
cin >>m;
vector<Edge> edges;
vector<int> weights; // To store and later sort the weights
cout << "Enter each bridge (edge) with islands (nodes) and the construction cost:" << endl;
for (int i = 0; i < m; i++)
{
int u, v, weight;

51
cin >> u >> v >> weight;
u--; // Shift to 0-based indexing
v--; // Shift to 0-based indexing
edges.push_back(Edge(u, v, weight));
weights.push_back(weight); // Add weight to the list for sorting
}
// Sort weights and print them
sort(weights.begin(), weights.end());
cout << "Weights of all edges in sorted order: ";
for (int w : weights)
{
cout << w << " ";
}
cout << endl;
int result = kruskalMST(n, edges);
cout << "Minimum cost to connect all islands: " << result << endl;
return 0;
}
OUTPUT:

52
WEEK-9 Date:
AIM: Imagine that you are a logistics manager planning the most efficient route for
delivering goods between cities. Each city is represented as a node in a graph, and each direct
route between cities is represented as an edge with a weight (distance or travel time). Apply
Dijkstra's algorithm to find the shortest path from a starting city to a destination city. CO2
Description:
Graph Representation: The graph is represented using an adjacency list where each city
(node) has a list of pairs representing neighboring cities and the distance (weight) to them.
ALGORITHM:
Step 1: Initialize Distances:
○ Create a distance array to store the minimum distance from the source to each node.
Set the distance to the source node as 0 and all other nodes as infinity (∞).
Step 2: Initialize Priority Queue:
○ Use a min-heap (or priority queue) to keep track of nodes with the current smallest
known distance from the source.
○ Insert the source node into the priority queue with a distance of 0.
Step 3: Initialize Parent Array (Optional):
○ To track the shortest path, create a parent array to store the predecessor of each node in
the path.
Step 4: Processing Nodes:
○ While the priority queue is not empty:
1. Extract the node u with the minimum distance from the priority queue.
2. For each neighbor v of u(all nodes directly connected to u):
■ Calculate the distance from the source to v through u:
■ new_distance = distance[u] + weight(u, v).
■ If new_distance is less than distance[v], update distance[v] with new_distance.
■ Update the parent array for v to track the path.
■ Insert or update v in the priority queue with its new distance.
Step 5. Repeat Until Queue is Empty:
○ Continue extracting nodes with the shortest known distance and updating distances for
neighbors until the priority queue is empty.
Step 6: Output the Results:
○ The distance array now holds the shortest path distances from the source to each node.
○ If tracking paths, use the parent array to reconstruct the path from the source to any
destination node.
PSEUDO CODE:
function Dijkstra(Graph, source):
Step 1:initialize distance array with all values as infinity distance[source] = 0
Step 2: initialize min-heap priority queue PQ
insert (0, source) into PQ

53
Step 3: while PQ is not empty:
u = node in PQ with minimum distance
remove u from PQ
Step 4: for each neighbor v of u:
weight = edge weight from u to v
if distance[u] + weight < distance[v]:
distance[v] = distance[u] + weight
parent[v] = u // optional, for path tracking
insert (distance[v], v) into PQ
return distance
IMPLEMENTATION :
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;
typedef pair<int, int> Pair;
class Graph
{
int V; // Number of cities
vector<vector<Pair>> adjList;
public:
Graph(int V)
{
this->V = V;
adjList.resize(V);
}
// Adds an edge, adjusting for 1-based to 0-based indexing
void addEdge(int u, int v, int weight)
{
adjList[u - 1].push_back({v - 1, weight}); // 1-based to 0-based
adjList[v - 1].push_back({u - 1, weight}); // For undirected graph
}
void dijkstra(int src, int dest)
{
vector<int> dist(V, INT_MAX);
dist[src - 1] = 0; // 1-based to 0-based
priority_queue<Pair, vector<Pair>, greater<Pair>> pq;
pq.push({0, src - 1}); // 1-based to 0-based

54
vector<int> parent(V, -1);
while (!pq.empty())
{
int u = pq.top().second;
pq.pop();
if (u == dest - 1) break; // 1-based to 0-based
for (auto &neighbor : adjList[u])
{
int v = neighbor.first;
int weight = neighbor.second;
if (dist[u] + weight < dist[v])
{
dist[v] = dist[u] + weight;
pq.push({dist[v], v});
parent[v] = u;
}
}
}
cout << "Shortest distance from city " << src << " to city " << dest << " is: " << dist[dest - 1]
<< endl;
cout << "Path: ";
printPath(parent, dest - 1);
cout << endl;
}
void printPath(vector<int> &parent, int city)
{
if (city == -1)
return;
printPath(parent, parent[city]);
cout << city + 1 << " "; // Convert back to 1-based for output
}
};
int main()
{
int V, E;
cout << "Enter the number of cities (nodes): ";
cin >> V;
Graph g(V);
cout << "Enter the number of routes (edges): ";

55
cin >> E;
cout << "Enter each route as: <start_city> <end_city> <distance>\n";
for (int i = 0; i < E; ++i)
{
int u, v, weight;
cin >> u >> v >> weight;
g.addEdge(u, v, weight);
}
int src, dest;
cout << "Enter the starting city: ";
cin >> src;
cout << "Enter the destination city: ";
cin >> dest;
g.dijkstra(src, dest);
return 0;
}
OUTPUT:

56
WEEK-10 Date:
AIM: Assume that you are a software developer working for a cybersecurity company. Your
task is to build a tool that scans large text files for specific patterns of malicious code
signatures. Apply Boyer-Moore pattern matching algorithm to implement this task.
Description:
The Boyer-Moore algorithm takes a 'backward' approach: the pattern string (P) is aligned
with the start of the text string (T), and then compares the characters of a pattern from right to
left, beginning with rightmost character.
If a character is compared that is not within the pattern, no match can be found by analyzing
any further aspects at this position so the pattern can be changed entirely past the
mismatching character.
The two strategies are called heuristics of Boyer - Moore as they are used to reduce the
search. They are:
 Bad Character Heuristics
 Good Suffix Heuristics
1. Bad Character Heuristics:
This Heuristics has two implications:
 Suppose there is a character in a text in which does not occur in a pattern at all. When
a mismatch happens at this character (called as bad character), the whole pattern can
be changed, begin matching form substring next to this 'bad character.'
 On the other hand, it might be that a bad character is present in the pattern, in this case,
align the nature of the pattern with a bad character in the text.
 Thus in any case shift may be higher than one.
2. Good Suffix Heuristics:
A good suffix is a suffix that has matched successfully. After a mismatch which has a
negative shift in bad character heuristics, look if a substring of pattern matched till bad
character has a good suffix in it, if it is so then we have an onward jump equal to the length of
suffix found.
IMPLEMENTATION:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <unordered_map>
#include <algorithm>
using namespace std;
// Function to preprocess the bad character heuristic
void badCharacterHeuristic(const string &pattern, unordered_map<char, int> &badCharTable)
{
int m = pattern.size();
for (int i = 0; i < m; i++)
{

57
badCharTable[pattern[i]] = i;
}
}
// Boyer-Moore string matching algorithm
vector<int> boyerMoore(const string &text, const string &pattern) {
int n = text.size();
int m = pattern.size();
vector<int> matches;
// Bad character table initialization
unordered_map<char, int> badCharTable;
badCharacterHeuristic(pattern, badCharTable);
int i = 0;
while (i <= n - m)
{
int j = m - 1;
// Compare the pattern from right to left with the text
while (j >= 0 && pattern[j] == text[i + j])
{
j--;
}
// If we have a match, store the index
if (j < 0)
{
matches.push_back(i);
// Shift the pattern using the bad character heuristic
i += (i + m < n) ? m - badCharTable[text[i + m]] : 1;
} else
{
// Shift the pattern using the bad character heuristic
i += max(1, j - badCharTable[text[i + j]]);
}
}
return matches;
}
// Function to scan the file and find the pattern
void scanFileForPattern(const string &filename, const string &pattern)
{
ifstream file(filename);
if (!file.is_open())

58
{
cerr << "Error opening file!" << endl;
return;
}
string line;
int lineNumber = 0;
while (getline(file, line))
{
lineNumber++;
vector<int> matches = boyerMoore(line, pattern);
if (!matches.empty())
{
cout << "Pattern found in line " << lineNumber << " at positions: ";
for (int pos : matches)
{
cout << pos << " ";
}
cout << endl;
}
}
file.close();
}
int main()
{
// Specify the file to scan and the pattern to search for
string filename = "myfile.txt"; // Replace with the actual file path
string pattern = "malicious_code_signature"; // Replace with the actual malicious pattern
// Scan the file for the pattern
scanFileForPattern(filename, pattern);
return 0;
}
Text file: myfile.txt
This is a normal line.
Here is a malicious_code_signature in the middle.
Another line with malicious_code_signature at the end.
Just a normal line again.
OUTPUT :
Pattern found in line 2 at positions: 10
Pattern found in line 3 at positions: 18

59
WEEK-11 Date:
AIM: Imagine you are working for a security software company that monitors large logs of
network activity to detect potential intrusions or malicious behaviour. One of the tasks
involves searching for known malicious patterns within the network logs. You have a large
log file where each entry is a sequence of characters representing network packets. You need
to search for a specific pattern that indicates a potential attack. This pattern can occur
multiple times within the log, and the log itself is very large. (Knuth-Morris-Pratt algorithm).
CO3
ALGORITHM:
Steps in the KMP Algorithm
1. Build the LPS Array:
 Iterate through the pattern and populate the LPS array.
 For each character in the pattern, calculate the length of the longest proper prefix
which is also a suffix.
2. Use the LPS Array for Pattern Matching:
 Traverse through the text, matching the pattern with the text.
 If there is a mismatch, use the LPS array to skip ahead in the pattern, rather than
restarting the match from the beginning.
PSEUDO CODE FOR CREATION OF LPS:
function computeLPSArray(pattern, m):
lps = array of size m initialized to 0
length = 0 // Length of the previous longest prefix suffix
i = 1 // Start from the second character
while i < m:
if pattern[i] == pattern[length]:
length = length + 1
lps[i] = length
i=i+1
else:
if length != 0:
length = lps[length - 1]
else:
lps[i] = 0
i=i+1
return lps
PSEUDO CODE FOR PATTERN MATCHING:
function KMPSearch(text, pattern, n, m):
lps = computeLPSArray(pattern, m)
occurrences = empty list to store match indices
i = 0 // Index for text
j = 0 // Index for pattern

60
while i < n:
if pattern[j] == text[i]:
i=i+1
j=j+1
if j == m: // A full match is found
occurrences.append(i - j)
j = lps[j - 1] // Use LPS to continue searching
elif i < n and pattern[j] != text[i]: // Mismatch after j matches
if j != 0:
j = lps[j - 1]
else:
i=i+1
return occurrences
IMPLEMENTATION:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// Function to preprocess the pattern and build the LPS (Longest Prefix Suffix) array
void computeLPSArray(const string& pattern, vector<int>& lps)
{
int length = 0; // Length of the previous longest prefix suffix
lps[0] = 0; // LPS for the first character is always 0
int i = 1;
while (i < pattern.size())
{
if (pattern[i] == pattern[length])
{
length++;
lps[i] = length;
i++;
}
else
{
if (length != 0)
{
length = lps[length - 1];
}
else

61
{
lps[i] = 0;
i++;
}
}
}
}
// KMP search function to find all occurrences of the pattern in the text
vector<int> KMPSearch(const string& log, const string& pattern)
{
int n = log.size();
int m = pattern.size();
vector<int> lps(m);
computeLPSArray(pattern, lps);
vector<int> occurrences; // To store the indices where the pattern is found
int i = 0; // Index for log
int j = 0; // Index for pattern
while (i < n)
{
if (pattern[j] == log[i])
{
i++;
j++;
}
if (j == m)
{
occurrences.push_back(i - j);
j = lps[j - 1];
}
else if (i < n && pattern[j] != log[i])
{
if (j != 0)
{
j = lps[j - 1];
}
else
{
i++;
}

62
}
}
return occurrences;
}
int main()
{
// Get log and pattern inputs from the user
string log, pattern;
cout << "Enter the network log data: ";
getline(cin, log);
cout << "Enter the malicious pattern to search: ";
getline(cin, pattern);
// Perform KMP search
vector<int> occurrences = KMPSearch(log, pattern);
if (!occurrences.empty())
{
cout << "Pattern found at indices: ";
for (int index : occurrences)
{
cout << index << " ";
}
cout << endl;
}
else
{
cout << "Pattern not found in the log." << endl;
}
return 0;
}
OUTPUT

63
WEEK-12 Date:
AIM: Imagine you work for a company that develops a search engine. One of your tasks is to
implement an autocomplete feature for search queries. The autocomplete feature should
suggest possible completions of a user's partial input in real-time. This requires efficient
storage and retrieval of a large dictionary of terms. You need to design a system that can
quickly suggest words based on a prefix provided by the user. The dictionary of terms is large,
containing thousands of words, and the system needs to handle real-time user input with
minimal delay. Write a program to check and correct misspelled words in a given text
ALGORITHM:
1. Data Structure Initialization
Step 1:Define a TrieNode structure:
 Contains an array Trie[256] for all possible characters.
 A boolean isEnd to mark the end of a word.
Step 2: Define a constructor for TrieNode:
 Initialize all elements of Trie to NULL.
 Set isEnd to false.
2. Insert a Word into the Trie
Function: InsertTrie(root, string s)
Step 1:Initialize a pointer temp to root.
Step 2: For each character c in string s:
 If temp->Trie[c] is NULL
 create a new TrieNode at that position.
 Move temp to temp->Trie[c].
Step 3:After processing all characters, set temp->isEnd = true.
3. Check if a Word is Present in the Trie
Function: checkPresent(root, string key)
Step 1:Initialize a pointer temp to root.
Step 2:For each character c in the string key:
 If temp->Trie[c] is NULL,
 print suggestions for the prefix up to key[0..i] and return false.
 Move temp to temp->Trie[c].
Step 3: If the end of the string is reached and temp->isEnd is true, return true.
Step 4:Otherwise, print suggestions for the prefix key and return false.
4. Auto-Complete Suggestions for a Prefix
Function: autoComplete(root, string prefix)
Step 1:Initialize a pointer temp to root.
Step 2:For each character c in the string prefix:
 If temp->Trie[c] is NULL, print "No suggestions found for prefix" and return.
 Move temp to temp->Trie[c].
Step 3:Call the helper function printSuggestions(temp, prefix) to print all suggestions starting
from the node temp.

64
5. Helper Function to Collect Suggestions
Function: printSuggestions(root, string res)
Step 1:If root->isEnd == true, print res as it forms a complete word.
Step 2:For each possible character i (0 to 255):
If root->Trie[i] is not NULL:
 Append the character i to res.
 Recursively call printSuggestions(root->Trie[i], res).
 Remove the last character from res (backtracking).
IMPLEMENTATION:
#include <bits/stdc++.h>
using namespace std;
// Structure of a Trie node
struct TrieNode
{
TrieNode* Trie[256];
bool isEnd;
TrieNode() {
for (int i = 0; i < 256; i++)
{
Trie[i] = NULL;
}
isEnd = false;
}
};
// Function to insert a string into the Trie
void InsertTrie(TrieNode* root, string s)
{
TrieNode* temp = root;
for (int i = 0; i < s.length(); i++)
{
if (temp->Trie[s[i]] == NULL)
{
temp->Trie[s[i]] = new TrieNode();
}
temp = temp->Trie[s[i]];
}
temp->isEnd = true;
}
// Function to print auto-suggestions for a prefix

65
void printSuggestions(TrieNode* root, string res)
{
if (root->isEnd == true)
{
cout << res << " ";
}
for (int i = 0; i < 256; i++)
{
if (root->Trie[i] != NULL)
{
res.push_back(i);
printSuggestions(root->Trie[i], res);
res.pop_back();
}
}
}
// Function to provide auto-suggestions for a prefix
void autoComplete(TrieNode* root, string prefix)
{
TrieNode* temp = root;
for (char c : prefix)
{
if (temp->Trie[c] == NULL)
{
cout << "No suggestions found for prefix \"" << prefix << "\"." << endl;
return;
}
temp = temp->Trie[c];
}
cout << "Suggestions for prefix \"" << prefix << "\": ";
printSuggestions(temp, prefix);

cout << endl;


}
// Function to check if a string is present in the Trie or provide suggestions for misspelled
words
bool checkPresent(TrieNode* root, string key)
{
TrieNode* temp = root;

66
for (int i = 0; i < key.length(); i++)
{
if (temp->Trie[key[i]] == NULL)
{
cout << "Suggestions for prefix \"" << key.substr(0, i) << "\": ";
printSuggestions(root, key.substr(0, i));
cout << endl;
return false;
}
temp = temp->Trie[key[i]];
}
if (temp->isEnd)
{
return true;
}
cout << "Suggestions for prefix \"" << key << "\": ";
printSuggestions(temp, key);
cout << endl;
return false;
}
// Driver Code
int main()
{
TrieNode* root = new TrieNode();
vector<string> dictionary;
string word, prefix, key;
int n, choice;
// Input words into the Trie
cout << "Enter the number of strings to insert into the Trie: ";

cin >> n;
cin.ignore(); // Clear input buffer
cout << "Enter the strings:" << endl;
for (int i = 0; i < n; i++)
{
getline(cin, word);
dictionary.push_back(word);
}
// Insert all words into the Trie

67
for (const auto& s : dictionary)
{
InsertTrie(root, s);
}
while (true)
{
cout << "\nMenu:\n";
cout << "1. Check if a word is present\n";
cout << "2. Get auto-suggestions for a prefix\n";
cout << "3. Exit\n";
cout << "Enter your choice: ";
cin >> choice;
cin.ignore(); // Clear input buffer
if (choice == 1) {
cout << "Enter the word to check: ";
getline(cin, key);
if (checkPresent(root, key)) {
cout << "The word \"" << key << "\" is present in the Trie." << endl;
} else {
cout << "The word \"" << key << "\" is NOT present in the Trie." << endl;
}
} else if (choice == 2) {
cout << "Enter the prefix: ";
getline(cin, prefix);
autoComplete(root, prefix);
} else if (choice == 3) {
cout << "Exiting the program." << endl;
break;

} else {
cout << "Invalid choice. Please try again." << endl;
}
}
return 0;
}

68
OUTPUT:

69

You might also like