I am currently implementing a pseudocode of Dijkstra's Algorithm and I am having trouble in freeing the nodes. My code seems to be working fine except for the freeing part. I have freed all mallocs in the code but it still keeps on crashing.
I have checked all possible "mis-free" that might occur and I'm currently stuck with this.
Here is my code.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <math.h>
//#####################################################################
//#####################################################################
//#####################################################################
//#####################################################################
//######################### Structures ################################
//#####################################################################
struct node
{
int vertex;
int cost;
struct node* next;
};
struct PQ
{
int* heap;
int* index;
double* key;
int sizePQ;
};
//#####################################################################
//######################### Graph Things ##############################
//#####################################################################
struct node* createNode(int v,int cost)
{
struct node* newNode = malloc(sizeof(struct node));
newNode->vertex = v;
newNode->cost = cost;
newNode->next = NULL;
return newNode;
}
struct G{
int n;
int* pred;
double* dist;
struct node** LIST;
};
struct G* initGraph(int vertices)
{
struct G* graph = malloc(sizeof(struct G));
graph->n = vertices-1;
graph->LIST = malloc(vertices * sizeof(struct node*));
graph->pred = malloc(vertices * sizeof(int));
graph->dist = malloc(vertices * sizeof(double));
int i;
for (i = 0; i <= vertices; i++)
graph->LIST[i] = NULL;
return graph;
}
void addEdge(struct G* graph, int src, int dest, int cost)
{
struct node* newNode = createNode(dest, cost);
newNode->next = graph->LIST[src];
graph->LIST[src] = newNode;
}
void freeG(struct G* graph){
int v;
for (v = 0; v <= graph->n+1; v++)
{
struct node* temp = graph->LIST[v];
struct node* temp2 = temp->next;
while (temp!=NULL)
{
free(temp);
temp = temp2;
temp2 = temp->next;
}
}
free(graph->pred);
free(graph->dist);
free(graph->LIST);
free(graph);
}
void freePQ(struct PQ* PQ){
free(PQ->heap);
free(PQ->key);
free(PQ->index);
free(PQ);
}
//#####################################################################
//############################ Procedures #############################
//#####################################################################
void PQ_UNDERFLOW(){
printf("Underflow Detected");
}
void InitPQ(struct G* G,struct PQ* PQ, int s){
PQ->heap = malloc(G->n * sizeof(int));
PQ->index = malloc(G->n * sizeof(int));
PQ->key = malloc(G->n * sizeof(double));
PQ->sizePQ = G->n;
// printf("%i",G->n);
int i = 1;
int v;
for(v=1;v<=G->n;v++){
if(v==s){
PQ->heap[1]=s;
PQ->index[s]=1;
PQ->key[s]=0;
}
else{
++i;
PQ->heap[i]=v;
PQ->index[v]=i;
PQ->key[v]=INFINITY;
// printf("%i//",PQ->heap[i]);
//printf("%lf ",PQ->key[v]);
}
}
}
void HEAPIFY(struct PQ* PQ,int r){
//printf("%i",PQ->heap[r]-1);
double k = PQ->key[PQ->heap[r]];
int l = PQ->heap[r];
int i = r, j = 2*i;
while(j<=PQ->sizePQ){
if (j<PQ->sizePQ && PQ->key[PQ->heap[j+1]]< PQ->key[PQ->heap[j]]){
++j;
}
if(PQ->key[PQ->heap[j]]<k){
PQ->heap[i]=PQ->heap[j];
PQ->index[PQ->heap[j]]=i;
i=j;
j=2*i;
}else break;
}
PQ->heap[i]=l;
PQ->index[l]=i;
}
int IsEmptyPQ(struct PQ* PQ){
return(PQ->sizePQ==0);
}
void EXTRACT_MIN(struct PQ* PQ, int *j){
if (PQ->sizePQ == 0) PQ_UNDERFLOW();
else{
*j=PQ->heap[1];
PQ->heap[1] = PQ->heap[PQ->sizePQ];
PQ->index[PQ->heap[1]]=1;
PQ->sizePQ=PQ->sizePQ-1;
HEAPIFY(PQ,1);
}
}
void DECREASE_KEY(struct PQ* PQ, int l, double newkey){
PQ->key[l] = newkey;
int i = PQ->index[l];//printf("pqindexl->%i\n",PQ->index[l]);
int j =floor(i/2);
while (i > 1 && PQ->key[PQ->heap[j]]>newkey){
PQ->heap[i]= PQ->heap[j];
PQ->index[PQ->heap[j]]=i;
i=j; j =floor(i/2);
}
PQ->heap[i]=l;
PQ->index[l]=i;
}
//#####################################################################
//############################ DIJKSTRA #############################
//#####################################################################
void DIJKSTRA(struct G* G, struct PQ* PQ, int s){
InitPQ(G,PQ,s);
int u = 0,v;
double newval;
G->pred[s]=0;
while(!IsEmptyPQ(PQ)){
EXTRACT_MIN(PQ,&u);
if (PQ->key[u]== INFINITY){break;}
struct node* a = G->LIST[u];
while (a!=NULL)
{
v = a->vertex;//printf("vertex = %i\n",a->vertex);
newval = PQ->key[u]+a->cost;
if (PQ->key[v]>newval){
G->pred[v]=u;
DECREASE_KEY(PQ,v,newval);
}
a = a->next;
}
}
G->dist=PQ->key;
}
//#####################################################################
//############################ print g #############################
//#####################################################################
void DISPLAY_PATH(struct G* G, int s,int v){
int path[G->n];
int len = 1;
path[len]=v;
int i=v;
while(i!=s){
if(G->pred[i]==0){printf("No path found");return;}
else{
i = G->pred[i];
++len;
path[len]=i;
}
}
printf("Shortest path found: ");
while(len>=1){
printf("%i",path[len]);
if(len!=1)printf(" -> ");
len--;
}
}
void printGraph(struct G* graph)
{
int v;
for (v = 1; v <= graph->n; v++)
{
struct node* temp = graph->LIST[v];
printf("\n Adjacency list of vertex %d\n ", v);
while (temp)
{
printf("%d -> ", temp->vertex);
temp = temp->next;
}
printf("\n");
}
}
//#####################################################################
//#####################################################################
//#####################################################################
int main()
{
struct G* graph = initGraph(10);
addEdge(graph, 1, 2, 4);
addEdge(graph, 1, 8, 8);
addEdge(graph, 2, 3, 8);
addEdge(graph, 2, 8, 11);
addEdge(graph, 3, 4, 7);
addEdge(graph, 3, 9, 2);
addEdge(graph, 3, 6, 4);
addEdge(graph, 4, 5, 9);
addEdge(graph, 4, 6, 14);
addEdge(graph, 5, 6, 10);
addEdge(graph, 6, 7, 2);
addEdge(graph, 7, 8, 1);
addEdge(graph, 7, 9, 6);
addEdge(graph, 8, 9, 7);
printGraph(graph);
printf("\n");
struct PQ* PQ=malloc(sizeof(struct PQ));
DIJKSTRA(graph, PQ, 1);
DISPLAY_PATH(graph,1,8);
freePQ(PQ);
freeG(graph);
}
Everything works fine except for the freeing part. It prints the desired output for the algorithm but crashes at the end of the program.
I also really want to understand how malloc and freeing works and this might give me more information about it.
Here's what happens everytime I run it
EDIT: I have ran valgrind on my code and it appears to get an error called "core dumped". As far as i know, core dumped error occurs when I freed a node twice or more. I don't see any errors in my freeing codes though.
Here is what valgrind outputs
have you tried using Valgrind ? If so, are there any errors ?
Valgrind is a tool to check memory leaks and memory violation. It replaces your system malloc by its own to observe your actions.
Also please avoid using UPPERCASE functions, these should be reserved for macro and macro functions (#define).
You should also use typedef to rename your structs.
For example,
typedef struct s_myStruct
{
...
} t_myStruct;
t_mystruct *st = malloc(sizeof(t_mystruct));
This code seems wrong:
for (v = 0; v <= graph->n+1; v++)
{
struct node* temp = graph->LIST[v];
As n is initialized to 9 in initGraph this code will loop for v = 0, 1, ..., 10
However, in initGraph you malloc'ed 10 elements so now you access LIST out of bounds.
Try
for (v = 0; v < graph->n+1; v++)
{
struct node* temp = graph->LIST[v];
instead.
Then look at this:
struct node* temp = graph->LIST[v];
struct node* temp2 = temp->next;
What would happen if graph->LIST[v] is NULL?
The program will crash when you do:
temp2 = temp->next
So you need to turn the code into something like:
struct node* temp = graph->LIST[v];
while (temp!=NULL)
{
struct node* temp2 = temp->next;
free(temp);
temp = temp2;
}
Related
so I have this function which does a depth first search traversal of a graph and prints out the nodes traversed. But instead of printing the nodes I want this function to return the node it newly moved to, return one node per call of the function.
when I call the function with the start node 0, it should return the next node in traversal (order of the nodes when traversing is printed out when running the program, along with the graph's adjacency list), which is 1 but it is returning 3.
the traversal order is: 1 2 3 2 4 5 4 6
below is what I have tried:
int DFS(struct Graph* graph, int vertex) {
struct node* adjList = graph->adjLists[vertex];
struct node* temp = adjList;
int back = 0;
graph->visited[vertex] = 1;
while (temp != NULL) {
int connectedVertex = temp->vertex;
if (graph->visited[connectedVertex] == 0) {
if ( back==1 ) {
return vertex;
printf("node: %d\n", vertex);
}
printf("node 1: %d\n", connectedVertex);
return DFS(graph, connectedVertex);
back = 1;
}
temp = temp->next;
}
return vertex;
}
and here is the function without the return statements (originally a void function):
void DFS(struct Graph* graph, int vertex) {
struct node* adjList = graph->adjLists[vertex];
struct node* temp = adjList;
int back = 0; // = "We have already expanded vertex"
graph->visited[vertex] = 1;
while (temp != NULL) {
int connectedVertex = temp->vertex;
if (graph->visited[connectedVertex] == 0) {
if ( back==1 ) // Report the revisited node
printf("node: %d\n", vertex);
printf("node: %d\n", connectedVertex);
DFS(graph, connectedVertex);
back = 1; // Tag this node as having been expanded.
}
temp = temp->next;
}
}
and here is my full program:
// DFS algorithm in C
#include <stdio.h>
#include <stdlib.h>
struct node {
int vertex;
struct node* next;
};
struct node* createNode(int v);
struct Graph {
int numVertices;
int* visited;
struct node** adjLists;
};
void DFS(struct Graph* graph, int vertex) {
struct node* adjList = graph->adjLists[vertex];
struct node* temp = adjList;
int back = 0; // = "We have already expanded vertex"
graph->visited[vertex] = 1;
while (temp != NULL) {
int connectedVertex = temp->vertex;
if (graph->visited[connectedVertex] == 0) {
if ( back==1 ) // Report the revisited node
printf("node: %d\n", vertex);
printf("node: %d\n", connectedVertex);
DFS(graph, connectedVertex);
back = 1; // Tag this node as having been expanded.
}
temp = temp->next;
}
}
// Create a node
struct node* createNode(int v) {
struct node* newNode = malloc(sizeof(struct node));
newNode->vertex = v;
newNode->next = NULL;
return newNode;
}
// Create graph
struct Graph* createGraph(int vertices) {
struct Graph* graph = malloc(sizeof(struct Graph));
graph->numVertices = vertices;
graph->adjLists = malloc(vertices * sizeof(struct node*));
graph->visited = malloc(vertices * sizeof(int));
int i;
for (i = 0; i < vertices; i++) {
graph->adjLists[i] = NULL;
graph->visited[i] = 0;
}
return graph;
}
void sortedInsert(struct node** head_ref,
struct node* new_node)
{
struct node* current;
/* Special case for the head end */
if (*head_ref == NULL
|| (*head_ref)->vertex
>= new_node->vertex) {
new_node->next = *head_ref;
*head_ref = new_node;
}
else {
/* Locate the node before
the point of insertion */
current = *head_ref;
while (current->next != NULL
&& current->next->vertex < new_node->vertex) {
current = current->next;
}
new_node->next = current->next;
current->next = new_node;
}
}
// Add edge
void addEdge(struct Graph* graph, int src, int dest) {
// Add edge from src to dest
sortedInsert(&graph->adjLists[src], createNode(dest));
// Add edge from dest to src
sortedInsert(&graph->adjLists[dest], createNode(src));
}
// Print the graph
void printGraph(struct Graph* graph) {
int v;
for (v = 0; v < graph->numVertices; v++) {
struct node* temp = graph->adjLists[v];
printf("\n Adjacency list of vertex %d\n ", v);
while (temp) {
printf("%d -> ", temp->vertex);
temp = temp->next;
}
printf("\n");
}
}
int main() {
struct Graph* graph = createGraph(7);
addEdge(graph, 0, 1);
addEdge(graph, 0, 3);
addEdge(graph, 1, 2);
addEdge(graph, 2, 3);
addEdge(graph, 2, 4);
addEdge(graph, 4, 5);
addEdge(graph, 4, 6);
printGraph(graph);
DFS(graph, 0);
return 0;
}
Help would be much appreciated.
" I want this function to return the node it newly moved to, return one node per call of the function."
This is a bad idea, because your function is recursive.
To get the nodes traversed in order add the visited node index to a global data structure.
Note: Recursion is the correct way to go here. Returning the node visited from the recursive function will not work.
Allow me to describe how I would do this:
When searching through graphs, the concept of a "visitor" is useful. A visitor is a function that the search code calls each time it reaches a new node. It makes writing the search code slightly more complex, but you need only do it once. Once written you can adapt the algorithm to do different purposes without disturbing your carefully tested and optimized search code. In this case, all the visitor need do is record the node indexes as they are visited.
Note that once you have the visitor written, you can easily change the searching algorithm ( say from depth first to breadth first ) without writing new code.
Your visitor can look like this in C++
/// in global namespace
std::vector<int> gvIndexNodeVisitedOrder();
void visitor( int indexNode )
{
gvIndexNodeVositedOrder.push_back( indexNode );
}
The searching code looks like:
void depthFirstRecurse(
int v )
{
// Call the visitor
visitor(v);
// remember this node has been visited
gvNodeVisited[v] = 1;
// look at adjacent nodes
for (int w : adjacent(v)) {
// check node has not been visited
if (!gvNodeVisited[w])
{
// continue search from new node
depthFirstRecurse(w);
}
}
}
Note: I have placed stuff in the global namespace because the original question is tagged C. In reality I would use a C++ class and make the "globals" private attributes and methods of the class.
I added this two fuctions:
// Adds a node to a list of nodes
void addNode(struct node** nodeList, int vertex){
struct node *temp = *nodeList;
if(*nodeList == NULL){
*nodeList = createNode(vertex);
}else{
while(temp->next != NULL){
temp = temp->next;
}
temp->next = createNode(vertex);
}
}
// Prints a list of nodes
void printNodeList(struct node* nodeList) {
struct node* temp = nodeList;
while(temp != NULL){
printf("%d", temp->vertex);
if(temp->next != NULL){
printf(" -> ");
}
temp = temp->next;
}
printf("\n");
}
and modified DFS and main as follow:
// added last argument
void DFS(struct Graph* graph, int vertex, struct node** nodeList) {
struct node* adjList = graph->adjLists[vertex];
struct node* temp = adjList;
graph->visited[vertex] = 1;
addNode(nodeList, vertex); // added this
while (temp != NULL) {
int connectedVertex = temp->vertex;
if (graph->visited[connectedVertex] == 0) {
printf("node: %d\n", connectedVertex);
DFS(graph, connectedVertex, nodeList);
addNode(nodeList, vertex); // added this
}
temp = temp->next;
}
}
int main() {
struct node* nodeList = NULL;
struct Graph* graph = createGraph(7);
addEdge(graph, 0, 1);
addEdge(graph, 0, 3);
addEdge(graph, 1, 2);
addEdge(graph, 2, 3);
addEdge(graph, 2, 4);
addEdge(graph, 4, 5);
addEdge(graph, 4, 6);
printGraph(graph);
DFS(graph, 0, &nodeList);
printNodeList(nodeList);
return 0;
}
If I would have to define the traversal order of the nodes, in your example graph it would not be 1 -> 2 -> 3 -> 2 -> 4 -> 5 -> 4 -> 6 but rather 0 -> 1 -> 2 -> 3 -> 2 -> 4 -> 5 -> 4 -> 6 -> 4 -> 2 -> 1 -> 0, since I think that any time you "land" on a different node (either because you call DFS or because DFS gives back control to the caller), that "counts" in the path you're following to search the graph, and this until you're back to the main function, hence you've finished searching. Therefore in the DFS function above I implemented that, but if you need the order you mentioned, just add addNode(nodeList, vertex); below your printf statements and you should get it.
Since the function is recursive you can't really use the return statement to return the visited nodes, because what you want to have at the end is a list of elements and not just a single value. For instance in your code you defined the return type of DFS as int, this means that the function can only give you back a number, but when you call DFS in your main function you expect it to give you back a list of node that got visited. You may be able to figure out something returning a pointer to a data structure or maybe returning an int (the visited vertex) and calling something like addNode(list, DFS(g, vertex)) but you would still need to pass the list to DFS (otherwise you won't be able to call addNode(list,...) inside of it), so you would get addNode(list, DFS(g, vertex, list)), therefore I don't think you would get any advantage out of it, but I don't know.
What I did is to define a list in the main function and to pass it to the recursive function (does not need to return anything), which is then able to add the visited node to it when necessary. The first call to addNode(nodeList, vertex) happens only once per vertex since you never call DFS more than one time for any vertex, while the second happens every time you come back to a vertex after having searched into one of it's neighbors.
Afternoon, I'm getting a strange valgrind error reporting. Please see attached images.
I have a function which frees the heap or I though I did. Need help with tracking down this bug. Fixes are welcome but also an explanation as well.
My analysis of the valgrind tracks it down to line 67, when I created the node, so I know it is likely I forgotten to free it with my free function.
#include "stdio.h"
#include "stdlib.h"
#include "limits.h"
struct adj_list_node
{
int vertex;
int weight;
struct adj_list_node *next;
};
struct adj_list
{
struct adj_list_node *head;
};
struct graph
{
int vertices;
struct adj_list *array;
};
struct adj_list_node* create_node(int vertex, int weight);
struct graph *create_graph(int vertices);
void add_edge(struct graph *graph, int src_vertex, int dst_vertex, int weight);
void free_nodes(struct adj_list_node *node);
void free_graph(struct graph *graph);
struct min_heap_node
{
int vertex;
int distance;
};
struct min_heap
{
int size;
int capacity;
int *position;
struct min_heap_node **array;
};
struct min_heap_node *create_heap_node(int vertex, int distance);
struct min_heap *create_heap(int capacity);
void swap_node(struct min_heap_node** a, struct min_heap_node** b);
int is_empty(struct min_heap* heap);
void min_heapify(struct min_heap *heap, int parent);
struct min_heap_node *extract_min_node(struct min_heap* heap);
int is_in_min_heap(struct min_heap *heap, int index);
void decrease_key(struct min_heap *heap, int index, int distance);
void dijkstra(struct graph* graph, int src_vertex);
void delete_heap(struct min_heap *heap);
void print_path(int parent[], int vertex);
void print_array(int dist[], int n,int parent[]);
#include "dikjkstra.h"
struct adj_list_node* create_adj_node(int vertex, int weight)
{
struct adj_list_node *new_node = malloc(sizeof(struct adj_list_node));
new_node->vertex = vertex;
new_node->weight = weight;
new_node->next = NULL;
return new_node;
}
struct graph *create_graph(int vertices)
{
struct graph *new_graph = malloc(sizeof(struct graph));
new_graph->vertices = vertices;
new_graph->array = malloc(sizeof(struct adj_list) * vertices);
for (int i = 0;i < vertices; ++i) {
new_graph->array[i].head = NULL;
}
return new_graph;
}
void add_edge(struct graph *graph, int src_vertex, int dst_vertex, int weight)
{
struct adj_list_node *new_node = create_adj_node(dst_vertex, weight);
new_node->next = graph->array[src_vertex].head;
graph->array[src_vertex].head = new_node;
new_node = create_adj_node(src_vertex, weight);
new_node->next = graph->array[dst_vertex].head;
graph->array[dst_vertex].head = new_node;
}
void free_nodes(struct adj_list_node *node)
{
if (node == NULL) {
return;
}
struct adj_list_node *temp_node = node;
while (temp_node) {
struct adj_list_node *removed_node = temp_node;
temp_node = removed_node->next;
removed_node->next = NULL;
free(removed_node);
}
}
void free_graph(struct graph *graph)
{
if(graph->array == NULL) {
return;
}
for (int i = 0; i < graph->vertices; ++i) {
free_nodes(graph->array[i].head);
}
free(graph->array);
}
struct min_heap_node *create_heap_node(int vertex, int distance)
{
struct min_heap_node *new_node = malloc(sizeof(struct min_heap_node));
new_node->vertex = vertex;
new_node->distance = distance;
return new_node;
}
struct min_heap *create_heap(int capacity)
{
struct min_heap *new_heap = malloc(sizeof(struct min_heap));
new_heap->size = 0;
new_heap->capacity = capacity;
new_heap->position = malloc(capacity * sizeof(int));
new_heap->array = malloc(sizeof(struct min_heap_node *) * capacity);
return new_heap;
}
void swap_node(struct min_heap_node** a, struct min_heap_node** b)
{
struct min_heap_node *temp_node;
temp_node = *a;
*a = *b;
*b = temp_node;
}
int is_empty(struct min_heap* heap)
{
return heap->size == 0;
}
void min_heapify(struct min_heap *heap, int parent)
{
int left_child = 2 * parent + 1;
int right_child = 2 * parent + 2;
int smallest = parent;
if (left_child < heap->size && heap->array[left_child]->distance < heap->array[smallest]->distance) {
smallest = left_child;
}
if ( right_child < heap->size && heap->array[right_child]->distance < heap->array[smallest]->distance) {
smallest = right_child;
}
if (smallest != parent) {
struct min_heap_node *smallest_node = heap->array[smallest];
struct min_heap_node *temp_node = heap->array[parent];
heap->position[smallest_node->vertex] = parent;
heap->position[temp_node->vertex] = smallest;
swap_node(&heap->array[smallest], &heap->array[parent]);
min_heapify(heap, smallest);
}
}
struct min_heap_node *extract_min_node(struct min_heap *heap)
{
if (is_empty(heap)) {
return NULL;
}
struct min_heap_node *root_node = heap->array[0];
struct min_heap_node *last_node = heap->array[heap->size - 1];
heap->array[0] = last_node;
heap->position[root_node->vertex] = heap->size - 1;
heap->position[last_node->vertex] = 0;
--(heap)->size;
min_heapify(heap, 0);
return root_node;
}
int is_in_min_heap(struct min_heap *heap, int index)
{
if (heap->position[index] < heap->size) {
return 1;
} else {
return 0;
}
}
void delete_heap(struct min_heap *heap)
{
free(heap->array);
free(heap->position);
free(heap);
}
void decrease_key(struct min_heap *heap, int index, int distance)
{
int key = heap->position[index];
heap->array[key]->distance = distance;
while(key && heap->array[key]->distance < heap->array[(key - 1) / 2]->distance) {
heap->position[heap->array[key]->vertex] = (key - 1) / 2;
heap->position[heap->array[(key - 1) / 2]->vertex] = key;
swap_node(&heap->array[key], &heap->array[(key - 1) / 2]);
key = (key - 1) / 2;
}
}
void dijkstra(struct graph* graph, int src_vertex)
{
int vertices = graph->vertices;
struct min_heap *heap = create_heap(vertices);
int distance[vertices];
heap->size = vertices;
int parent[vertices];
parent[src_vertex] = src_vertex;
for(int i = 0; i < vertices; ++i) {
distance[i] = INT_MAX;
heap->array[i] = create_heap_node(i, INT_MAX);
heap->position[i] = i;
}
distance[src_vertex] = 0;
decrease_key(heap, src_vertex, distance[src_vertex]);
while(!is_empty(heap)) {
struct min_heap_node *min_node = extract_min_node(heap);
int u = min_node->vertex;
for (struct adj_list_node *cursor = graph->array[u].head; cursor; cursor = cursor->next) {
int v = cursor->vertex;
if(is_in_min_heap(heap,v) && distance[u]!=INT_MAX && distance[u] + cursor->weight < distance[v]) {
distance[v] = cursor->weight + distance[u];
parent[v] = u;
decrease_key(heap, v, distance[v]);
}
}
}
print_array(distance, vertices, parent);
delete_heap(heap);
}
void print_path(int parent[], int vertex)
{
if (parent[vertex]==vertex) {
return;
}
print_path(parent, parent[vertex]);
printf("%d->", parent[vertex]);
}
void print_array(int cost[], int vertices,int parent[])
{
printf("\nvertex\t\tcost\t\tpath\n");
for(int i = 0; i < vertices ; ++i) {
printf("%d\t\t\t%d\t\t\t", i, cost[i]);
print_path(parent, i);
printf("%d\n", i);
}
}
/**
* 6
* 0-------------1
* | /|\
* | / | \
* | / | \5
* | / | \
* | / | \
* | / | \
* 1| 2/ 2| 2
* | / | /
* | / | /
* | / | /5
* | / | /
* | / | /
* |/ |/
* 3-------------4
* 1
*/
int main()
{
int total_vertex = 5;
struct graph* graph = create_graph(total_vertex);
add_edge(graph, 0, 1, 6);
add_edge(graph, 0, 3, 1);
add_edge(graph, 1, 0, 6);
add_edge(graph, 1, 3, 2);
add_edge(graph, 1, 4, 2);
add_edge(graph, 1, 2, 5);
add_edge(graph, 2, 1, 5);
add_edge(graph, 2, 4, 5);
add_edge(graph, 3, 0, 1);
add_edge(graph, 3, 1, 2);
add_edge(graph, 3, 4, 1);
add_edge(graph, 4, 3, 1);
add_edge(graph, 4, 1, 2);
add_edge(graph, 4, 2, 5);
dijkstra(graph,0);
free_graph(graph);
free(graph);
return 0;
}
/**
* Output
* vertex cost path
* 0 0 0
* 1 3 0->3->1
* 2 7 0->3->4->2
* 3 1 0->3
* 4 2 0->3->4
*/
Valgrind says the leaked memory was allocated by create_heap_node meaning you didn't free some heap nodes. How do we find this?
Every malloc needs a free. It's easier to check this if every create function has a matching free function (and to use a consistent naming scheme).
create_heap_node
missing
create_heap
delete_heap (should be free_heap)
create_adj_node
free_nodes (should be free_adj_nodes)
create_graph
free_graph
calls free_nodes
does not free the graph (you free it manually, but this is a memory leak waiting to happen)
At a glance, you're missing free_heap_node.
void delete_heap(struct min_heap *heap)
{
free(heap->array); // potential memory leak
free(heap->position);
free(heap);
}
Perhaps something else is freeing those nodes, but delete_heap should not assume that. There's a potential memory leak.
dijkstra is the only function using delete_heap. dijkstra assumes the heap is empty when it calls delete heap, which it is. However, dijkstra extracts nodes but it never frees them.
while(!is_empty(heap)) {
struct min_heap_node *min_node = extract_min_node(heap);
// min_node is removed from heap but never freed.
// memory leak.
// needs free_heap_node(min_node)
}
delete_heap(heap);
free_nodes should be free_adj_nodes. You could add free_adj_node for completeness which would make free_nodes simpler.
// free itself, return the next node
struct adj_list_node *free_adj_node(struct adj_list_node *node) {
struct adj_list_node *next = node->next;
free(node);
return next;
}
void free_adj_nodes(struct adj_list_node *node)
{
// No need to check if node is null.
// If it is, the loop will simply not run.
// Free nodes until the next node is null.
while (node) {
node = free_adj_node(node);
}
}
I'm implementing a graph traversal breadth-first search that I found here. However, their implementation involves integers and without any linked list. I was playing around with it a little bit I have no luck in getting any results because it doesn't seem to work as intended.
This is the code that I currently have:
(main.c)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct s_list
{
struct s_list *next;
void *content;
} t_list;
typedef struct s_queue
{
t_list *first;
t_list *last;
} t_queue;
typedef struct s_node
{
struct s_node *next;
int vertex;
} t_node;
typedef struct s_graph
{
t_node **adj_lists;
int *visited;
int total_vertices;
} t_graph;
/*Graph functions*/
t_node *create_node(int vertex);
t_graph *create_graph(int vertices);
void add_edge(t_graph *graph, int src, int dst);
void bfs(t_graph *graph, int start_vertex);
/*Misc functions*/
void my_putstr(char *str);
void *my_memalloc(size_t size);
void *my_memset(void *ptr, int value, size_t num);
void my_bzero(void *s, size_t n);
/*Queue functions*/
t_queue *init_queue(void);
void enqueue(t_queue *queue, void *content);
void *dequeue(t_queue *queue);
void *peek_queue(t_queue *queue);
int is_empty(t_queue *queue);
void my_print_queue(t_queue *queue);
t_node *create_node(int val)
{
t_node *new_node;
new_node = (t_node*)my_memalloc(sizeof(t_node));
new_node->vertex = val;
new_node->next = NULL;
return (new_node);
}
t_graph *create_graph(int vertices)
{
int i;
t_graph *graph;
i = 0;
graph = my_memalloc(sizeof(t_graph));
graph->total_vertices = vertices;
printf("graph->total_vertices: %d\n", vertices);
graph->adj_lists = (t_node**)my_memalloc(sizeof(t_node));
graph->visited = my_memalloc(sizeof(int) * vertices);
while (i < vertices)
{
graph->adj_lists[i] = NULL;
graph->visited[i] = 0;
i++;
}
return (graph);
}
void add_edge(t_graph *graph, int src, int dst)
{
t_node *new_node;
new_node = create_node(dst);
new_node->next = graph->adj_lists[src];
graph->adj_lists[src] = new_node;
new_node = create_node(src);
new_node->next = graph->adj_lists[dst];
graph->adj_lists[dst] = new_node;
}
void bfs(t_graph *graph, int start_vertex)
{
t_queue *queue;
queue = init_queue();
graph->visited[start_vertex] = 1;
printf("start_vertex before enqueue %d\n", start_vertex);
my_print_queue(queue);
enqueue(queue, &start_vertex);
printf("start_vertex after enqueue %d\n", start_vertex);
while (!is_empty(queue))
{
my_print_queue(queue);
int current_vertex;
t_node *tmp;
current_vertex = (int)dequeue(queue);
printf("Visited %d nodes\n", current_vertex);
tmp = graph->adj_lists[current_vertex];
while (tmp)
{
int adj_vertex;
adj_vertex = tmp->vertex;
if (graph->visited[adj_vertex] == 0)
{
graph->visited[adj_vertex] = 1;
printf("%d\n", graph->visited[adj_vertex]);
enqueue(queue, &adj_vertex);
my_print_queue(queue);
}
tmp = tmp->next;
}
}
}
t_queue *init_queue(void)
{
t_queue *node;
node = (t_queue *)my_memalloc(sizeof(t_queue));
node->first = NULL;
node->last = NULL;
return (node);
}
void enqueue(t_queue *queue, void *content)
{
t_list *node;
node = (t_list *)my_memalloc(sizeof(t_list));
node->content = content;
node->next = NULL;
if (!queue->last)
{
queue->last = node;
queue->first = node;
}
else
{
queue->last->next = node;
queue->last = queue->last->next;
}
return ;
}
void *dequeue(t_queue *queue)
{
t_list *tmp;
tmp = queue->first;
if (!tmp)
return (NULL);
else
{
queue->first = tmp->next;
return (tmp->content);
}
}
void *peek_queue(t_queue *queue)
{
if (queue->first == NULL)
return (NULL);
return (queue->first->content);
}
int is_empty(t_queue *queue)
{
return (queue->first == NULL);
}
void my_print_queue(t_queue *queue)
{
if (is_empty(queue))
my_putstr("Empty queue\n");
else
{
while (!is_empty(queue))
{
int val = *(int *)queue->first->content;
printf("%d \n", val);
dequeue(queue);
}
}
}
void my_putstr(char *str)
{
int i;
i = 0;
while (str[i])
write(1, &str[i++], 1);
}
void *my_memalloc(size_t size)
{
char *str;
str = ((void*)malloc(size));
if (!str)
return (NULL);
my_bzero(str, size);
return (str);
}
void *my_memset(void *ptr, int value, size_t num)
{
unsigned char *uptr;
uptr = (unsigned char*)ptr;
while (num--)
*uptr++ = (unsigned char)value;
return (ptr);
}
void my_bzero(void *s, size_t n)
{
my_memset(s, 0, n);
}
int main(void)
{
t_graph *graph;
graph = create_graph(3);
add_edge(graph, 0, 1);
add_edge(graph, 0, 2);
add_edge(graph, 2, 4);
bfs(graph, 2);
return (0);
}
I did some research like type-casting a void pointer to make it into a char or int, or any other data type. What happens is that the create graph does it's creation after calling it; but, when it comes to the bfs, it doesn't show the correct output after. It never prints the visited vertices. I'm getting a result of
graph->total_vertices: 3
start_vertex before enqueue 2
Empty queue
start_vertex after enqueue 2
2
Visited 0 nodes
The expected output should be something like this:
Queue contains
0 Resetting queueVisited 0
Queue contains
2 1 Visited 2
Queue contains
1 4 Visited 1
Queue contains
4 Resetting queueVisited 4
I've been trying to figure out by myself to the point that I'm burning out. What am I doing wrong in here?
While posting this, I will keep debugging on my side and see what it does with a couple print statements.
I can point out the following mistakes:
my_print_queue destroys your queue. So anything after it's call works with empty queue.
You don't fill visited with to zeroes. By default their values is pretty much arbitrary. Since you compare their values with 0, it makes sense that comparison fails.
I am trying to build a multi-way tree in C. I've got stuck on allocation memory for childrens.
I have a vector which contains the fathers of each node. Here is my code:
#define MAX_CHILDS 10
int t[10] = {1, 2, 4, 1, -1, 3, 2, 1, 0, 4};
NODE *root;
NODE *v[MAX_CHILDS];
//add children for specified node
void ADD_REF(int i) {
v[i]->children[v[i]->child_count] = v[t[i]];
v[i]->child_count++;
}
//creates the tree
NODE *T1(int n, int *t) {
int root = 0;
for (int i = 0; i < n; i++) {
v[i] = (NODE *) malloc(sizeof(NODE));
v[i]->info = i;
v[i]->child_count = 0;
v[i]->children = (NODE **) malloc(sizeof(NODE)); // I think the problem is here
}
for (int i = 0; i<n; i++) {
if (t[i] == -1)
root = i;
else
ADD_REF(i);
}
return v[root];
}
void main() {
root = T1(MAX_CHILDS, t);
print_tree(root, 0); // prints the tree
}
Here is the structure of the NODE:
typedef struct NODE {
int info;
int child_count;
struct NODE **children;
} NODE;
I am not sure exactly if the problem is at the memory allocation. With my logic it should work.
I've found my error.
The memory allocation was ok. The problem was at adding new children.
I've added children for the current node instead of adding children to it's parent.
This was the solve:
void ADD_REF(int i) {
v[t[i]]->children[v[t[i]]->child_count] = v[i];
v[t[i]]->child_count++;
}
I am trying to implement a graph and perform DFS in C. but the dfs operation causes the bug that w gets allocated a random value once the pointer x runs off the queue of adjacent nodes. The condition !=NULL doesnt seem to do anything. I want it to break as soon as the queue empties, how to achieve this?
Also I wanted to know, how to implement a runtime version of the number of nodes? I believe that C does not support dynamic instance of arrays. Should I declare a very large array and use that?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
struct node {
int data;
struct node* next;
};
void add(struct node **bag, int data) {
struct node *newnode = malloc(sizeof(struct node));
newnode->data = data;
newnode->next = *bag;
*bag = newnode;
}
int V;
struct node *adj[7];
bool marked[7];
int edgeTo[7 * 6];
void initialize() {
int i = 0;
for (i = 0; i < 7; ++i) {
adj[i] = malloc(sizeof(struct node));
marked[i] = false;
}
}
void addEdge(int v, int w) {
add(&adj[v], w);
add(&adj[w], v);
}
void dfs(int v) {
printf("%d ", v);
marked[v] = true;
struct node *x = adj[v];
while (x != NULL) {
int w = x->data;
if (marked[w] == false) {
dfs(w);
}
x = x->next;
}
}
int main(int argc, char **argv) {
initialize();
addEdge(0, 1);
addEdge(0, 2);
addEdge(0, 5);
addEdge(1, 4);
addEdge(3, 2);
addEdge(3, 4);
addEdge(3, 5);
addEdge(3, 6);
addEdge(5, 2);
addEdge(6, 0);
addEdge(6, 4);
dfs(0);
printf("done");
return 0;
}
You haven't coded your initialize method correctly. Make sure you initialize your next to null adj[i]->next = NULL;
void initialize() {
int i = 0;
for (i = 0; i < 7; ++i) {
adj[i] = (node*)malloc(sizeof(struct node));
marked[i] = false;
adj[i]->data = 0;
adj[i]->next = NULL;
}
}