Phase 3 labWeeks 11–16 6–8 hours
Lab 3: Campus Navigator
Store buildings in a BST, paths in a graph, find routes with BFS, explore with DFS, and sort results with merge sort and quick sort.
Uses:6.2 Binary Search Tree6.4 Tree Traversals7.2 Adjacency Matrix & Adjacency List7.4 BFS & DFS8.2 Quick Sort8.3 Merge Sort
01Spec
The task
New students get lost. Build a console navigator for campus:
- Buildings live in a BST keyed by name, so lookups are O(log n) on a balanced tree, and an inorder walk lists them A to Z for free.
- Paths between buildings form an undirected graph, stored as an adjacency list.
- BFS gives the route with the fewest hops. DFS tells you everything reachable.
- Results are sorted: nearest buildings with merge sort (stable, by hops then name) and reachable names with quick sort.
Input format
n
name1 name2 … nameN (single-word names)
m
a b (m lines: a path between buildings a and b)
ROUTE a b | NEAREST a | REACH a (commands until end of input)
Visit neighbours in alphabetical order so your output matches the sample.
Questions to answer in your report
- Why is the inorder traversal of the BST sorted?
- What is the time complexity of ROUTE in terms of V and E?
- The Clinic has no paths. What do BFS and DFS do with it, and why?
- Would an adjacency matrix be a better choice here? Count the cells vs the list entries.
02Starter file
It compiles as-is. Every TODO is a milestone below.
// Lab 3: Campus Navigator (starter). Build each part, test it, then move to the next milestone.
#include <iostream>
#include <string>
#include <vector>
#include <queue>
using namespace std;
struct BNode {
string name;
int id;
BNode* left = nullptr;
BNode* right = nullptr;
};
BNode* insert(BNode* r, const string& name, int id) {
// TODO: standard recursive BST insert keyed by name
if (!r) return new BNode{name, id};
return r;
}
int findId(BNode* r, const string& name) {
// TODO: iterative BST search, return id or -1
(void)r; (void)name;
return -1;
}
void destroy(BNode* r) { if (!r) return; destroy(r->left); destroy(r->right); delete r; }
// TODO: BFS that fills dist[] and parent[] (for ROUTE and NEAREST)
// TODO: recursive DFS that records the visit order (for REACH)
// TODO: merge sort of {name, hops} by hops then name; quick sort of names A-Z
int main() {
int n, m;
cin >> n;
vector<string> names(n);
BNode* root = nullptr;
for (int i = 0; i < n; i++) { cin >> names[i]; root = insert(root, names[i], i); }
cin >> m;
vector<vector<int>> adj(n);
for (int k = 0; k < m; k++) {
string a, b;
cin >> a >> b;
// TODO: look up both ids in the BST and add an undirected edge
}
string cmd;
while (cin >> cmd) {
string rest;
getline(cin, rest);
cout << "TODO " << cmd << "\n"; // ROUTE a b · NEAREST a · REACH a
}
destroy(root);
}03Milestones
0/6 ticked
04Sample input & output
Save the input as input.txt and run ./campus-navigator < input.txt. Your output should match the solution's output exactly.
input.txt
8 Library Cafeteria Gate Lab Stadium Dorm Clinic Admin 8 Gate Admin Gate Library Admin Library Library Lab Library Cafeteria Cafeteria Dorm Dorm Stadium Lab Stadium ROUTE Gate Stadium ROUTE Admin Dorm ROUTE Gate Clinic NEAREST Library REACH Gate
05Reference solution
Don't just watch: implement it yourself, then solve 2–3 problems. Try for at least an hour before opening this.
Show the solution
// Lab 3: Campus Navigator (solution)
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
// ---------- BST of buildings, keyed by name ----------
struct BNode {
string name;
int id;
BNode* left = nullptr;
BNode* right = nullptr;
};
BNode* insert(BNode* r, const string& name, int id) {
if (!r) return new BNode{name, id};
if (name < r->name) r->left = insert(r->left, name, id);
else if (name > r->name) r->right = insert(r->right, name, id);
return r;
}
int findId(BNode* r, const string& name) {
while (r) {
if (name == r->name) return r->id;
r = name < r->name ? r->left : r->right;
}
return -1;
}
void inorder(BNode* r) { if (!r) return; inorder(r->left); cout << r->name << " "; inorder(r->right); }
void destroy(BNode* r) { if (!r) return; destroy(r->left); destroy(r->right); delete r; }
// ---------- graph traversals ----------
vector<int> bfsDistances(int s, const vector<vector<int>>& adj, vector<int>& parent) {
vector<int> dist(adj.size(), -1);
parent.assign(adj.size(), -1);
queue<int> q;
dist[s] = 0;
q.push(s);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int v : adj[u])
if (dist[v] == -1) { dist[v] = dist[u] + 1; parent[v] = u; q.push(v); }
}
return dist;
}
void dfs(int u, const vector<vector<int>>& adj, vector<bool>& seen, vector<int>& order) {
seen[u] = true;
order.push_back(u);
for (int v : adj[u]) if (!seen[v]) dfs(v, adj, seen, order);
}
// ---------- sorting results ----------
struct Result { string name; int hops; };
bool before(const Result& a, const Result& b) { return a.hops != b.hops ? a.hops < b.hops : a.name < b.name; }
void mergeSort(vector<Result>& a, int lo, int hi) {
if (lo >= hi) return;
int mid = lo + (hi - lo) / 2;
mergeSort(a, lo, mid);
mergeSort(a, mid + 1, hi);
vector<Result> tmp;
int i = lo, j = mid + 1;
while (i <= mid && j <= hi) tmp.push_back(before(a[j], a[i]) ? a[j++] : a[i++]);
while (i <= mid) tmp.push_back(a[i++]);
while (j <= hi) tmp.push_back(a[j++]);
for (int k = 0; k < (int)tmp.size(); k++) a[lo + k] = tmp[k];
}
int partition(vector<string>& a, int lo, int hi) {
string pivot = a[hi];
int i = lo - 1;
for (int j = lo; j < hi; j++) if (a[j] < pivot) swap(a[++i], a[j]);
swap(a[i + 1], a[hi]);
return i + 1;
}
void quickSort(vector<string>& a, int lo, int hi) {
if (lo < hi) { int p = partition(a, lo, hi); quickSort(a, lo, p - 1); quickSort(a, p + 1, hi); }
}
int main() {
int n, m;
cin >> n;
vector<string> names(n);
BNode* root = nullptr;
for (int i = 0; i < n; i++) { cin >> names[i]; root = insert(root, names[i], i); }
cin >> m;
vector<vector<int>> adj(n);
for (int k = 0; k < m; k++) {
string a, b;
cin >> a >> b;
int u = findId(root, a), v = findId(root, b);
if (u == -1 || v == -1) { cout << "unknown building in path " << a << "-" << b << "\n"; continue; }
adj[u].push_back(v);
adj[v].push_back(u);
}
for (auto& l : adj) sort(l.begin(), l.end(), [&](int x, int y) { return names[x] < names[y]; });
cout << "Buildings (BST inorder): ";
inorder(root);
cout << "\n";
string cmd;
while (cin >> cmd) {
if (cmd == "ROUTE") {
string a, b;
cin >> a >> b;
int s = findId(root, a), t = findId(root, b);
if (s == -1 || t == -1) { cout << "unknown building\n"; continue; }
vector<int> parent;
vector<int> dist = bfsDistances(s, adj, parent);
if (dist[t] == -1) { cout << "no route from " << a << " to " << b << "\n"; continue; }
vector<string> path;
for (int v = t; v != -1; v = parent[v]) path.push_back(names[v]);
cout << "route " << a << " -> " << b << " (" << dist[t] << " hops): ";
for (int k = path.size() - 1; k >= 0; k--) cout << path[k] << (k ? " > " : "\n");
} else if (cmd == "NEAREST") {
string a;
cin >> a;
int s = findId(root, a);
if (s == -1) { cout << "unknown building\n"; continue; }
vector<int> parent;
vector<int> dist = bfsDistances(s, adj, parent);
vector<Result> r;
for (int v = 0; v < n; v++) if (v != s && dist[v] != -1) r.push_back({names[v], dist[v]});
mergeSort(r, 0, (int)r.size() - 1);
cout << "nearest to " << a << ":";
for (auto& x : r) cout << " " << x.name << "(" << x.hops << ")";
cout << "\n";
} else if (cmd == "REACH") {
string a;
cin >> a;
int s = findId(root, a);
if (s == -1) { cout << "unknown building\n"; continue; }
vector<bool> seen(n, false);
vector<int> order;
dfs(s, adj, seen, order);
vector<string> reach;
for (int v : order) reach.push_back(names[v]);
cout << "DFS order from " << a << ":";
for (auto& x : reach) cout << " " << x;
quickSort(reach, 0, (int)reach.size() - 1);
cout << "\nreachable A-Z:";
for (auto& x : reach) cout << " " << x;
cout << "\n";
}
}
destroy(root);
} Expected output (with sample input)
Buildings (BST inorder): Admin Cafeteria Clinic Dorm Gate Lab Library Stadium route Gate -> Stadium (3 hops): Gate > Library > Lab > Stadium route Admin -> Dorm (3 hops): Admin > Library > Cafeteria > Dorm no route from Gate to Clinic nearest to Library: Admin(1) Cafeteria(1) Gate(1) Lab(1) Dorm(2) Stadium(2) DFS order from Gate: Gate Admin Library Cafeteria Dorm Stadium Lab reachable A-Z: Admin Cafeteria Dorm Gate Lab Library Stadium