/*
------------------------------------------------------------
TRAVEL EXPERIENCE BROWSER
Data Structures Mini Project (C Language)
DATA STRUCTURES USED:
1) Singly Linked List - Stores travel destinations dynamically
2) Stack - Stores recently viewed destination IDs (LIFO)
3) Queue - Stores recommendation requests (FIFO)
FEATURES:
- View all destinations
- View destination by ID (pushes to stack)
- Search destinations by City / Type
- Sort destinations by Rating (descending)
- Recently viewed (stack display)
- Add recommendation request (queue enqueue)
- Process recommendation request (queue dequeue + match)
------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* ---------- CONSTANTS ---------- */
#define MAX_NAME 50
#define MAX_CITY 30
#define MAX_TYPE 20
#define MAX_EXP 200
/* =========================================================
1) LINKED LIST: Destination Node
========================================================= */
typedef struct Destination {
int id; /* Unique destination ID */
char name[MAX_NAME]; /* Destination name */
char city[MAX_CITY]; /* City */
char type[MAX_TYPE]; /* Beach/Hill/Heritage etc. */
int rating; /* 1 to 5 rating */
char experience[MAX_EXP]; /* Short experience text */
struct Destination *next; /* Pointer to next node */
} Destination;
/* =========================================================
2) STACK: Recently Viewed (stores destination IDs)
========================================================= */
typedef struct StackNode {
int destId; /* Viewed destination ID */
struct StackNode *next; /* Next stack node */
} StackNode;
/* =========================================================
3) QUEUE: Recommendation Requests
========================================================= */
typedef struct ReqNode {
char user[MAX_NAME]; /* User name */
char prefType[MAX_TYPE]; /* Preferred type */
int minRating; /* Minimum rating */
struct ReqNode *next; /* Next request node */
} ReqNode;
typedef struct Queue {
ReqNode *front; /* Front pointer */
ReqNode *rear; /* Rear pointer */
} Queue;
/* ---------- FUNCTION DECLARATIONS ---------- */
/* Utilities */
static void trim_newline(char *s);
static int containsIgnoreCase(const char *text, const char *pat);
/* Linked list operations */
Destination* createDestination(int id, const char *name, const char *city,
const char *type
, int rating
, const char *exp); void addDestination(Destination **head, Destination *node);
void displayAll(Destination *head);
Destination* searchById(Destination *head, int id);
void searchDestinations(Destination *head);
void sortByRating(Destination *head);
/* Stack operations */
void push(StackNode **top, int id);
void displayStack(StackNode *top);
/* Queue operations */
void initQueue(Queue *q);
void enqueue(Queue *q, const char *user, const char *type, int minRating);
ReqNode* dequeue(Queue *q);
void processRecommendation(Queue *q, Destination *head);
/* Seed/sample data */
void seedData(Destination **head);
/* =========================================================
UTILITY FUNCTIONS
========================================================= */
/* Remove trailing newline from fgets() input */
static void trim_newline(char *s) {
if (s == NULL) return;
}
/* Case-insensitive substring check:
returns 1 if 'pat' exists inside 'text', else 0 */
static int containsIgnoreCase(const char *text, const char *pat) {
if (pat == NULL || pat[0] == '\0') return 1;
if (text == NULL) return 0;
char tbuf[300], pbuf[80];
int i;
for (i = 0; text[i] && i < (int)sizeof(tbuf) - 1; i++)
tbuf
[i
] = (char)tolower((unsigned char)text
[i
]); tbuf[i] = '\0';
for (i = 0; pat[i] && i < (int)sizeof(pbuf) - 1; i++)
pbuf
[i
] = (char)tolower((unsigned char)pat
[i
]); pbuf[i] = '\0';
return (strstr(tbuf
, pbuf
) != NULL
); }
/* =========================================================
LINKED LIST FUNCTIONS
========================================================= */
/* Create a new destination node */
Destination* createDestination(int id, const char *name, const char *city,
const char *type
, int rating
, const char *exp) { Destination
*n
= (Destination
*)malloc(sizeof(Destination
)); if (n == NULL) {
printf("Memory allocation failed while creating destination.\n"); return NULL;
}
n->id = id;
strncpy(n
->name
, name
, MAX_NAME
- 1); n
->name
[MAX_NAME
- 1] = '\0'; strncpy(n
->city
, city
, MAX_CITY
- 1); n
->city
[MAX_CITY
- 1] = '\0'; strncpy(n
->type
, type
, MAX_TYPE
- 1); n
->type
[MAX_TYPE
- 1] = '\0'; n->rating = rating;
strncpy(n
->experience
, exp, MAX_EXP
- 1); n
->experience
[MAX_EXP
- 1] = '\0';
n->next = NULL;
return n;
}
/* Insert destination at the end of the linked list */
void addDestination(Destination **head, Destination *node) {
if (node == NULL) return;
if (*head == NULL) {
*head = node;
return;
}
Destination *t = *head;
while (t->next != NULL) t = t->next;
t->next = node;
}
/* Display all destinations in table format */
void displayAll(Destination *head) {
if (head == NULL) {
printf("No destinations available.\n"); return;
}
printf("\nID NAME CITY TYPE RATING\n"); printf("------------------------------------------------------\n"); while (head != NULL) {
printf("%-4d %-17s %-14s %-9s %d\n", head->id, head->name, head->city, head->type, head->rating);
head = head->next;
}
}
/* Search destination by ID */
Destination* searchById(Destination *head, int id) {
while (head != NULL) {
if (head->id == id) return head;
head = head->next;
}
return NULL;
}
/* Search destinations by City or Type */
void searchDestinations(Destination *head) {
int option;
char key[80];
if (head == NULL) {
printf("No destinations to search.\n"); return;
}
printf("\nSearch by:\n1) City\n2) Type\nEnter choice: "); if (scanf("%d", &option
) != 1) { return;
}
int found = 0;
while (head != NULL) {
if ((option == 1 && containsIgnoreCase(head->city, key)) ||
(option == 2 && containsIgnoreCase(head->type, key))) {
printf("Match: %s (%s) [%s] Rating=%d\n", head->name, head->city, head->type, head->rating);
found = 1;
}
head = head->next;
}
if (!found
) printf("No matching destinations found.\n"); }
/* Sort destinations by rating in descending order (bubble sort by swapping data) */
void sortByRating(Destination *head) {
if (head == NULL) return;
int swapped;
Destination *ptr1;
Destination *lptr = NULL;
do {
swapped = 0;
ptr1 = head;
while (ptr1->next != lptr) {
if (ptr1->rating < ptr1->next->rating) {
/* Swap contents (data) of the two nodes */
Destination tmp = *ptr1;
*ptr1 = *(ptr1->next);
*(ptr1->next) = tmp;
/* Fix next pointers after struct copy swap */
Destination *n1 = ptr1->next;
Destination *n2 = n1->next;
ptr1->next = n1;
n1->next = n2;
swapped = 1;
}
ptr1 = ptr1->next;
}
lptr = ptr1;
} while (swapped);
printf("Destinations sorted by rating (descending).\n"); }
/* =========================================================
STACK FUNCTIONS (RECENTLY VIEWED)
========================================================= */
/* Push destination ID to stack (top insert) */
void push(StackNode **top, int id) {
StackNode
*n
= (StackNode
*)malloc(sizeof(StackNode
)); if (n == NULL) {
printf("Memory allocation failed while pushing to stack.\n"); return;
}
n->destId = id;
n->next = *top;
*top = n;
}
/* Display stack IDs from top to bottom */
void displayStack(StackNode *top) {
if (top == NULL) {
printf("Recently viewed list is empty.\n"); return;
}
printf("Recently Viewed (Top -> Bottom): "); while (top != NULL) {
top = top->next;
}
}
/* =========================================================
QUEUE FUNCTIONS (RECOMMENDATION REQUESTS)
========================================================= */
/* Initialize queue pointers */
void initQueue(Queue *q) {
q->front = NULL;
q->rear = NULL;
}
/* Add request at rear (enqueue) */
void enqueue(Queue *q, const char *user, const char *type, int minRating) {
ReqNode
*n
= (ReqNode
*)malloc(sizeof(ReqNode
)); if (n == NULL) {
printf("Memory allocation failed while enqueuing.\n"); return;
}
strncpy(n
->user
, user
, MAX_NAME
- 1); n
->user
[MAX_NAME
- 1] = '\0'; strncpy(n
->prefType
, type
, MAX_TYPE
- 1); n
->prefType
[MAX_TYPE
- 1] = '\0'; n->minRating = minRating;
n->next = NULL;
if (q->rear == NULL) {
/* Queue is empty */
q->front = q->rear = n;
} else {
q->rear->next = n;
q->rear = n;
}
}
/* Remove request from front (dequeue) and return it */
ReqNode* dequeue(Queue *q) {
if (q->front == NULL) return NULL;
ReqNode *t = q->front;
q->front = t->next;
if (q->front == NULL) {
/* Queue became empty */
q->rear = NULL;
}
return t;
}
/* Process one recommendation request and suggest first matching destination */
void processRecommendation(Queue *q, Destination *head) {
ReqNode *req = dequeue(q);
if (req == NULL) {
printf("No recommendation requests available.\n"); return;
}
printf("\nProcessing Recommendation for %s\n", req
->user
);
while (head != NULL) {
if (containsIgnoreCase(head->type, req->prefType) &&
head->rating >= req->minRating) {
printf("Recommended Destination:\n"); printf("Name: %s\nCity: %s\nType: %s\nRating: %d\n", head->name, head->city, head->type, head->rating);
return;
}
head = head->next;
}
printf("No suitable destination found.\n"); }
/* =========================================================
SAMPLE DATA
========================================================= */
void seedData(Destination **head) {
addDestination(head, createDestination(101, "Baga Beach", "Goa", "Beach", 5,
"Beautiful beach and nightlife."));
addDestination(head, createDestination(102, "Ooty", "TamilNadu", "Hill", 4,
"Pleasant hill station and cool climate."));
addDestination(head, createDestination(103, "Munnar", "Kerala", "Hill", 5,
"Tea gardens and scenic views."));
}
/* =========================================================
MAIN FUNCTION (MENU-DRIVEN)
========================================================= */
int main() {
Destination *head = NULL; /* Linked list head */
StackNode *top = NULL; /* Stack top */
Queue q; /* Queue object */
initQueue(&q);
seedData(&head); /* Insert sample destinations */
while (1) {
int choice;
printf("\n==== TRAVEL EXPERIENCE BROWSER ====\n"); printf("1. View All Destinations\n"); printf("2. View Destination by ID\n"); printf("3. Search Destination\n"); printf("4. Sort by Rating\n"); printf("5. Recently Viewed\n"); printf("6. Add Recommendation Request\n"); printf("7. Process Recommendation\n");
if (scanf("%d", &choice
) != 1) { printf("Invalid input. Exiting.\n"); break;
}
if (choice == 1) {
displayAll(head);
}
else if (choice == 2) {
int id;
printf("Enter destination ID: ");
Destination *d = searchById(head, id);
if (d != NULL) {
printf("\nName: %s\nCity: %s\nType: %s\nRating: %d\nExperience: %s\n", d->name, d->city, d->type, d->rating, d->experience);
/* Push viewed destination ID to stack */
push(&top, id);
} else {
printf("Destination not found.\n"); }
}
else if (choice == 3) {
searchDestinations(head);
}
else if (choice == 4) {
sortByRating(head);
}
else if (choice == 5) {
displayStack(top);
}
else if (choice == 6) {
char user[MAX_NAME];
char type[MAX_TYPE];
int minRating;
/* Consume leftover newline from previous scanf */
fgets(user
, sizeof(user
), stdin
); trim_newline(user);
printf("Enter preferred type: "); fgets(type
, sizeof(type
), stdin
); trim_newline(type);
printf("Enter minimum rating (1 to 5): ");
enqueue(&q, user, type, minRating);
}
else if (choice == 7) {
processRecommendation(&q, head);
}
else if (choice == 8) {
break;
}
else {
}
}
return 0;
}