CC Lab 2 Report
CC Lab 2 Report
Report
Submitted By :
Mehak Aftab
2021-CS-92
15 September 2024
2 Object-Oriented Programming 5
2.1 Classes and Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.3 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.4 Virtual Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4 Templates 10
4.1 Function Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.2 Class Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.3 Template Specialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5 Algorithms 12
5.1 Sorting Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
5.1.1 std::sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
5.1.2 std::stables or t . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
5.2 Searching Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
5.2.1 std::binarys ear ch . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
5.2.2 std::find . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
6 Concurrency 14
6.1 Multithreading with std::thread . . . . . . . . . . . . . . . . . . . . . . . . . 14
6.2 Mutexes and Locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
7 Problems 15
7.1 Task 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
7.2 Task 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
7.3 Task 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
7.4 Task 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
7.5 Task 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2
7.6 Task 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
7.7 Task 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
7.8 Task 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
7.9 Task 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
7.10 Task 10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
7.11 Task 11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
7.12 Task 12 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3
List of Figures
1 Task 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2 Task 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3 Task 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4 Task 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
5 Task 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
6 Task 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
7 Task 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
8 Task 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
9 Task 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
10 Task 10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
11 Task 11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
12 Task 12 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4
1 Memory Management
C++ allows to allocate memory dynamically in run-time. This is called Dynamic Memory
Allocation where we need to deallocate the dynamically allocated memory after we have no
use for a variable. For this purpose, we use “new” and “delete” operators to allocate and
deallocate memory respectively.
New Operator:
data_type* pointer_variable = new data_typevalue;
Delete Operator:
delete pointer_variable;
2 Object-Oriented Programming
2.1 Classes and Objects
A class is a blueprint for creating objects. It defines properties (attributes) and behaviors
(methods) which an object of the class can have.
An Object is an instance of a class. It holds the data and performs operations defined by its
class.
class Car {
public:
string model;
string color;
void drive() {
cout << "Driving the car." << endl;
}
};
int main() {
Car myCar; //Object of class Car
myCar.model = "Toyota";
myCar.color = "Red";
myCar.drive();
}
2.2 Struct
It is similar to a class but for simpler data structures. By default members of a struct are
public.
struct Book {
string title;
5
string author;
double price;
};
int main() {
Book myBook;
myBook.title = "Engineering a Compiler";
myBook.author = " Keith D. Cooper & Linda Torczon ";
myBook.price = 39.99;
}
2.3 Inheritance
This allows a new class (derived class) to inherit properties and behaviors from an existing
class (base class). It helps in re-using code and maintain hierarchical relationships between
classes.
class Animal {
public:
void eat() {
cout << "Eating" << endl;
}
};
int main() {
Dog myDog;
myDog.eat(); // Inherited from Animal
myDog.bark(); // Defined in Dog
}
6
public:
virtual void sound() { // Virtual function
cout << "Animal sound" << endl;
}
};
int main() {
Animal* myAnimal = new Dog(); // Base class pointer pointing to derived class objec
myAnimal->sound(); // Outputs: Bark, because of runtime polymorphism
}
Vectors are better when you need quick access by index or when you know there is frequent
re-sizing of an array.
3.2 Lists
It is doubly linked list, which means every element has pointers to both the previous and next
element. Doubly linked list use more memory space due to this than singly linked list as it
points to the next element only.
7
Lists are better than vectors when you need to make frequent insertions and deletions at
specific positions without shifting elements.
3.3 Deque
It allows insertion and deletion of elements from both ends. It can be implemented both as
a dynamic array or a doubly linked list.
Deque is better in scenarios when you need fast access at both ends, e.g. sliding window
scenario.
3.4 Stack
It is a last-In, First-Out data structure where elements are added and removed from top.
3.5 Queue
It is a First-In, First-Out data structure where elements are added at the back and removed
from the front.
8
3.6 Priority Queue
It is a special type of queue where each element is associated with a priority, and elements
are removed in order of their priority.
Insert: O(log n)
Find: O(1) to find the element with highest priority
Delete: O(log n) to remove the element with highest priority
It is better when we need to manage dynamic sets of elements with varying priorities.
3.7 Set
It is a collection of unique elements. [Implemented as a balanced binary search tree (like a
Red-Black Tree)]
Insert: O(log n)
Find: O(log n)
Delete: O(log n)
Set is better than unordered set when we need to maintain a sorted collection of unique
elements.
3.8 Map
It is a collection of key-value pairs, where each key is unique. [Implemented as a balanced
binary search tree (like a Red-Black Tree)]
Insert: O(log n)
Find: O(log n)
Delete: O(log n)
It is better when we need to maintain a sorted collection of key-value pairs and require ordered
traversal.
9
Insert: O(1) on average while in case of collisions O(n)
Find: O(1) on average otherwise O(n)
Delete: O(1) on average otherwise O(n)
Unordered maps/sets are better than ordered maps/sets when order of elements does not
matter and you need fast access to elements.
4 Templates
4.1 Function Templates
They allow us to create generic functions that can operate on different data types without
rewriting the same function for each type. We define the function template once, and the
compiler generates the appropriate function according to the specific data type.
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
int x = 5, y = 10;
double p = 5.5, q = 10.5;
cout << add(x, y) << endl; // Calls add<int>
cout << add(p, q) << endl; // Calls add<double>
return 0;
}
10
int main() {
Pair<int> intPair(1, 2);
Pair<double> doublePair(3.4, 5.6);
cout << intPair.getFirst() << ", " << intPair.getSecond() << endl;
cout << doublePair.getFirst() << ", " << doublePair.getSecond() << endl;
return 0;
}
int main() {
Printer<int> intPrinter;
intPrinter.print(42); // Calls generic print
Printer<char*> charPrinter;
charPrinter.print("Hello"); // Calls specialized print
return 0;
}
11
5 Algorithms
5.1 Sorting Algorithms
5.1.1 std::sort
It is a non-stable sorting algorithm that sorts elements in ascending order by default using
the < operator.
Average case: O(N log N), Worst Case: O(N log N)
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {4, 2, 3, 1, 5};
std::sort(vec.begin(), vec.end());
for(int v : vec) {
std::cout << v << " "; // Output: 1 2 3 4 5
}
return 0;
}
5.1.2 std::stables or t
It is a stable sorting algorithm which means that it preserves the relative order of elements
with equal keys.
Average case: O(N log N), Worst Case: O(N log N)
#include <algorithm>
#include <vector>
#include <iostream>
struct Person {
std::string name;
int age;
};
int main() {
std::vector<Person> people = {{"Alice", 30}, {"Bob", 25}, {"Charlie", 25}};
12
std::stable_sort(people.begin(), people.end(), compareByAge);
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
bool found = std::binary_search(vec.begin(), vec.end(), 3);
std::cout << (found ? "Found" : "Not Found") << std::endl; // Output: Found
return 0;
}
5.2.2 std::find
It searches for the first occurrence of a value in a range.
Complexity: 0(N)
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {4, 2, 3, 1, 5};
auto it = std::find(vec.begin(), vec.end(), 3);
if (it != vec.end()) {
std::cout << "Found: " << *it << std::endl; // Output: Found: 3
13
} else {
std::cout << "Not Found" << std::endl;
}
return 0;
}
6 Concurrency
6.1 Multithreading with std::thread
It is a class in the C++ Standard Library which represents a single thread of execution.
Threads are used to perform tasks concurrently.
#include <iostream>
#include <thread>
int main() {
std::thread thread1(printMessage, "Hello from thread 1", 5);
std::thread thread2(printMessage, "Hello from thread 2", 5);
14
std::mutex mtx; // Mutex for critical section
int sharedCounter = 0;
int main() {
std::thread thread1(incrementCounter, 5);
std::thread thread2(incrementCounter, 5);
thread1.join();
thread2.join();
std::cout << "Final counter value: " << sharedCounter << std::endl;
return 0;
}
7 Problems
7.1 Task 1
#include <iostream>
#include <vector>
int main() {
std::vector<int> studentGrades;
15
Capacity: " << studentGrades.capacity() << std::endl;
studentGrades.push_back(85);
studentGrades.push_back(90);
studentGrades.push_back(78);
studentGrades.push_back(92);
studentGrades.push_back(88);
studentGrades.push_back(76);
studentGrades.push_back(95);
studentGrades.push_back(83);
int index = 3;
if (index < studentGrades.size()) {
std::cout << "\nGrade at index " << index << ": " <<
studentGrades[index] << std::endl;
}
index = 2;
if (index < studentGrades.size()) {
studentGrades.erase(studentGrades.begin() + index);
std::cout << "\nAfter deleting the grade at index " <<
index << ":" << std::endl;
displayGrades(studentGrades);
}
studentGrades.push_back(89);
studentGrades.push_back(91);
return 0;
}
16
Figure 1: Task 1
7.2 Task 2
#include <iostream>
#include <string>
class WebPage {
public:
string url;
WebPage* prev;
WebPage* next;
class DoublyLinkedList {
private:
WebPage* head;
WebPage* tail;
WebPage* current;
public:
DoublyLinkedList() : head(nullptr), tail(nullptr), current(nullptr) {}
17
void addPage(string url) {
WebPage* newPage = new WebPage(url);
if (!head) {
head = tail = current = newPage;
} else {
newPage->prev = current;
if (current->next) {
WebPage* temp = current->next;
while (temp) {
WebPage* toDelete = temp;
temp = temp->next;
delete toDelete;
}
}
current->next = newPage;
tail = newPage;
current = newPage;
}
cout << "Visited: " << url << endl;
}
void moveForward() {
if (current && current->next) {
current = current->next;
cout << "Moved forward to: " << current->url << endl;
} else {
cout << "No more pages to move forward to." << endl;
}
}
void moveBackward() {
if (current && current->prev) {
current = current->prev;
cout << "Moved backward to: " << current->url << endl;
} else {
cout << "No more pages to move backward to." << endl;
}
}
void deleteCurrentPage() {
if (!current) {
cout << "No current page to delete." << endl;
18
return;
}
if (current == head)
head = current->next;
if (current == tail)
tail = current->prev;
void printCurrentPage() {
if (current) {
cout << "Current page: " << current->url << endl;
} else {
cout << "No current page." << endl;
}
}
~DoublyLinkedList() {
while (head) {
WebPage* temp = head;
head = head->next;
delete temp;
}
}
};
int main() {
DoublyLinkedList browserHistory;
browserHistory.addPage("http://example.com");
browserHistory.addPage("http://example.com/page1");
browserHistory.addPage("http://example.com/page2");
19
browserHistory.moveBackward();
browserHistory.printCurrentPage();
browserHistory.moveForward();
browserHistory.printCurrentPage();
browserHistory.deleteCurrentPage();
browserHistory.printCurrentPage();
return 0;
}
Figure 2: Task 2
7.3 Task 3
#include <iostream>
#include <deque>
#include <string>
class TaskScheduler {
private:
deque<string> taskDeque;
20
public:
void addHighPriorityTask(const string& task) {
taskDeque.push_front(task);
cout << "Added high priority task at the front: " << task
<< endl;
}
void removeFrontTask() {
if (!taskDeque.empty()) {
cout << "Removed task from the front: " <<
taskDeque.front() << endl;
taskDeque.pop_front();
} else {
cout << "No tasks to remove from the front." << endl;
}
}
void removeBackTask() {
if (!taskDeque.empty()) {
cout << "Removed task from the back: " <<
taskDeque.back() << endl;
taskDeque.pop_back();
} else {
cout << "No tasks to remove from the back." << endl;
}
}
void viewFrontTask() {
if (!taskDeque.empty()) {
cout << "Task at the front: " << taskDeque.front() <<
endl;
} else {
cout << "No tasks at the front." << endl;
}
}
void viewBackTask() {
if (!taskDeque.empty()) {
21
cout << "Task at the back: " << taskDeque.back() <<
endl;
} else {
cout << "No tasks at the back." << endl;
}
}
void displayAllTasks() {
if (taskDeque.empty()) {
cout << "No tasks in the queue." << endl;
return;
}
int main() {
TaskScheduler scheduler;
scheduler.addRegularTask("Task 1 - Regular");
scheduler.addHighPriorityTask("Task 2 - High Priority");
scheduler.addRegularTask("Task 3 - Regular");
scheduler.addHighPriorityTask("Task 4 - High Priority");
scheduler.displayAllTasks();
scheduler.viewFrontTask();
scheduler.viewBackTask();
scheduler.removeFrontTask();
scheduler.removeBackTask();
scheduler.displayAllTasks();
return 0;
}
22
Figure 3: Task 3
7.4 Task 4
#include <iostream>
#include <stack>
#include <string>
23
s.pop();
return s.empty();
}
int main() {
string expression;
if (areParenthesesBalanced(expression)) {
cout << "The expression is balanced." << endl;
} else {
cout << "The expression is not balanced." << endl;
}
return 0;
}
Figure 4: Task 4
7.5 Task 5
#include <iostream>
24
#include <queue>
#include <string>
struct Customer {
string name;
bool isVIP;
class CinemaTicketingSystem {
private:
queue<Customer> regularQueue;
queue<Customer> vipQueue;
public:
void addRegularCustomer(string name) {
regularQueue.push(Customer(name, false));
cout << name << " has joined the regular queue." << endl;
}
void processNextCustomer() {
if (!vipQueue.empty()) {
Customer vipCustomer = vipQueue.front();
vipQueue.pop();
cout << "Serving VIP customer: " << vipCustomer.name <<
endl;
} else if (!regularQueue.empty()) {
Customer regularCustomer = regularQueue.front();
regularQueue.pop();
cout << "Serving regular customer: " << regularCustomer.name << endl;
} else {
cout << "No customers in the queue." << endl;
}
}
25
bool isEmpty() const {
return regularQueue.empty() && vipQueue.empty();
}
};
int main() {
CinemaTicketingSystem cinema;
cinema.addRegularCustomer("John");
cinema.addRegularCustomer("Alice");
cinema.addVIPCustomer("Mr. Smith");
cinema.addRegularCustomer("Bob");
cinema.addVIPCustomer("Ms. Taylor");
while (!cinema.isEmpty()) {
cinema.processNextCustomer();
}
return 0;
}
Figure 5: Task 5
7.6 Task 6
#include <iostream>
#include <queue>
#include <string>
#include <vector>
26
struct Patient {
string name;
int severity;
struct CompareSeverity {
bool operator()(const Patient& p1, const Patient& p2) {
return p1.severity < p2.severity;
}
};
class EmergencyRoomSystem {
private:
priority_queue<Patient, vector<Patient>, CompareSeverity> pq;
public:
void addPatient(string name, int severity) {
pq.push(Patient(name, severity));
cout << "Added patient: " << name << " with severity: " <<
severity << endl;
}
void treatNextPatient() {
if (pq.empty()) {
cout << "No patients in the queue." << endl;
} else {
Patient nextPatient = pq.top();
pq.pop();
cout << "Treating patient: " << nextPatient.name << "
with severity: " << nextPatient.severity << endl;
}
}
int main() {
EmergencyRoomSystem emergencyRoom;
27
emergencyRoom.addPatient("John", 5);
emergencyRoom.addPatient("Alice", 8);
emergencyRoom.addPatient("Bob", 3);
emergencyRoom.addPatient("Eve", 10);
emergencyRoom.addPatient("Tom", 1);
while (!emergencyRoom.isEmpty()) {
emergencyRoom.treatNextPatient();
}
return 0;
}
Figure 6: Task 6
7.7 Task 7
#include <iostream>
#include <set>
#include <string>
class CustomerEmails {
private:
set<string> emailSet;
public:
28
void insertEmail(const string& email) {
auto result = emailSet.insert(email);
if (result.second) {
cout << "Inserted email: " << email << endl;
} else {
cout << "Email already exists: " << email << endl;
}
}
int main() {
CustomerEmails emailManager;
emailManager.insertEmail("[email protected]");
emailManager.insertEmail("[email protected]");
emailManager.insertEmail("[email protected]");
emailManager.displayEmails();
29
emailManager.searchEmail("[email protected]");
emailManager.searchEmail("[email protected]");
emailManager.deleteEmail("[email protected]");
emailManager.displayEmails();
return 0;
}
Figure 7: Task 7
7.8 Task 8
#include <iostream>
#include <map>
#include <string>
struct StudentDetails {
string name;
float grade;
StudentDetails() {}
StudentDetails(string name, float grade) : name(name), grade(grade) {}
};
class StudentRecordManagement {
30
private:
map<int, StudentDetails> studentMap;
public:
void insertStudent(int id, const string& name, float grade) {
if (studentMap.find(id) != studentMap.end()) {
cout << "Student ID " << id << " already exists." <<
endl;
} else {
studentMap[id] = StudentDetails(name, grade);
cout << "Student ID " << id << " inserted successfully." << endl;
}
}
void displayAllStudents() {
if (studentMap.empty()) {
cout << "No student records available." << endl;
return;
}
31
cout << "Grade: " << student.second.grade << endl;
cout << "-------------------------" << endl;
}
}
};
int main() {
StudentRecordManagement manager;
manager.displayAllStudents();
manager.retrieveStudent(102);
manager.deleteStudent(101);
manager.retrieveStudent(101);
manager.displayAllStudents();
return 0;
}
Figure 8: Task 8
32
7.9 Task 9
#include <iostream>
#include <string>
#include <unordered_map>
#include <map>
#include <sstream>
#include <chrono>
33
cout << "\nWord frequencies using map:\n";
for (const auto &entry : wordFreq) {
cout << entry.first << ": " << entry.second << endl;
}
int main() {
string text = "This is a sample text with several words this
is a test text with repeated words text repeated repeated";
wordFrequencyUnorderedMap(text);
wordFrequencyMap(text);
return 0;
}
Figure 9: Task 9
34
7.10 Task 10
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
struct Student {
std::string name;
int grade;
};
int main() {
std::vector<Student> students = {
{"John", 85},
{"Alice", 95},
{"Bob", 85},
{"Charlie", 70},
{"David", 95},
{"Eve", 85}
};
return 0;
}
35
Figure 10: Task 10
7.11 Task 11
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
struct Employee {
std::string name;
std::string department;
std::string hireDate;
};
int main() {
std::vector<Employee> employees = {
{"John", "HR", "2022-05-01"},
{"Alice", "Engineering", "2021-01-15"},
{"Bob", "HR", "2020-11-20"},
{"Charlie", "Engineering", "2019-06-30"},
{"David", "Marketing", "2023-03-22"},
{"Eve", "Engineering", "2022-08-01"}
};
36
<< " | " << employee.hireDate << std::endl;
}
return 0;
}
7.12 Task 12
#include <iostream>
#include <thread>
void print1to5() {
for (int i = 1; i <= 5; ++i) {
std::cout << "Thread 1: " << i << std::endl;
}
}
void print6to10() {
for (int i = 6; i <= 10; ++i) {
std::cout << "Thread 2: " << i << std::endl;
}
}
int main() {
std::thread t1(print1to5);
std::thread t2(print6to10);
t1.join();
t2.join();
37
return 0;
}
38