finished
This commit is contained in:
@@ -3,10 +3,11 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|||||||
|
|
||||||
|
|
||||||
# "ON" = build Option 1, "OFF" = build Option 2.
|
# "ON" = build Option 1, "OFF" = build Option 2.
|
||||||
option(BUILD_ASSIGNMENT_04_OPTION_1 "Build Assignment Option 1 (Standard)" OFF)
|
option(BUILD_ASSIGNMENT_04_OPTION_1 "Build Assignment Option 1 (Standard)" ON)
|
||||||
|
|
||||||
add_executable(Assignment-04
|
add_executable(Assignment-04
|
||||||
main.cpp
|
main.cpp
|
||||||
|
option1.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(BUILD_ASSIGNMENT_04_OPTION_1)
|
if(BUILD_ASSIGNMENT_04_OPTION_1)
|
||||||
|
|||||||
@@ -28,16 +28,18 @@ To force an update (e.g., in Visual Studio):
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include "option1.h"
|
||||||
static constexpr std::string_view AssignmentName = "Category 4: Graphs & Dijkstra's Algorithm";
|
static constexpr std::string_view AssignmentName = "Category 4: Graphs & Dijkstra's Algorithm";
|
||||||
|
|
||||||
#if ASSIGNMENT_04_OPTION == 1
|
|
||||||
static constexpr std::string_view AssignmentOption = "Option 1 (Standard): Data Center Network Monitor.";
|
static constexpr std::string_view AssignmentOption = "Option 1 (Standard): Data Center Network Monitor.";
|
||||||
|
|
||||||
|
/*
|
||||||
|
#if ASSIGNMENT_04_OPTION == 1
|
||||||
#include "option1.h"
|
#include "option1.h"
|
||||||
#elif ASSIGNMENT_04_OPTION == 2
|
#elif ASSIGNMENT_04_OPTION == 2
|
||||||
static constexpr std::string_view AssignmentOption = "Option 2 (Advanced): Inter-city Logistics Router.";
|
static constexpr std::string_view AssignmentOption = "Option 2 (Advanced): Inter-city Logistics Router.";
|
||||||
#include "option2.h"
|
#include "option2.h"
|
||||||
#endif
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,261 @@
|
|||||||
#include "option1.h"
|
#include "option1.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "SharedLib.h"
|
||||||
|
|
||||||
|
// Necessary declarations
|
||||||
|
constexpr float INF = 1e9f;
|
||||||
|
Graph g;
|
||||||
|
std::unordered_map<std::string, int> nameToIndex;
|
||||||
|
std::string filename = R"(C:\Users\csand\IKT203\Exam\IKT203Exam\DATA\network_graph.txt)"; // Local path to MY graph file
|
||||||
|
|
||||||
|
//////////////////////////////// Callbacks ////////////////////////////////
|
||||||
|
bool onNodeRead(const int aIndex, const int aTotalCount, const std::string& aNode)
|
||||||
|
{
|
||||||
|
const int idx = g.AddVertex(aNode);
|
||||||
|
nameToIndex[aNode] = idx;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool onEdgeRead(const int aIndex, const int aTotalCount, const std::string& aFromNode, const std::string& aToNode, const float aWeight)
|
||||||
|
{
|
||||||
|
const int fromIdx = nameToIndex[aFromNode];
|
||||||
|
const int toIdx = nameToIndex[aToNode];
|
||||||
|
|
||||||
|
g.AddUndirectedEdge(fromIdx, toIdx, aWeight);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////// Dijkstra algorithm ////////////////////////////////
|
||||||
|
float Dijkstra(const Graph& graph, int src, int dst, std::vector<int>& outPath)
|
||||||
|
{
|
||||||
|
const int n = graph.GetVertexCount();
|
||||||
|
|
||||||
|
std::vector<float> dist(n, INF);
|
||||||
|
std::vector<int> prev(n, -1);
|
||||||
|
std::vector<bool> visited(n, false);
|
||||||
|
|
||||||
|
dist[src] = 0.0f;
|
||||||
|
|
||||||
|
MinHeap heap;
|
||||||
|
heap.Push(src, 0.0f);
|
||||||
|
|
||||||
|
while (!heap.isEmpty()) {
|
||||||
|
HeapNode* node = heap.Pop();
|
||||||
|
const int u = node->vertex;
|
||||||
|
float d = node->distance;
|
||||||
|
delete node;
|
||||||
|
|
||||||
|
if (visited[u])
|
||||||
|
continue;
|
||||||
|
visited[u] = true;
|
||||||
|
if (u == dst)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (const TEdge* e : graph.GetEdges(u)) {
|
||||||
|
int v = e->toIndex;
|
||||||
|
float w = e->weight;
|
||||||
|
|
||||||
|
if (visited[v])
|
||||||
|
continue;
|
||||||
|
if (dist[u] + w < dist[v]) {
|
||||||
|
dist[v] = dist[u] + w;
|
||||||
|
prev[v] = u;
|
||||||
|
heap.Push(v, dist[v]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outPath.clear();
|
||||||
|
if (dist[dst] == INF)
|
||||||
|
return INF;
|
||||||
|
for (int v = dst; v != -1; v = prev[v])
|
||||||
|
outPath.push_back(v);
|
||||||
|
std::reverse(outPath.begin(), outPath.end());
|
||||||
|
return dist[dst];
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////// Class logic ////////////////////////////////
|
||||||
|
// Graph
|
||||||
|
Graph::~Graph()
|
||||||
|
{
|
||||||
|
for (TVertex* v : vertices) {
|
||||||
|
for (TEdge* e : v->edges) {
|
||||||
|
delete e;
|
||||||
|
}
|
||||||
|
delete v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Graph::AddVertex(const std::string& name)
|
||||||
|
{
|
||||||
|
auto* v = new TVertex;
|
||||||
|
v->name = name;
|
||||||
|
vertices.push_back(v);
|
||||||
|
return static_cast<int>(vertices.size()) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graph::AddUndirectedEdge(int fromIndex, int toIndex, float weight)
|
||||||
|
{
|
||||||
|
TEdge* e1 = new TEdge;
|
||||||
|
e1->toIndex = toIndex;
|
||||||
|
e1->weight = weight;
|
||||||
|
|
||||||
|
TEdge* e2 = new TEdge;
|
||||||
|
e2->toIndex = fromIndex;
|
||||||
|
e2->weight = weight;
|
||||||
|
|
||||||
|
vertices[fromIndex]->edges.push_back(e1);
|
||||||
|
vertices[toIndex]->edges.push_back(e2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Graph::GetVertexCount() const
|
||||||
|
{
|
||||||
|
return static_cast<int>(vertices.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
const TVertex *Graph::GetVertex(int index) const
|
||||||
|
{
|
||||||
|
return vertices[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<TEdge*>& Graph::GetEdges(const int index) const
|
||||||
|
{
|
||||||
|
return vertices[index]->edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Heap
|
||||||
|
MinHeap::~MinHeap()
|
||||||
|
{
|
||||||
|
for (HeapNode* n : data)
|
||||||
|
delete n;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MinHeap::isEmpty() const
|
||||||
|
{
|
||||||
|
return data.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MinHeap::Push(int vertex, float dist)
|
||||||
|
{
|
||||||
|
auto* n = new HeapNode{vertex, dist};
|
||||||
|
data.push_back(n);
|
||||||
|
HeapUp(static_cast<int>(data.size()) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapNode* MinHeap::Pop()
|
||||||
|
{
|
||||||
|
if (data.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
HeapNode* root = data[0];
|
||||||
|
data[0] = data.back();
|
||||||
|
data.pop_back();
|
||||||
|
if (!data.empty())
|
||||||
|
HeapDown(0);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MinHeap::HeapUp(int idx)
|
||||||
|
{
|
||||||
|
while (idx > 0) {
|
||||||
|
int parent = (idx - 1) / 2;
|
||||||
|
if (data[parent]->distance <= data[idx]->distance)
|
||||||
|
break;
|
||||||
|
std::swap(data[idx], data[parent]);
|
||||||
|
idx = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MinHeap::HeapDown(int idx)
|
||||||
|
{
|
||||||
|
int n = static_cast<int>(data.size());
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int left = 2 * idx + 1;
|
||||||
|
int right = 2 * idx + 2;
|
||||||
|
int smallest = idx;
|
||||||
|
|
||||||
|
if (left < n && data[left]->distance < data[smallest]->distance)
|
||||||
|
smallest = left;
|
||||||
|
if (right < n && data[right]->distance < data[smallest]->distance)
|
||||||
|
smallest = right;
|
||||||
|
|
||||||
|
if (smallest == idx)
|
||||||
|
break;
|
||||||
|
std::swap(data[idx], data[smallest]);
|
||||||
|
idx = smallest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int RunApp() {
|
int RunApp() {
|
||||||
|
|
||||||
|
readGraphFromFile(filename, onNodeRead, onEdgeRead);
|
||||||
|
|
||||||
|
// Debug: Print all nodes and vertices
|
||||||
|
/*
|
||||||
|
pack("Graph");
|
||||||
|
for (int i = 0; i < g.GetVertexCount(); i++) {
|
||||||
|
const TVertex* v = g.GetVertex(i);
|
||||||
|
std::cout << i << ": " << v->name << std::endl;
|
||||||
|
for (const TEdge* e : g.GetEdges(i)) {
|
||||||
|
std::cout << " -> " << e->toIndex << " (weight = " << e->weight << ")" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Debug heap test
|
||||||
|
pack("Heap");
|
||||||
|
MinHeap test;
|
||||||
|
test.Push(1, 5.0f);
|
||||||
|
test.Push(2, 3.0f);
|
||||||
|
test.Push(3, 10.0f);
|
||||||
|
while (!test.isEmpty())
|
||||||
|
{
|
||||||
|
const HeapNode* n = test.Pop();
|
||||||
|
std::cout << "(" << n->vertex << ", " << n->distance << ")" << "\n";
|
||||||
|
delete n;
|
||||||
|
}
|
||||||
|
printline();
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::cout << "\nGraph:" << std::endl;
|
||||||
|
for (int i = 0; i < g.GetVertexCount(); ++i)
|
||||||
|
std::cout << i << ": " << g.GetVertex(i)->name << std::endl;
|
||||||
|
|
||||||
|
int src, dst;
|
||||||
|
std::cout << "\nEnter source index: ";
|
||||||
|
std::cin >> src;
|
||||||
|
std::cout << "\nEnter destination index: ";
|
||||||
|
std::cin >> dst;
|
||||||
|
if (src < 0 || src >= g.GetVertexCount() ||
|
||||||
|
dst < 0 || dst >= g.GetVertexCount()) {
|
||||||
|
std::cout << "Invalid indices.\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> path;
|
||||||
|
float total = Dijkstra(g, src, dst, path);
|
||||||
|
|
||||||
|
if (total >= INF) {
|
||||||
|
std::cout << "\nNo path between those nodes.\n";
|
||||||
|
} else {
|
||||||
|
std::cout << "\nLowest latency path: ";
|
||||||
|
for (size_t i = 0; i < path.size(); ++i) {
|
||||||
|
std::cout << g.GetVertex(path[i])->name;
|
||||||
|
if (i + 1 < path.size()) std::cout << " -> ";
|
||||||
|
}
|
||||||
|
std::cout << " \n(Total: " << total << " ms)\n";
|
||||||
|
}
|
||||||
|
printline();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,81 @@
|
|||||||
|
|
||||||
#ifndef OPTION1_H
|
#ifndef OPTION1_H
|
||||||
#define OPTION1_H
|
#define OPTION1_H
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Structs and classes
|
||||||
|
struct TEdge {
|
||||||
|
int toIndex;
|
||||||
|
float weight;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TVertex {
|
||||||
|
std::string name;
|
||||||
|
std::vector<TEdge*> edges;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HeapNode {
|
||||||
|
int vertex;
|
||||||
|
float distance;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MinHeap {
|
||||||
|
private:
|
||||||
|
std::vector<HeapNode*> data;
|
||||||
|
|
||||||
|
void HeapUp(int idx);
|
||||||
|
void HeapDown(int idx);
|
||||||
|
|
||||||
|
public:
|
||||||
|
~MinHeap();
|
||||||
|
|
||||||
|
[[nodiscard]] bool isEmpty() const;
|
||||||
|
void Push(int vertex, float dist);
|
||||||
|
HeapNode* Pop();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Graph {
|
||||||
|
private:
|
||||||
|
std::vector<TVertex*> vertices; // Owns all TVertex*
|
||||||
|
|
||||||
|
public:
|
||||||
|
~Graph();
|
||||||
|
|
||||||
|
int AddVertex(const std::string& name);
|
||||||
|
void AddUndirectedEdge(int fromIndex, int toIndex, float weight);
|
||||||
|
|
||||||
|
[[nodiscard]] int GetVertexCount() const;
|
||||||
|
[[nodiscard]] const TVertex* GetVertex(int index) const;
|
||||||
|
[[nodiscard]] const std::vector<TEdge*>& GetEdges(int index) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Callbacks & funcs
|
||||||
|
bool onNodeRead(int aIndex, int aTotalCount, const std::string& aNode);
|
||||||
|
bool onEdgeRead(int aIndex, int aTotalCount, std::string& aFromNode, std::string& aToNode, float aWeight);
|
||||||
|
|
||||||
|
float Dijkstra(const Graph& graph, int src, int dst, std::vector<int>& outPath);
|
||||||
|
|
||||||
|
// Terminal tidying
|
||||||
|
inline void printline()
|
||||||
|
{
|
||||||
|
std::cout << "----------------------------------------" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void pack(const std::string& line)
|
||||||
|
{
|
||||||
|
std::cout << "\n\n\n" << std::endl;
|
||||||
|
printline();
|
||||||
|
std::cout << line << std::endl;
|
||||||
|
printline();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int RunApp();
|
int RunApp();
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ static bool EdgeReadCallback(const int aIndex, const int aTotalCount, const std:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
int RunApp()
|
int RunApp()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -44,4 +44,4 @@ int RunApp()
|
|||||||
std::cout << "\nFinished reading graph." << std::endl;
|
std::cout << "\nFinished reading graph." << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}*/
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#ifndef OPTION2_H
|
#ifndef OPTION2_H
|
||||||
#define OPTION2_H
|
#define OPTION2_H
|
||||||
|
/*
|
||||||
int RunApp();
|
int RunApp();
|
||||||
|
*/
|
||||||
|
|
||||||
#endif // OPTION2_H
|
#endif // OPTION2_H
|
||||||
|
|||||||
Reference in New Issue
Block a user