DATA STRUCTURE (LAB)
PROJECT
SUBMITTED BY : - KAINAAT AFZAL
STUDENT ID : - S2025408067
SUBMITTED TO : - SYEDA NIMRA ZAMIR
// ============================================================
// FOOD DELIVERY MANAGEMENT SYSTEM
// ============================================================
#include <iostream>
#include <cstring>
using namespace std;
// ============================================================
// SECTION 1: SINGLY LINKED LIST — CUSTOMERS
// Each customer has an ID, name, and address.
// New customers are added at the end of the list.
// ============================================================
struct CustomerNode {
int id;
char name[50];
char address[100];
CustomerNode* next;
};
class CustomerList {
private:
CustomerNode* head;
int count;
public:
CustomerList() {
head = NULL;
count = 0;
}
// ADD CUSTOMER (insertion at tail)
void addCustomer(int id, const char* name, const char* address) {
// Create a new node on the heap
CustomerNode* newNode = new CustomerNode;
newNode->id = id;
strcpy(newNode->name, name);
strcpy(newNode->address, address);
newNode->next = NULL;
if (head == NULL) {
head = newNode;
} else {
CustomerNode* temp = head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
count++;
cout << "\n [Customer Added] " << name
<< " (ID: " << id << ")\n";
}
// DISPLAY ALL CUSTOMERS (traversal)
void displayCustomers() {
if (head == NULL) {
cout << "\n No customers registered yet.\n";
return;
}
cout << "\n ===== Customer List (" << count << " total) =====\n";
CustomerNode* temp = head;
int pos = 1;
while (temp != NULL) {
cout << " " << pos << ". ID: " << temp->id
<< " | Name: " << temp->name
<< " | Address: " << temp->address << "\n";
temp = temp->next;
pos++;
}
}
// FIND CUSTOMER BY ID
bool customerExists(int id) {
CustomerNode* temp = head;
while (temp != NULL) {
if (temp->id == id) return true;
temp = temp->next;
}
return false;
}
// Destructor: free all nodes to prevent memory leaks
~CustomerList() {
CustomerNode* temp = head;
while (temp != NULL) {
CustomerNode* toDelete = temp;
temp = temp->next;
delete toDelete;
}
}
};
// ============================================================
// SECTION 2: DOUBLY LINKED LIST — RESTAURANTS
// Each restaurant has an ID and a name.
// The doubly linked list allows traversal in both directions.
// ============================================================
struct RestaurantNode {
int id;
char name[50];
char cuisine[50];
RestaurantNode* prev;
RestaurantNode* next;
};
class RestaurantList {
private:
RestaurantNode* head;
RestaurantNode* tail;
int count;
public:
RestaurantList() {
head = NULL;
tail = NULL;
count = 0;
}
// ADD RESTAURANT (insertion at tail)
void addRestaurant(int id, const char* name, const char* cuisine) {
RestaurantNode* newNode = new RestaurantNode;
newNode->id = id;
strcpy(newNode->name, name);
strcpy(newNode->cuisine, cuisine);
newNode->prev = NULL;
newNode->next = NULL;
if (head == NULL) {
head = newNode;
tail = newNode;
} else {
tail->next = newNode;
newNode->prev = tail;
tail = newNode;
}
count++;
cout << "\n [Restaurant Added] " << name
<< " | Cuisine: " << cuisine
<< " (ID: " << id << ")\n";
}
// DISPLAY RESTAURANTS (forward traversal)
void displayRestaurants() {
if (head == NULL) {
cout << "\n No restaurants registered yet.\n";
return;
}
cout << "\n ===== Restaurant List (" << count << " total) =====\
n";
RestaurantNode* temp = head;
int pos = 1;
while (temp != NULL) {
cout << " " << pos << ". ID: " << temp->id
<< " | Name: " << temp->name
<< " | Cuisine: " << temp->cuisine;
if (temp->prev != NULL)
cout << " | Prev: " << temp->prev->name;
else
cout << " | Prev: ---";
if (temp->next != NULL)
cout << " | Next: " << temp->next->name;
else
cout << " | Next: ---";
cout << "\n";
temp = temp->next;
pos++;
}
}
// CHECK IF RESTAURANT EXISTS
bool restaurantExists(int id) {
RestaurantNode* temp = head;
while (temp != NULL) {
if (temp->id == id) return true;
temp = temp->next;
}
return false;
}
~RestaurantList() {
RestaurantNode* temp = head;
while (temp != NULL) {
RestaurantNode* toDelete = temp;
temp = temp->next;
delete toDelete;
}
}
};
// ============================================================
// SECTION 3: DYNAMIC QUEUE — FOOD ORDERS
// Orders are placed at the REAR and processed from the FRONT.
// This follows FIFO (First In, First Out) principle.
// ============================================================
struct OrderNode {
int orderId;
int customerId;
int restaurantId;
char foodItem[100];
OrderNode* next;
};
class OrderQueue {
private:
OrderNode* front;
OrderNode* rear;
int size;
public:
OrderQueue() {
front = NULL;
rear = NULL;
size = 0;
}
// ENQUEUE — Place a new order
void enqueue(int orderId, int custId, int restId, const char* item) {
OrderNode* newNode = new OrderNode;
newNode->orderId = orderId;
newNode->customerId = custId;
newNode->restaurantId = restId;
strcpy(newNode->foodItem, item);
newNode->next = NULL;
if (rear == NULL) {
front = newNode;
rear = newNode;
} else {
rear->next = newNode;
rear = newNode;
}
size++;
cout << "\n [Order Placed] Order #" << orderId
<< " | Item: " << item
<< " | Customer ID: " << custId
<< " | Restaurant ID: " << restId << "\n";
}
// DEQUEUE — Process the front order
// Returns the processed order node (caller must delete it)
OrderNode* dequeue() {
if (front == NULL) {
cout << "\n No orders in the queue.\n";
return NULL;
}
OrderNode* processed = front;
front = front->next;
if (front == NULL) rear = NULL;
processed->next = NULL;
size--;
cout << "\n [Order Processed] Order #" << processed->orderId
<< " | Item: " << processed->foodItem << "\n";
return processed;
}
// CHECK IF QUEUE IS EMPTY
bool isEmpty() {
return front == NULL;
}
// DISPLAY ALL PENDING ORDERS
void displayOrders() {
if (front == NULL) {
cout << "\n No pending orders in the queue.\n";
return;
}
cout << "\n ===== Pending Orders (" << size << " total) =====\n";
OrderNode* temp = front;
int pos = 1;
while (temp != NULL) {
cout << " " << pos << ". Order #" << temp->orderId
<< " | Item: " << temp->foodItem
<< " | Customer ID: " << temp->customerId
<< " | Restaurant ID: " << temp->restaurantId << "\n";
temp = temp->next;
pos++;
}
}
~OrderQueue() {
OrderNode* temp = front;
while (temp != NULL) {
OrderNode* toDelete = temp;
temp = temp->next;
delete toDelete;
}
}
};
// ============================================================
// SECTION 4: DYNAMIC STACK — COMPLETED DELIVERIES
// Each completed delivery is pushed onto the stack.
// The most recently completed delivery is on TOP.
// This follows LIFO (Last In, First Out) principle.
// ============================================================
struct DeliveryNode {
int orderId;
int customerId;
char foodItem[100];
char riderName[50];
DeliveryNode* next;
};
class DeliveryStack {
private:
DeliveryNode* top;
int size;
public:
DeliveryStack() {
top = NULL;
size = 0;
}
// PUSH — Record a completed delivery
void push(int orderId, int custId, const char* item, const char*
rider) {
DeliveryNode* newNode = new DeliveryNode;
newNode->orderId = orderId;
newNode->customerId = custId;
strcpy(newNode->foodItem, item);
strcpy(newNode->riderName, rider);
newNode->next = top;
top = newNode;
size++;
cout << "\n [Delivery Completed] Order #" << orderId
<< " delivered by " << rider << "\n";
}
// POP — Remove and return the top delivery
void pop() {
if (top == NULL) {
cout << "\n No completed deliveries on record.\n";
return;
}
DeliveryNode* toDelete = top;
cout << "\n [Delivery Removed from Stack] Order #"
<< top->orderId << "\n";
top = top->next;
delete toDelete;
size--;
}
// DISPLAY ALL COMPLETED DELIVERIES
void displayDeliveries() {
if (top == NULL) {
cout << "\n No completed deliveries yet.\n";
return;
}
cout << "\n ===== Completed Deliveries (most recent first) =====\
n";
cout << " Total: " << size << "\n";
DeliveryNode* temp = top;
int pos = 1;
while (temp != NULL) {
cout << " " << pos << ". Order #" << temp->orderId
<< " | Item: " << temp->foodItem
<< " | Customer: " << temp->customerId
<< " | Rider: " << temp->riderName << "\n";
temp = temp->next;
pos++;
}
}
// CHECK IF STACK IS EMPTY
bool isEmpty() {
return top == NULL;
}
// PEEK — View the top delivery without removing
void peek() {
if (top == NULL) {
cout << "\n Stack is empty.\n";
} else {
cout << "\n [Top of Stack] Order #" << top->orderId
<< " | Item: " << top->foodItem
<< " | Rider: " << top->riderName << "\n";
}
}
~DeliveryStack() {
DeliveryNode* temp = top;
while (temp != NULL) {
DeliveryNode* toDelete = temp;
temp = temp->next;
delete toDelete;
}
}
};
// ============================================================
// SECTION 5: CIRCULAR LINKED LIST — DELIVERY RIDERS
// Riders are arranged in a circle.
// When assigning riders we go one by one.
// The last node's 'next' points back to the first node.
// ============================================================
struct RiderNode {
int id;
char name[50];
bool available;
RiderNode* next;
};
class RiderCircularList {
private:
RiderNode* tail;
int count;
public:
RiderCircularList() {
tail = NULL;
count = 0;
}
//ADD RIDER (insertion into circle)
void addRider(int id, const char* name) {
RiderNode* newNode = new RiderNode;
newNode->id = id;
strcpy(newNode->name, name);
newNode->available = true;
if (tail == NULL) {
newNode->next = newNode;
tail = newNode;
} else {
newNode->next = tail->next;
tail->next = newNode;
tail = newNode;
}
count++;
cout << "\n [Rider Added] " << name
<< " (ID: " << id << ")\n";
}
// ASSIGN FIRST AVAILABLE RIDER
// Returns the rider node pointer or NULL if none available
RiderNode* assignRider() {
if (tail == NULL) {
cout << "\n No riders registered.\n";
return NULL;
}
RiderNode* current = tail->next;
int checked = 0;
// Traverse the circle once looking for a free rider
while (checked < count) {
if (current->available) {
current->available = false;
cout << "\n [Rider Assigned] " << current->name
<< " (ID: " << current->id << ")\n";
return current;
}
current = current->next;
checked++;
}
cout << "\n All riders are currently busy.\n";
return NULL;
}
// FREE A RIDER (mark available again)
void freeRider(int riderId) {
if (tail == NULL) return;
RiderNode* current = tail->next;
for (int i = 0; i < count; i++) {
if (current->id == riderId) {
current->available = true;
cout << "\n [Rider Free] " << current->name
<< " is now available.\n";
return;
}
current = current->next;
}
cout << "\n Rider ID " << riderId << " not found.\n";
}
// DISPLAY ALL RIDERS (circular traversal)
void displayRiders() {
if (tail == NULL) {
cout << "\n No riders registered yet.\n";
return;
}
cout << "\n ===== Delivery Riders (" << count << " total) =====\
n";
RiderNode* current = tail->next;
for (int i = 0; i < count; i++) {
cout << " " << (i + 1) << ". ID: " << current->id
<< " | Name: " << current->name
<< " | Status: "
<< (current->available ? "Available" : "On Delivery")
<< "\n";
current = current->next;
}
}
// CHECK IF ANY RIDER IS AVAILABLE
bool anyAvailable() {
if (tail == NULL) return false;
RiderNode* current = tail->next;
for (int i = 0; i < count; i++) {
if (current->available) return true;
current = current->next;
}
return false;
}
// GET RIDER NAME BY ID
void getRiderName(int id, char* buffer) {
if (tail == NULL) { strcpy(buffer, "Unknown"); return; }
RiderNode* current = tail->next;
for (int i = 0; i < count; i++) {
if (current->id == id) {
strcpy(buffer, current->name);
return;
}
current = current->next;
}
strcpy(buffer, "Unknown");
}
~RiderCircularList() {
if (tail == NULL) return;
RiderNode* current = tail->next;
// Break the circle first
tail->next = NULL;
while (current != NULL) {
RiderNode* toDelete = current;
current = current->next;
delete toDelete;
}
}
};
// ============================================================
// SECTION 6: HELPER UTILITIES
// ============================================================
// Print a decorative section separator
void printLine() {
cout << " -----------------------------------------------\n";
}
// Print the main menu
void printMenu() {
cout << "\n ===============================================\n";
cout << " FOOD DELIVERY MANAGEMENT SYSTEM\n";
cout << " ===============================================\n";
cout << " 1. Add Customer\n";
cout << " 2. Display Customers\n";
cout << " 3. Add Restaurant\n";
cout << " 4. Display Restaurants\n";
cout << " 5. Place Order\n";
cout << " 6. Process Order (Dequeue)\n";
cout << " 7. Add Rider\n";
cout << " 8. Assign Rider to Active Order\n";
cout << " 9. Complete Delivery (Push to Stack)\n";
cout << " 10. Display Completed Deliveries\n";
cout << " 11. Exit\n";
cout << " -----------------------------------------------\n";
cout << " Enter your choice: ";
}
// ============================================================
// SECTION 7: MAIN — MENU-DRIVEN PROGRAM
// ============================================================
int main() {
// Instantiate all data structures
CustomerList customers;
RestaurantList restaurants;
OrderQueue orders;
DeliveryStack deliveries;
RiderCircularList riders;
// Counters for auto-incrementing IDs
int customerIdCounter = 1;
int restaurantIdCounter = 1;
int orderIdCounter = 1;
int riderIdCounter = 1;
// Temporarily holds the last processed (dequeued) order
// so it can be completed in the next step
int activeOrderId = -1;
int activeCustomerId = -1;
char activeFoodItem[100] = "";
int activeRiderId = -1;
char activeRiderName[50] = "";
bool orderBeingDelivered = false;
int choice;
cout << "\n Welcome to the Food Delivery Management System!\n";
do {
printMenu();
cin >> choice;
[Link]();
printLine();
// OPTION 1: Add Customer (Singly Linked List)
if (choice == 1) {
char name[50], address[100];
cout << "\n Enter customer name : ";
[Link](name, 50);
cout << " Enter customer address : ";
[Link](address, 100);
[Link](customerIdCounter, name, address);
customerIdCounter++;
}
// OPTION 2: Display Customers
else if (choice == 2) {
[Link]();
}
// OPTION 3: Add Restaurant (Doubly Linked List)
else if (choice == 3) {
char name[50], cuisine[50];
cout << "\n Enter restaurant name : ";
[Link](name, 50);
cout << " Enter cuisine type : ";
[Link](cuisine, 50);
[Link](restaurantIdCounter, name, cuisine);
restaurantIdCounter++;
}
// OPTION 4: Display Restaurants
else if (choice == 4) {
[Link]();
}
// OPTION 5: Place Order (Enqueue)
else if (choice == 5) {
int custId, restId;
char item[100];
cout << "\n Enter customer ID : ";
cin >> custId;
[Link]();
if () {
cout << "\n Customer ID " << custId << " not found.
Please add the customer first.\n";
} else {
cout << " Enter restaurant ID : ";
cin >> restId;
[Link]();
if () {
cout << "\n Restaurant ID " << restId << " not found.
Please add the restaurant first.\n";
} else {
cout << " Enter food item : ";
[Link](item, 100);
[Link](orderIdCounter, custId, restId, item);
orderIdCounter++;
}
}
}
// OPTION 6: Process Order (Dequeue from Queue)
else if (choice == 6) {
if ([Link]()) {
cout << "\n No orders to process.\n";
} else if (orderBeingDelivered) {
cout << "\n An order is already being delivered.\n";
cout << " Complete the current delivery first (Option
9).\n";
} else {
OrderNode* processed = [Link]();
if (processed != NULL) {
// Save this order as the active delivery
activeOrderId = processed->orderId;
activeCustomerId = processed->customerId;
strcpy(activeFoodItem, processed->foodItem);
activeRiderId = -1;
orderBeingDelivered = true;
delete processed;
cout << " Order #" << activeOrderId
<< " is ready. Assign a rider (Option 8).\n";
}
}
}
// OPTION 7: Add Rider (Circular Linked List)
else if (choice == 7) {
char name[50];
cout << "\n Enter rider name : ";
[Link](name, 50);
[Link](riderIdCounter, name);
riderIdCounter++;
}
// OPTION 8: Assign Rider to Active Order
else if (choice == 8) {
if (!orderBeingDelivered) {
cout << "\n No active order to assign a rider to.\n";
cout << " Process an order first (Option 6).\n";
} else if (activeRiderId != -1) {
cout << "\n Rider already assigned to Order #"
<< activeOrderId << ".\n";
} else {
[Link]();
RiderNode* rider = [Link]();
if (rider != NULL) {
activeRiderId = rider->id;
strcpy(activeRiderName, rider->name);
cout << " Rider " << activeRiderName
<< " assigned to Order #" << activeOrderId << ".\
n";
}
}
}
// OPTION 9: Complete Delivery (Push onto Stack)
else if (choice == 9) {
if (!orderBeingDelivered) {
cout << "\n No active delivery to complete.\n";
} else if (activeRiderId == -1) {
cout << "\n Please assign a rider first (Option 8).\n";
} else {
// Push the completed delivery onto the stack
[Link](activeOrderId, activeCustomerId,
activeFoodItem, activeRiderName);
// Free the rider so they can take new orders
[Link](activeRiderId);
// Reset the active order state
activeOrderId = -1;
activeCustomerId = -1;
activeFoodItem[0] = '\0';
activeRiderId = -1;
activeRiderName[0] = '\0';
orderBeingDelivered = false;
}
}
// OPTION 10: Display Completed Deliveries (Stack)
else if (choice == 10) {
[Link]();
}
// OPTION 11: Exit
else if (choice == 11) {
cout << "\n Thank you for using the Food Delivery System!\n";
cout << " Goodbye!\n\n";
}
else {
cout << "\n Invalid choice. Please enter a number between 1
and 11.\n";
}
printLine();
} while (choice != 11);
// All destructors run automatically here, freeing heap memory.
}