/* * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include struct Graph { size_t n; Edge *matrix; }; Graph * GraphCreate(size_t n) { Graph *g; if (!n) { return NULL; } g = Malloc(sizeof(Graph)); if (!g) { return NULL; } g->n = n; g->matrix = Malloc((n * n) * sizeof(Edge)); if (!g->matrix) { Free(g); return NULL; } memset(g->matrix, 0, (n * n) * sizeof(Edge)); return g; } Graph * GraphCreateWithEdges(size_t n, Edge * matrix) { Graph *g = GraphCreate(n); if (!g) { return NULL; } memcpy(g->matrix, matrix, (n * n) * sizeof(Edge)); return g; } void GraphFree(Graph * g) { if (!g) { return; } Free(g->matrix); Free(g); } Edge GraphEdgeGet(Graph * g, Node n1, Node n2) { if (n1 >= g->n || n2 >= g->n) { return -1; } return g->matrix[(g->n * n1) + n2]; } Edge GraphEdgeSet(Graph * g, Node n1, Node n2, Edge e) { int oldVal; if (n1 >= g->n || n2 >= g->n) { return -1; } if (e < 0) { return -1; } oldVal = g->matrix[(g->n * n1) + n2]; g->matrix[(g->n * n1) + n2] = e; return oldVal; } size_t GraphCountNodes(Graph * g) { return g ? g->n : 0; } Node * GraphBreadthFirstSearch(Graph * G, Node s, size_t * n) { Node *visited; Node *queue; Node *result; size_t queueSize; Node i; if (!G || !n) { return NULL; } *n = 0; result = Malloc(G->n * sizeof(Node)); if (!result) { return NULL; } if (s >= G->n) { Free(result); return NULL; } visited = Malloc(G->n * sizeof(Node)); memset(visited, 0, G->n * sizeof(Node)); queue = Malloc(G->n * sizeof(Node)); queueSize = 0; visited[s] = 1; queueSize++; queue[queueSize - 1] = s; while (queueSize) { s = queue[queueSize - 1]; queueSize--; result[*n] = s; (*n)++; for (i = 0; i < G->n; i++) { if (GraphEdgeGet(G, s, i) && !visited[i]) { visited[i] = 1; queueSize++; queue[queueSize - 1] = i; } } } Free(visited); Free(queue); return result; } static void GraphDepthFirstSearchRecursive(Graph * G, Node s, Node * result, size_t * n, Node * visited) { size_t i; visited[s] = 1; result[*n] = s; (*n)++; for (i = 0; i < G->n; i++) { if (GraphEdgeGet(G, s, i) && !visited[i]) { GraphDepthFirstSearchRecursive(G, i, result, n, visited); } } } Node * GraphDepthFirstSearch(Graph * G, Node s, size_t * n) { Node *visited; Node *result; if (!G || !n) { return NULL; } result = Malloc(G->n * sizeof(Node)); if (!result) { return NULL; } *n = 0; if (s >= G->n) { Free(result); return NULL; } visited = Malloc(G->n * sizeof(Node)); memset(visited, 0, G->n * sizeof(Node)); GraphDepthFirstSearchRecursive(G, s, result, n, visited); Free(visited); return result; } static void GraphTopologicalSortRecursive(Graph * G, Node s, Node * visited, Node * stack, size_t * stackSize) { size_t i; visited[s] = 1; for (i = 0; i < G->n; i++) { if (GraphEdgeGet(G, s, i) && !visited[i]) { GraphTopologicalSortRecursive(G, i, visited, stack, stackSize); } } stack[*stackSize] = s; (*stackSize)++; } Node * GraphTopologicalSort(Graph * G, size_t * n) { Node *visited; Node *stack; Node *result; size_t i; size_t stackSize; if (!G || !n) { return NULL; } *n = 0; result = Malloc(G->n * sizeof(Node)); if (!result) { return NULL; } visited = Malloc(G->n * sizeof(Node)); memset(visited, 0, G->n * sizeof(Node)); stack = Malloc(G->n * sizeof(Node)); memset(stack, 0, G->n * sizeof(Node)); stackSize = 0; for (i = 0; i < G->n; i++) { if (!visited[i]) { GraphTopologicalSortRecursive(G, i, visited, stack, &stackSize); } } Free(visited); while (stackSize) { stackSize--; result[*n] = stack[stackSize]; (*n)++; } Free(stack); return result; } Graph * GraphTranspose(Graph * G) { Graph *T = Malloc(sizeof(Graph)); size_t i, j; T->n = G->n; T->matrix = Malloc((G->n * G->n) * sizeof(Edge)); memset(T->matrix, 0, (T->n * T->n) * sizeof(Edge)); for (i = 0; i < G->n; i++) { for (j = 0; j < G->n; j++) { if (GraphEdgeGet(G, i, j)) { GraphEdgeSet(T, j, i, GraphEdgeGet(G, i, j)); } } } return T; }