diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..79ddb0c --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,21 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "windowsSdkVersion": "10.0.26100.0", + "compilerPath": "cl.exe", + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "windows-msvc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/Graph.cpp b/Graph.cpp index 13e9b6e..0023262 100644 --- a/Graph.cpp +++ b/Graph.cpp @@ -1,96 +1,149 @@ #include "Graph.h" // Begin : Construction & Deconstruction +Graph::Graph(size_t max_points, size_t max_edges) noexcept +{ + all_points = new(std::nothrow) Point[max_points] {}; + all_edges = new(std::nothrow) Edge[max_edges] {}; - /** Constructor - * Creates a new Graph object - * - * @param max_points : Maximum number of points in the Graph - * @param max_edges : Maximum number of edges in the GRAPH (not the point) - */ - Graph::Graph(size_t max_points, size_t max_edges) noexcept + if(all_points && all_edges) { - all_points = new(std::nothrow) Point[max_points] {}; - all_edges = new(std::nothrow) Edge[max_edges] {}; - - if(all_points && all_edges) - { - p_capacity = max_points; - e_capacity = max_edges; - } + p_capacity = max_points; + e_capacity = max_edges; } +} - /**Deconstruction - * NOTE on the '~Graph()': - * The ~ flags this block as a deconstructor. It makes it so this runs before the object is removed from memory preventing memory leaks - * Find the memory buffers pointed to by all_points and all_edges, and mark that memory as available for other programs to use. - * - */ - Graph::~Graph() - { - delete[] all_points; - delete[] all_edges; - } +Graph::~Graph() +{ + delete[] all_points; + delete[] all_edges; +} - /** Move Constructor - * Instructions to move the current graph object from one memory location to another without copying - */ - Graph::Graph(Graph&& other) noexcept - : all_points(std::exchange(other.all_points, nullptr)), - all_edges(std::exchange(other.all_edges, nullptr)), - p_capacity(std::exchange(other.p_capacity, 0)), - e_capacity(std::exchange(other.e_capacity, 0)) {} +Graph::Graph(Graph&& new_location) noexcept + : all_points(std::exchange(new_location.all_points, nullptr)), + all_edges(std::exchange(new_location.all_edges, nullptr)), + p_capacity(std::exchange(new_location.p_capacity, 0)), + e_capacity(std::exchange(new_location.e_capacity, 0)) {} // End : Construction & Deconstruction -// Begin : Getters +// ----------------------- BEGIN : Getters ----------------------- - /** Getter Function: get_p_edges - * Gets the address of the first edge for Point P at index p_index - * - * @param p_index : The index (int) of the point - * @returns Edge* : the address of the first edge for p_index - * */ - Edge* Graph::get_p_edges(int p_index) noexcept - { - //Checking for for index validity and that the point has edges - if(p_index < 0 || (size_t)p_index >= p_capacity) return nullptr; +Point* Graph::get_points() noexcept +{ + return all_points; +} - //assigning the start_point_index to be the first_edge in the points array of edges - //if it's negative one, there are not edges assigned - int start_point_index = all_points[p_index].first_edge; - if(start_point_index == -1) return nullptr; +Edge* Graph::get_p_edges(int p_index) noexcept +{ + if(p_index < 0 || (size_t)p_index >= p_capacity) return nullptr; - //if there are edges it returns the address of the first edge so that the user can iterate through them like an array - return &all_edges[start_point_index]; - } + int head_idx = all_points[p_index].first_edge; + if(head_idx == -1) return nullptr; + + return &all_edges[head_idx]; +} +// ----------------------- END : Getters ----------------------- +// ----------------------- BEGIN : Mutators ----------------------- -// Begin : Setters - /** add_edge - * Adds an edge between two points - * - * @param start_point_index : the index of the starting point - * @param end_point_index : the index of the ending point - * - **/ - void Graph::add_edge(int start_point_index, int end_point_index) noexcept - { - if (next_possible_edge >= e_capacity) return; // Buffer full +Point* Graph::add_point(std::string name, float x, float y, float z) noexcept { + int target_idx = -1; - // 1. If this is the first edge for this point, record the start index - if (all_points[start_point_index].e_count == 0) - { - all_points[end_point_index].first_edge = next_possible_edge; - } + if (next_free_point != -1) { + target_idx = next_free_point; + // The hijacked 'first_edge' tells us where the NEXT hole is + next_free_point = all_points[target_idx].first_edge; + } + else if (num_points < p_capacity) { + target_idx = (int)num_points; + num_points++; + } + else return nullptr; - // 2. Place the edge in the flat buffer - all_edges[next_possible_edge].target_point = end_point_index; + Point* p = &all_points[target_idx]; + p->name = name; + p->x = x; p->y = y; p->z = z; + p->first_edge = -1; + p->e_count = 0; - // 3. Update counters - all_points[start_point_index].e_count++; - next_possible_edge++; + return p; +} + + +bool Graph::delete_point(int p_index) { + if (p_index < 0 || (size_t)p_index >= p_capacity) return false; + + // 1. IMPORTANT: Clean up all edges belonging to this point first! + // While the point has edges, delete the 'end_point' of the first edge. + while (all_points[p_index].first_edge != -1) { + int target_end = all_edges[all_points[p_index].first_edge].end_point; + delete_edge(p_index, target_end); } -// End : Setters \ No newline at end of file + // 2. Hijack point for Free List + all_points[p_index].first_edge = next_free_point; + all_points[p_index].e_count = -1; + next_free_point = p_index; + + return true; +} + + +Edge* Graph::add_edge(int e_start, int e_end, float weight) noexcept { + // Validation: Ensure indices are within bounds + if (e_start < 0 || (size_t)e_start >= p_capacity || + e_end < 0 || (size_t)e_end >= p_capacity) return nullptr; + + int target_edge = -1; + + if (next_free_edge != -1) { + target_edge = next_free_edge; + next_free_edge = all_edges[target_edge].next_edge; + } + else if (num_edges < e_capacity) { + target_edge = (int)num_edges; + num_edges++; + } + else return nullptr; + + // Initialize and Link + all_edges[target_edge].end_point = e_end; + all_edges[target_edge].e_weight = weight; + + // Link to Point's head + all_edges[target_edge].next_edge = all_points[e_start].first_edge; + all_points[e_start].first_edge = target_edge; + all_points[e_start].e_count++; + + return &all_edges[target_edge]; +} + +bool Graph::delete_edge(int e_start, int e_end) noexcept { + Point& p = all_points[e_start]; + int current = p.first_edge; + int prev = -1; + + // 1. Traverse the linked list of edges for this point + while (current != -1) { + if (all_edges[current].end_point == e_end) { + // 2. Unhook the node + if (prev == -1) p.first_edge = all_edges[current].next_edge; + else all_edges[prev].next_edge = all_edges[current].next_edge; + + // 3. Add the edge slot back to the global free list + all_edges[current].next_edge = next_free_edge; + next_free_edge = current; + + p.e_count--; + return true; + } + prev = current; + current = all_edges[current].next_edge; + } + return false; +} + + +// ----------------------- END : Mutators ----------------------- \ No newline at end of file diff --git a/documentation/html/annotated.html b/documentation/html/annotated.html new file mode 100644 index 0000000..bf9bc37 --- /dev/null +++ b/documentation/html/annotated.html @@ -0,0 +1,111 @@ + + +
+ + + + +|
+ Graph Theory
+
+ |
+
|
+ Graph Theory
+
+ |
+
This is the complete list of members for Graph, including all inherited members.
+| add_edge(int start_point_index, int end_point_index) noexcept | Graph | |
| get_p_edges(int p_index) noexcept | Graph | |
| Graph(size_t maxPoints, size_t maxEdges) noexcept | Graph | |
| Graph(Graph &&other) noexcept | Graph | |
| Graph(const Graph &)=delete (defined in Graph) | Graph | |
| operator=(const Graph &)=delete (defined in Graph) | Graph | |
| ~Graph() | Graph |
|
+ Graph Theory
+
+ |
+
+Public Member Functions | |
| Graph (size_t maxPoints, size_t maxEdges) noexcept | |
| ~Graph () | |
| Graph (Graph &&other) noexcept | |
| Edge * | get_p_edges (int p_index) noexcept |
| void | add_edge (int start_point_index, int end_point_index) noexcept |
| + | Graph (const Graph &)=delete |
| +Graph & | operator= (const Graph &)=delete |
+
|
+ +noexcept | +
| Graph::~Graph | +( | +) | ++ |
Deconstruction NOTE on the '~Graph()': The ~ flags this block as a deconstructor. It makes it so this runs before the object is removed from memory preventing memory leaks Find the memory buffers pointed to by all_points and all_edges, and mark that memory as available for other programs to use.
+ +
+
|
+ +noexcept | +
Move Constructor Instructions to move the current graph object from one memory location to another without copying
+ +
+
|
+ +noexcept | +
add_edge Adds an edge between two points
+| start_point_index | : the index of the starting point |
| end_point_index | : the index of the ending point |
+
|
+ +noexcept | +
Getter Function: get_p_edges Gets the address of the first edge for Point P at index p_index
+| p_index | : The index (int) of the point |
|
+ Graph Theory
+
+ |
+
|
+ Graph Theory
+
+ |
+
|
+ Graph Theory
+
+ |
+
|
+ Graph Theory
+
+ |
+
|
+ Graph Theory
+
+ |
+
|
+ Graph Theory
+
+ |
+