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;
}
}
Related
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);
}
}
Basically I made a create_app() function to allocate 2 nodes in the stack, each having a pointer to an array[max]; undo() pops the last element, and before returning it, it adds it into the REDO node's array. redo() does the opposite, pops the last element in it's array, putting it into Undo's array before returning it. What did I do wrong ?
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define EMPTY_TOS (-1)
typedef struct node *node_ptr;
struct node
{
int arr_size;
int tos;
int *arr_stack;
node_ptr next;
};
typedef node_ptr STACK;
STACK
create_app(int max)
{
STACK UNDO = (STACK) malloc(sizeof(struct node));
STACK REDO = (STACK) malloc(sizeof(struct node));
{
UNDO->arr_stack == (int *) malloc(max * sizeof(int));
REDO->arr_stack == (int *) malloc(max * sizeof(int));
if(UNDO->arr_stack != NULL){printf("Out of space!");}
else
{
UNDO->tos = EMPTY_TOS;
REDO->tos = EMPTY_TOS;
UNDO->arr_size = max;
REDO->arr_size = max;
UNDO->next = REDO;
REDO->next = UNDO;
return UNDO;
}
}
}
int
isEmpty(STACK S)
{
return(S->tos==-1);
}
int
isFull(STACK S)
{
return(S->tos>=S->arr_size-1);
}
void
push(int x, STACK S)
{
if(isFull(S)){printf("Stack full!");}
else
{
S->arr_stack[++S->tos] = x;
}
}
int
undo(STACK S)
{
if(isEmpty(S)){printf("Nothing to undo!");}
else
{
S->next->arr_stack[++S->next->tos] = S->arr_stack[S->tos];
printf("%d",S->arr_stack[S->tos--]);
}
}
int
redo(STACK S)
{
if(isEmpty(S->next)){printf("Nothing to redo!");}
else
{
int temp = S->next->arr_stack[S->next->tos];
push(S->next->arr_stack[S->next->tos], S);
S->next->tos--;
printf("%d",temp);
}
}
int main()
{
STACK app = create_app(5);
push(1,app);
push(2,app);
push(3,app);
undo(app);
undo(app);
redo(app);
redo(app);
/* Expected output: 3223 */
return 0;
}
Some small errors were in your code, like these ones in create_app() which seem like typos.
UNDO->arr_stack == (int *) malloc(max * sizeof(int));
REDO->arr_stack == (int *) malloc(max * sizeof(int));
^
|
if(UNDO->arr_stack != NULL){printf("Out of space!");}
^
|
...
and some int returning functions did not return anything in the else part which gave some warnings.
Here is the modified code, which worked fine for me
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define EMPTY_TOS (-1)
typedef struct node* node_ptr;
struct node
{
int arr_size;
int tos;
int *arr_stack;
node_ptr next;
};
typedef node_ptr STACK;
STACK
create_app(int max)
{
STACK UNDO = (STACK) malloc(sizeof(struct node));
STACK REDO = (STACK) malloc(sizeof(struct node));
{
UNDO->arr_stack = (int *) malloc(max * sizeof(int));
REDO->arr_stack = (int *) malloc(max * sizeof(int));
if(UNDO->arr_stack == NULL){printf("Out of space!");
return NULL;}
else
{
UNDO->tos = EMPTY_TOS;
REDO->tos = EMPTY_TOS;
UNDO->arr_size = max;
REDO->arr_size = max;
UNDO->next = REDO;
REDO->next = UNDO;
return UNDO;
}
}
}
int
isEmpty(STACK S)
{
return (S->tos == -1);
}
int
isFull(STACK S)
{
return (S->tos >= S->arr_size-1);
}
void
push(int x, STACK S)
{
if(isFull(S)){printf("Stack full!");}
else
{
S->arr_stack[++S->tos] = x;
}
}
void
undo(STACK S)
{
if(isEmpty(S)){printf("Nothing to undo!");}
else
{
S->next->arr_stack[++S->next->tos] = S->arr_stack[S->tos];
printf("%d",S->arr_stack[S->tos--]);
}
}
void
redo(STACK S)
{
if(isEmpty(S->next)){printf("Nothing to redo!");}
else
{
int temp = S->next->arr_stack[S->next->tos];
push(S->next->arr_stack[S->next->tos], S);
S->next->tos--;
printf("%d",temp);
}
}
int main()
{
STACK app = create_app(5);
push(1,app);
push(2,app);
push(3,app);
undo(app);
undo(app);
redo(app);
redo(app);
/* Expected output: 3223 */
return 0;
}
Result:
3223
However, always take precaution in deallocating the memory malloced using free().
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;
}
I've been trying to write up a simple AVL Tree implementation in C. It supports duplicate values as well. Everything seems to work fine but every now and then I get a poorly balanced tree. To me, the rotation functions seem to be working fine like they should. I'm thinking there is a problem with the height checks but I can't seem to find the problem.
The tree I get just from the inserts is unbalanced, so the insert is problematic. Then, before this, after deletion the tree is usually poorly balanced. It is sometimes balanced properly though, which I can't seem to identify how.
The code for this implementation is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#define SPACE_PER_NODE 2
#define MAX(x, y) (x) > (y) ? (x) : (y)
enum delete_flags {
DELETE_NO_FORCE,
DELETE_FORCE
};
typedef unsigned int uint;
struct tree_elem {
int data;
uint dup_count;
int height;
struct tree_elem* left;
struct tree_elem* right;
};
typedef struct tree_elem node;
node* create_bst();
void insert(node**, int);
void delete_elem(node**, int, uint);
node* search(node*, int);
node* get_parent(node*, node*);
node* find_min(node*);
node* get_successor(node*, node*);
uint max_depth(node*);
void display_helper(node*, int);
void display_tree(node*);
int get_height(node*);
void rotate_once_left(node**);
void rotate_once_right(node**);
void rotate_twice_left(node**);
void rotate_twice_right(node**);
void* s_malloc (const uint t) {
void* p = malloc(t);
if(!p) {
printf("Out of memory.\n");
exit(EXIT_FAILURE);
}
return p;
}
void s_free (void* p) {
if(!p) {
printf("Error: Tried to free NULL ptr.\n");
exit(EXIT_FAILURE);
}
else
free(p);
}
node* create_bst(int data) {
node* tree = (node*) s_malloc(sizeof(node));
tree->left = tree->right = NULL;
tree->data = data;
return tree;
}
void insert(node** t, int val) {
if(!(*t)) {
*t = (node*) s_malloc(sizeof(node));
(*t)->data = val;
(*t)->left = (*t)->right = NULL;
(*t)->dup_count = 0;
(*t)->height = 0;
return;
}
if((*t)->data < val) {
insert(&(*t)->right, val);
if(get_height((*t)->right) - get_height((*t)->left) >= 2) {
if((*t)->right->data < val)
rotate_once_right(&(*t));
else if((*t)->right->data > val)
rotate_twice_right(&(*t));
}
}
else if((*t)->data > val) {
insert(&(*t)->left, val);
if(get_height((*t)->left) - get_height((*t)->right) >= 2) {
if((*t)->left->data > val)
rotate_once_left(&(*t));
else if((*t)->left->data < val)
rotate_twice_left(&(*t));
}
}
else {
++(*t)->dup_count;
return; // this is important! if there are duplicates, they might cause an unwanted height change!
}
(*t)->height = MAX(get_height((*t)->left), get_height((*t)->right)) + 1;
}
node* get_successor(node* t, node* s) {
if(s->right)
return find_min(s->right);
node* suc = NULL;
node* temp = t;
// Start from root and search for successor in the tree
while (temp) {
if (s->data < temp->data) {
suc = temp;
temp = temp->left;
}
else if (s->data > temp->data)
temp = temp->right;
else
break;
}
return suc;
}
void free_tree (node* t) {
if (!t)
return;
free_tree(t->left);
free_tree(t->right);
free(t);
}
node* search(node* t, int val) {
if(!t)
return NULL;
if(t->data == val)
return t;
else if(t->data < val)
return search(t->right, val);
return search(t->left, val);
}
node* find_min(node* t) {
node* temp = t;
while(temp->left)
temp = temp->left;
return temp;
}
uint max_depth(node* t) {
if (!t)
return 0;
int ldepth = max_depth(t->left);
int rdepth = max_depth(t->right);
if (ldepth > rdepth)
return ldepth + 1;
return rdepth + 1;
}
void display_helper(node* t, int spaces) {
int width = ceil(log10(max_depth(t)+0.01)) + 2;
wchar_t* sp64 = L" ";
if (!t) {
wprintf(L"\n");
return;
}
display_helper(t->right, spaces + width);
wprintf(L"%*.*s%d\n", 0, spaces, sp64, t->data);
display_helper(t->left, spaces + width);
}
void display_tree(node* t) {
if(t)
display_helper(t, SPACE_PER_NODE);
}
int get_height(node* t) {
if(!t)
return 0;
return t->height;
}
void rotate_once_left(node** k1) {
node* temp = (*k1)->left;
(*k1)->left = temp->right;
temp->right = *k1;
(*k1)->height = MAX(get_height((*k1)->left), get_height((*k1)->right)) + 1;
temp->height = MAX(get_height(temp->left), (*k1)->height) + 1;
*k1 = temp;
}
void rotate_once_right(node** k1) {
node* temp = (*k1)->right;
(*k1)->right = temp->left;
temp->left = *k1;
(*k1)->height = MAX(get_height((*k1)->left), get_height((*k1)->right)) + 1;
temp->height = MAX(get_height(temp->right), (*k1)->height) + 1;
*k1 = temp;
}
void rotate_twice_left(node** k1) {
rotate_once_right(&(*k1)->left);
rotate_once_left(k1);
}
void rotate_twice_right(node** k1) {
rotate_once_left(&(*k1)->right);
rotate_once_right(k1);
}
int main() {
srand(time(NULL));
node* tree = create_bst(rand() % 15 + 1);
for(uint i = 0; i < 14; ++i) {
int elem;
// create unique elements from 1 to 20.
do {
elem = rand() % 15 + 1;
} while (search(tree, elem));
insert(&tree, elem);
}
display_tree(tree);
int input;
do {
printf("Enter value to delete: ");
scanf("%d", &input);
delete_elem(&tree, input, DELETE_NO_FORCE);
display_tree(tree);
} while(input != -1);
return 0;
}
One place to look is your MAX macro.
MAX(get_height((*t)->left), get_height((*t)->right)) + 1;
probably does not compute what you think it does.
In this day and age, when compilers inline with such great aplomb, you shouldn't use a macro for this computation. It's not only incorrect, it's almost certainly less efficient.
And I'll ditto here what I said in the comment: You should strongly consider test driven development. Write a predicate that checks the AVL conditions are met for a given tree, including that it's a valid BST. Now add items to an empty tree and run the predicate after each. When it reports the tree is not AVL, you'll be able to see what went wrong. When it doesn't, you'll have more confidence your code is working as intended.
Edit
Okay, expand the macro by hand (adding some whitespace):
(get_height((*t)->left)) > (get_height((*t)->right))
? (get_height((*t)->left))
: (get_height((*t)->right)) + 1;
The + 1 is affecting only the else branch. You'd need an additional set of parentheses to get the right answer.
Moreover, the heights are being computed twice. With a function, it would only happen once. Admittedly an aggressive optimizer would probably eliminate the duplicate computations, too, but that optimization is considerably more elaborate and therefore fragile than merely inlining a max() function. Why use a macro to make the compiler's job harder?
This code fills a tree with values based on their depths. But when traversing the tree, I cannot manage to determine the actual number of children without iterating over the parent node. This is necessary because the subleafs are stored in in the node underneath the current one. Which conceptual changes are necessary to store the leafs directly within the current node?
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef NULL
#define NULL ((void *) 0)
#endif
// ----
typedef struct _Tree_Node {
// data ptr
void *p;
// number of nodes
int cnt;
struct _Tree_Node **nodes;
// parent nodes
struct _Tree_Node *parent;
} Tree_Node;
typedef struct {
Tree_Node root;
} Tree;
void Tree_Init(Tree *this) {
this->root.p = NULL;
this->root.cnt = 0;
this->root.nodes = NULL;
this->root.parent = NULL;
}
Tree_Node* Tree_AddNode(Tree_Node *node) {
if (node->cnt == 0) {
node->nodes = malloc(sizeof(Tree_Node *));
} else {
node->nodes = realloc(
node->nodes,
(node->cnt + 1) * sizeof(Tree_Node *)
);
}
Tree_Node *res
= node->nodes[node->cnt]
= malloc(sizeof(Tree_Node));
res->p = NULL;
res->cnt = 0;
res->nodes = NULL;
res->parent = node;
node->cnt++;
return res;
}
// ----
void handleNode(Tree_Node *node, int depth) {
int j = depth;
printf("\n");
while (j--) {
printf(" ");
}
printf("depth=%d ", depth);
if (node->p == NULL) {
goto out;
}
int cnt = 0;
for (int i = 0; i < node->parent->cnt - 1; i++) {
if (node->parent->nodes[i] == node) {
cnt = node->parent->nodes[i + 1]->cnt;
}
}
printf("value=%s cnt=%i", node->p, cnt);
out:
for (int i = 0; i < node->cnt; i++) {
handleNode(node->nodes[i], depth + 1);
}
}
Tree tree;
int curdepth;
Tree_Node *curnode;
void add(int depth, char *s) {
printf("%s: depth (%d) > curdepth (%d): %d\n", s, depth, curdepth, depth > curdepth);
if (depth > curdepth) {
curnode = Tree_AddNode(curnode);
Tree_Node *node = Tree_AddNode(curnode);
node->p = malloc(strlen(s) + 1);
memcpy(node->p, s, strlen(s) + 1);
curdepth++;
} else {
while (curdepth - depth > 0) {
if (curnode->parent == NULL) {
printf("Illegal nesting\n");
return;
}
curnode = curnode->parent;
curdepth--;
}
Tree_Node *node = Tree_AddNode(curnode);
node->p = malloc(strlen(s) + 1);
memcpy(node->p, s, strlen(s) + 1);
}
}
void main(void) {
Tree_Init(&tree);
curnode = &tree.root;
curdepth = 0;
add(0, "1");
add(1, "1.1");
add(2, "1.1.1");
add(3, "1.1.1.1");
add(4, "1.1.1.1.1");
add(4, "1.1.1.1.2");
add(4, "1.1.1.1.3");
add(4, "1.1.1.1.4");
add(2, "1.1.2");
add(0, "2");
handleNode(&tree.root, 0);
}
I see two problems in you program
1) When you "realloc" the node list, you actually move in memory the node objects, so the parent pointer in their children must me updated as well. I suggest you to transform the array of nodes into an array of pointers to nodes, so you can realloc it without correcting pointers.
2) You forgot to terminate strings:
node->p = malloc(strlen(s));
memcpy(node->p, s, strlen(s));
should be:
node->p = malloc(strlen(s)+1);
memcpy(node->p, s, strlen(s)+1);
or also simply
node->p = strdup(s);
Maybe there are other issues, but I strongly suggest to correct these ones first.
I hope it may help you
Regards
If your structure is truly a tree, then the following pseudo code for recursively counting nodes may help:
def total_number_of_leaf_nodes(node):
if node does not have children:
return 1
else:
sum = 0
for each child of node:
sum += total_number_of_leaf_nodes(child)
return sum
If it is at all possible for you to use C++, then I would strongly advise it. Being able to use an std::vector or std::list to store your child nodes and being able to make the data element have a template type would greatly simplify the complexity of your code.