Min Heap Problem After Extracting Minimum Element - c

I'm working on a min heap implementation and am really new to the concept.
Using this as reference:
https://www.geeksforgeeks.org/building-heap-from-array/
https://algorithmtutor.com/Data-Structures/Tree/Binary-Heaps/
I modified the code and came up with:
(this is the code I'm having problems with, all other code is irrelevant to my problem, at least so I think)
#define LCHILD(x) (2 * (x)) + 1
#define RCHILD(x) (2 * (x)) + 2
#define PARENT(x) ((x) - 1) / 2
typedef struct {
int key;
Event *element; // Assume NULL for this example
} Node;
void swap(Node **x, Node **y) {
Node *temp = *x;
*x = *y;
*y = temp;
}
void heapify(void *pq, int n, int i) {
Node **node = (Node**) pq;
int smallest = i; // Initialize smallest as root
int left = LCHILD(i);
int right = RCHILD(i); // right = 2*i + 2
if (left < n && (node[left])->key < (node[smallest ])->key)
smallest = left;
if (right < n && (node[right])->key < (node[smallest ])->key)
smallest = right;
if (smallest != i) {
swap(&node[i], &node[smallest ]);
heapify(node, n, smallest );
}
}
int extractKey(void *pq, int *n) {
Node **node = (Node**) pq;
int minElement = (node[0])->key;
node[0] = node[*n - 1];
*n = *n - 1;
heapify(pq, *n, 0);
return minElement;
}
void insert(void *pq, int key, void *element, int *n) {
Node **node = (Node**) pq;
node[*n]->key = key;
node[*n]->element = element;
*n = *n + 1;
int i = *n - 1;
while ( (i != 0) && (node[PARENT(i)]->key > node[i]->key) ) {
swap(&node[PARENT(i)], &node[i]);
i = PARENT(i);
}
}
int main() {
Node **pq = malloc (100 * sizeof(Node*));
int i;
for(i = 0; i < 100; i++) {
pq[i] = malloc(sizeof(Node));
pq[i]->element = malloc(sizeof(Event));
}
int n = 0; // heap size
insert(pq, 0, NULL, &n);
printHeap(pq, n);
insert(pq, 5, NULL, &n);
printHeap(pq, n);
insert(pq, 1, NULL, &n);
printHeap(pq, n);
insert(pq, 50, NULL, &n);
printHeap(pq, n);
extractKey(pq, &n);
printHeap(pq, n);
insert(pq, 10, NULL, &n);
printHeap(pq, n);
return 0;
}
OUTPUT:
Array representation of heap is:
0
Array representation of heap is:
0 5
Array representation of heap is:
0 5 1
Array representation of heap is:
0 5 1 50
Array representation of heap is:
1 5 50
Array representation of heap is:
1 5 10 10 // What happened here?
This only happens when I extract the minimum node and then add a new one. If I don't extract a node, then it works perfectly fine. Am I missing something?
EDIT 1: This is the print function I'm using. Forgot to add it in the initial post (It's a modified version from the one found here:
https://algorithmtutor.com/Data-Structures/Tree/Binary-Heaps/)
void printHeap(void *pq, int n) {
Node **node = (Node**) pq;
printf("Array representation of heap is:\n");
for (int i = 0; i < n; ++i) {
printf("%d ", node[i]->key);
}
printf("\n");
}
EDIT 2: I did some more testing. Here's what I got:
Inserted some print statements:
void insert(void *pq, int key, void *element, int *n) {
Node **node = (Node**) pq;
if(*n > 0) {
printf("node[%d] = %d\n", *n-1, node[*n-1]->key);
}
node[*n]->key = key;
printf("node[%d] = %d\n", *n, node[*n]->key);
if(*n > 0) {
printf("node[%d] = %d\n", *n-1, node[*n-1]->key);
}
node[*n]->element = element;
*n = *n + 1;
// move up until the heap property satisfies
int i = *n - 1;
while ( (i != 0) && (node[PARENT(i)]->key > node[i]->key) ) {
swap(&node[PARENT(i)], &node[i]);
i = PARENT(i);
}
}
OUTPUT:
node[0] = 0
Array representation of heap is:
0
node[0] = 0
node[1] = 5
node[0] = 0
Array representation of heap is:
0 5
node[1] = 5
node[2] = 1
node[1] = 5
Array representation of heap is:
0 5 1
node[2] = 1
node[3] = 50
node[2] = 1
Array representation of heap is:
0 5 1 50
Array representation of heap is:
1 5 50
node[2] = 50
node[3] = 10
node[2] = 10 // Huh? it should be 50
Array representation of heap is:
1 5 10 10

The problem is the line node[0] = node[*n - 1]; in extractKey. That is setting two of your node pointers to the same value, so you no longer have 100 unique node pointers. (As a consequence, it is also leaking memory.) Changing the line to swap(&node[0], &node[*n - 1]); should solve the problem.

Related

Memory Limit exceedeed. For the Dijkstra algorithm based on the binary heap

trying to implement a Dijkstra algorithm for my homework.
Faced the "Memory Limit exceedeed" error.
Please tell me what I'm doing wrong.
Memory limit: 8 Mb
Statement You are to write a program that receives a weighted directed graph and finds all distances from fixed vertex S to all
other vertices. Distance from S to some vertex W is the minimal length
of path going from S to W. Length of path is the sum of weights of its
arcs.
Input file contains two integers N, M and S. Vertices are numbered
with integer numbers from 1 to N. S is the number of source vertex. M
is the number of arcs. Each of next M lines contain three integers —
numbers of starting and ending vertices of some arc and its weight
respectively. All weights are positive. There is at most one arc
connecting two vertices in every direction.
Output file must contain N numbers. Each I-th number is the distance
from vertex S to vertex I. If some vertices are not reachable from S,
corresponding numbers must be −1.
Constraints 1 ≤ N, M ≤ 100000 All weights are less or equal 1000.
Sample test:
5 3 1
1 2 5
1 3 7
3 4 10
Out: 0 5 7 17 -1
My programm:
#include <stdio.h>
#include <stdlib.h>
#define INF 100001
typedef enum {max, min} Heap_type;
typedef struct {
Heap_type type;
int *data, size;
} Heap;
Heap init_heap(Heap_type type, int size){
Heap * heap = (Heap*)malloc(sizeof(Heap));
if (heap!=NULL)
{
heap->data = (int *) malloc(size * sizeof(int));
heap->type = type;
heap->size = 0;
}
return *heap;
}
void swap(int *a, int *b){
int tmp = *a;
*a = *b;
*b = tmp;
}
void sift_up(Heap *heap, int id){
heap->size++;
while(heap->type == max ? (heap->data[id] > heap->data[(id - 1) / 2]) : (heap->data[id] < heap->data[(id - 1) / 2])){
swap(&(heap->data[id]), &(heap->data[(id - 1) / 2]));
id = (id - 1) / 2;
}
}
void sift_down(Heap *heap, int id){
int child_l, child_r, child_tmp;
while(2 * id + 1 < heap->size){
child_l = 2 * id + 1;
child_r = 2 * id + 2;
child_tmp = child_l;
if(child_r < heap->size)
if(heap->type == max ? heap->data[child_r] > heap->data[child_l] : heap->data[child_r] < heap->data[child_l])
child_tmp = child_r;
if(heap->type == max ? heap->data[id] >= heap->data[child_tmp] : heap->data[id] <= heap->data[child_tmp])
break;
swap(&(heap->data[id]), &(heap->data[child_tmp]));
id = child_tmp;
}
}
void push(Heap *heap, int num){
heap->data[heap->size] = num;
sift_up(heap, heap->size);
}
int get_root(Heap *heap){
int root = heap->data[0];
heap->size--;
heap->data[0] = heap->data[heap->size];
sift_down(heap, 0);
return root;
}
void fast_dijkstra(int s, int *d, int n, int m, int **W, Heap pq){
for (int i = 0; i<n; i++)
d[i] = INF;
d[s] = 0;
push(&pq, s);
while (pq.size){
int v = get_root(&pq);
for(int u = 0; u<n; ++u) {
if (W[v][u] && (d[v] + W[v][u]) < d[u]) {
d[u] = d[v] + W[v][u];
push(&pq, u);
}
}
}
}
int main() {
FILE *inp = fopen("input.txt", "r"),
*out = fopen("output.txt", "w");
int N, M, S;
fscanf(inp, "%d %d %d", &N, &M, &S);
S -= 1;
int **W = (int **)malloc(N*sizeof(int *));
for(int i = 0; i < N; i++) {
W[i] = (int *)calloc(N, sizeof(int));
}
for (int _=M; _; _--){
int from, to, path;
fscanf(inp,"%d %d %d", &from, &to, &path);
W[from - 1][to - 1] = path;
}
Heap pq = init_heap(min,N);
int d[N];
fast_dijkstra(S, d, N, M, W, pq);
for (int i = 0; i<N; ++i)
fprintf(out, "%d ", d[i] != INF ? d[i] : -1);
return 0;
}

How to fix setting ending node in a linked list created by malloc causes a segmentation fault?

I am learning dynamic memory management and am working on a program that lets you set the size of the array, and then generates it, and prints it out.
here is the code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int number;
struct node *next;
}node;
int main(void)
{
node *ptr;
int n, i;
printf("How big should the array initially be? ");
//scanf("%i",&n);
printf("\n\n");
// for debugging purposes
n = 8;
ptr = (node *)malloc(n * sizeof(node));
for (i = 0; i < n; i++)
{
ptr[i] = (struct node)
{
.number = i + 1,
.next = &ptr[i + 1]
};
}
struct node *listptr = &ptr[0];
ptr[n - 1].next = NULL;
/*while (listptr->next != NULL)
{
printf("ptr[%i].number = %i, ptr[%i].next->number = %i"
,i,ptr[i].number,i,ptr[i].next->number);
listptr = listptr->next;
i++;
}*/
for (i = 0; i < n; i++)
{
printf("ptr[%i].number = %i, ptr[%i].next->number = %i\n"
,i,ptr[i].number,i,ptr[i].next->number);
}
printf("How much bigger would you like this array to be? ");
printf("\n\n");
free(ptr);
}
I have tried changing malloc to calloc but I still get the same error. How do I set the ending node.next to NULL and terminate the program?
when I run the code I get this output:
How big should the array initially be?
ptr[0].number = 1, ptr[0].next->number = 2
ptr[1].number = 2, ptr[1].next->number = 3
ptr[2].number = 3, ptr[2].next->number = 4
ptr[3].number = 4, ptr[3].next->number = 5
ptr[4].number = 5, ptr[4].next->number = 6
ptr[5].number = 6, ptr[5].next->number = 7
ptr[6].number = 7, ptr[6].next->number = 8
zsh: segmentation fault ./file
In this for loop
for (i = 0; i < n; i++)
{
printf("ptr[%i].number = %i, ptr[%i].next->number = %i\n"
,i,ptr[i].number,i,ptr[i].next->number);
}
when i is equal tp n - 1 this expression ptr[i].next->number tries to access memory using the null pointer ptr[i].next.
Also in this for loop
for (i = 0; i < n; i++)
{
ptr[i] = (struct node)
{
.number = i + 1,
.next = &ptr[i + 1]
};
}
you have to write
for (i = 0; i < n; i++)
{
ptr[i] = (struct node)
{
.number = i + 1,
.next = i == n - 1 ? NULL : &ptr[i + 1]
};
}
first linked list today. This ones easy
printf(...........ptr[i].next->number);
For the last entry in the list ptr[i].next is NULL, so this fails
How to fix,
printf("ptr[%i].number = %i, ptr[%i].next->number = %i\n"
,i,ptr[i].number,i,(i == n-1)?0:ptr[i].next->number);
this prints 0 instead of crashing. Question is - what do you want to print for the last entry

transforming max-heap into min-heap with heapfy

I'm trying to heapfy a max-heap i've got into a min-heap. For some reason i'm not getting the result i expect.
i've built my max-heap and the array contents of it are showing as expected:
60 50 30 20 40 10
When trying heapfy the above array and transform it into a min-heap, the desired result is:
10 20 30 60 50 40
However, the result i'm getting is:
10 20 60 50 40 30
here are my functions:
struct _heap
{
int max; //array max
int pos; //current position
int* priority; //array gets initialized after.
};
typedef struct _heap heap_t;
void heapify_min(heap_t* h, int father)
{
int smallest = father;
int left = 2 * father + 1;
int right = 2 * father + 2;
if (left < h->pos && h->priority[left] < h->priority[smallest) {
smallest = left;
}
if (dir < h->pos && h->priority[right] < h->priority[smallest])
smallest = right;
if (smallest != father) {
swap(father,smallest,h->priority);
heapify_min(h,left);
}
}
void swap(int a, int b, int *v)
{
int f = v[a];
v[a] = v[b];
v[b] = f;
}
void build_heap(heap_t* h)
{
int n = h->pos;
int i2 = (n/2) -1;
int i;
for (i = i2;i>=0;i--) {
heapify_min(h,i);
}
}
Any insights would be really helpful.
Check your code against my (below is working code for min_heap).
There are 3 problems :
In heapify_min function when you calling function recursively you should use variable smallest not left.
operators of comparing values in MIN HEAP should be > (greater) instead of < (smaller)
Function build_heap is correct but that should be just very first rearrange of array. And after that first rearrange of array (first creation of max heap) you should swap first and last element in array. After that initial swap you continue with heapify function but every further creation of max heap, swapping values in sub-trees (during recursive calling) and swaping first element with last element is done in cycle until there is only one node left.
Here is code :
void heapify(int arr[], int n, int i)
{
int smallest = i;
int l = 2 * i + 1;
int r = 2 * i + 2;
// If left child is larger than root
if (l < n && arr[l] > arr[smallest])
smallest = l;
// If right child is larger than largest so far
if (r < n && arr[r] > arr[smallest])
smallest = r;
// If largest is not root
if (smallest != i) {
//swap
int backUp = arr[i];
arr[i] = arr[smallest];
arr[smallest] = backUp;
// Recursively call on heapify function
heapify(arr, n, smallest);
}
}
void heapSort(int arr[], int n)
{
// Build heap (rearrange array)
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
// One by one extract an element from heap
for (int i = n - 1; i > 0; i--) {
// Swap root node with last node in array (WARNING: last node don't have to be
necessarily smallest one)
int backUp = arr[0];
arr[0] = arr[i];
arr[i] = backUp;
// call max heapify on the reduced heap
heapify(arr, i, 0);
}
}
/* A utility function to print array of size n */
void printArray(int arr[], int n)
{
for (int i = 0; i < n; ++i)
printf("%d ", arr[i]);
printf("\n");
}

Prim's Algorithm in C producing incorrect output

I've been tasked with implementing Prim's algorithm to find the MCST using an adjacency matrix to represent the graph, and a struct to hold the MCST. The program takes in a file input, applies the algorithm and then outputs the minimum cost spanning tree. I got the program to take a file input and produce output, but the values I am getting are incorrect and look like dummy values to me.
My assumption is that the error occurs in either how I am storing the file input in my array, or in the algorithm itself. I've spent a good 12-15 hours troubleshooting this issue and am hoping someone can provide insight. The program is written in C and compiled with make in the format ./a6 <file>. I take and store the file input in my main() and then the methods are used in the order they are called. Below is an example my professor provided. The first line contains info about the vertices being entered and the remaining lines contain the actual data itself.
input:
6 10 0 <<--(size, edges, start)
0 1 16 <<--(from, to, weight)
0 5 21
0 4 19
1 2 5
1 3 6
1 5 11
2 3 10
3 4 18
3 5 14
4 5 33
output:
0 1 16 <<--(first edge)
1 2 5
1 3 6
1 5 11
3 4 18
total cost: 56
My code:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h> /* for INT_MAX */
#define N 10 /* max matrix size is 10 x 10 */
#define INF 9999
int cost = 0;
typedef struct lnode {
int fromv;
int tov;
int weight;
struct lnode *next;
} lnode;
int insertnode(lnode **lst, int from, int to, int wt);
void prims(int amtrx[][N],int n, lnode **lst);
void printpaths(lnode **lst);
void freelist(lnode **lst);
int isValid(int a, int b, int select[]);
int insertnode(lnode **lst, int from, int to, int wt){
lnode *newnode;
newnode = (lnode *) malloc(sizeof(struct lnode));
newnode->fromv = from;
newnode->tov = to;
newnode->weight = wt;
newnode->next=NULL;
if(*lst == NULL){
newnode -> next = *lst;
*lst = newnode;
} else {
lnode *current;
current = *lst;
while(current->next != NULL){
current = current->next;
}
newnode->next = current->next;
current->next = newnode;
}
return 1;
}
int isValid(int a, int b, int select[]){
if(a == b) return 0;
if(select[a] == 0 && select[b] == 0) return 0;
else if (select[a] == 1 && select[b] == 1) return 0;
return 1;
}
void prims(int amtrx[][N], int n, lnode **lst){
int i, j, row, col, edges_seen, min;
int select[N] = {0};
edges_seen = 0;
select[n] = 1;
while(edges_seen < N-1){
min = INF;
row = -1;
col = -1;
for(i = 0; i < N; i++) {
for(j = 0; j < N; j++){
if(amtrx[i][j] < min) {
if(isValid(i, j, select) == 1){
min = amtrx[i][j];
row = i;
col = j;
}
}
}
}
if(row != -1 && col != -1){
select[col] = 1;
select[row] = 1;
cost = cost + min;
insertnode(lst, row, col, min);
edges_seen++;
}
for(i = 0; i < N; i++){
printf("%3d", select[i]);
}
puts("\n\n");
}
}
void printpaths(lnode **lst){
lnode *current;
current = *lst;
while(current != NULL) {
printf("%4i ",current->fromv);
printf("%4i ", current->tov);
printf("%4i \n", current->weight);
current = current->next;
}
printf("\ntotal cost: %4i\n", cost);
}
void freelist(lnode **lst) {
lnode *temp = NULL;
while(*lst != NULL)
{
temp = *lst;
*lst = (*lst)->next;
free(temp);
}
}
int main(int argc, char **argv){
FILE *f = fopen(argv[1], "r");
lnode *lst;
lst = (lnode *)malloc(sizeof(struct lnode));
int i, j, nsz, nedg, fr, to, vtx, wt;
vtx = 1111;
nedg = 999;
nsz = 100;
fscanf(f, "%d %d %d", &nsz, &nedg, &vtx);
int amtrx[nsz][N];
for(i = 0; i < nsz; i++){
for(j = 0; j < nsz; j++){
amtrx[i][j] = INF;
}
}
for(i = 0; i < nedg; i++){
fscanf(f, "%d %d %d", &fr, &to, &wt);
amtrx[fr][to] = wt;
amtrx[to][fr] = wt;
}
fclose(f);
prims(amtrx, vtx, &lst);
printpaths(&lst);
freelist(&lst);
return EXIT_SUCCESS;
}

issue in making Queue data structure as array implementation

this code to make simple queue data structure as array implementation
#include <stdio.h>
#define Q_MAX_SIZE 255
#include <stdbool.h>
struct queue
{
int* pointer;
int* currentValue;
int max, count, theQueue[Q_MAX_SIZE];
};
void initQueue(struct queue*);
bool pushQueue(struct queue*, int);
int* popQueue(struct queue*);
int main(void)
{
int i, j, num = 0;
struct queue obj[5];
for(i=0; i<5; i++)
{
initQueue(&obj[i]);
for(j = 0; j<3; j++)
{
num++;
pushQueue(&obj[i], num);
}
num = 0;
}
for(i=0; i<5; i++)
{
printf("Queue[%d]:\n", i);
int* inputobj;
inputobj = popQueue(&obj[i]);
while(inputobj != NULL)
{
printf("Queue[No.%d] = %d\n", i, *inputobj);
inputobj = popQueue(&obj[i]);
}
putchar('\n');
}
puts("done..!");
return 0;
}
//#################################
void initQueue(struct queue *Q)
{
Q->pointer = Q->theQueue;
Q->max = Q_MAX_SIZE;
Q->count = 0;
}
bool pushQueue(struct queue *Q, int input)
{
if(Q->count < Q->max)
{
*Q->pointer = input;
Q->pointer++;
Q->count++;
return 1;
}
else
return 0;
}
//#################################
int* popQueue(struct queue *Q)
{
int i;
if(Q->count > 0)
{
Q->currentValue = Q->theQueue;
Q->pointer--;
Q->count--;
for(i=0; i < Q->count; i++)
{
int* currentPtr = Q->theQueue + i;
int* nextPtr = currentPtr + 1;
*currentPtr = *nextPtr;
}
return Q->currentValue;
}
else
NULL;
}
there is a problem with the code in the function popQueue() in this line:
Q->currentValue = Q->theQueue;
it is work put the output is not correct
output:
Queue[0]:
Queue[No.0] = 2
Queue[No.0] = 3
Queue[No.0] = 3
Queue[1]:
Queue[No.1] = 2
Queue[No.1] = 3
Queue[No.1] = 3
Queue[2]:
Queue[No.2] = 2
Queue[No.2] = 3
Queue[No.2] = 3
Queue[3]:
Queue[No.3] = 2
Queue[No.3] = 3
Queue[No.3] = 3
Queue[4]:
Queue[No.4] = 2
Queue[No.4] = 3
Queue[No.4] = 3
done..!
but after i change the pointer (currentValue) in the queue struct to make it of type integer and edit some lines in the function popQueue() every thing work fine.
--here is the function after editing:
int* popQueue(struct queue *Q)
{
int i;
if(Q->count > 0)
{
Q->currentValue = Q->theQueue[0];
Q->pointer--;
Q->count--;
for(i=0; i < Q->count; i++)
{
int* currentPtr = Q->theQueue + i;
int* nextPtr = currentPtr + 1;
*currentPtr = *nextPtr;
}
return &Q->currentValue;
}
-- and this is the correct output:
Queue[0]:
Queue[No.0] = 1
Queue[No.0] = 2
Queue[No.0] = 3
Queue[1]:
Queue[No.1] = 1
Queue[No.1] = 2
Queue[No.1] = 3
Queue[2]:
Queue[No.2] = 1
Queue[No.2] = 2
Queue[No.2] = 3
Queue[3]:
Queue[No.3] = 1
Queue[No.3] = 2
Queue[No.3] = 3
Queue[4]:
Queue[No.4] = 1
Queue[No.4] = 2
Queue[No.4] = 3
The Question is: what makes the first code provide wrong output?
What gave you the wrong output in the first case was the fact that the pointer Q->currentValue never changed its value (the address which it was holding). It was always pointing to the first element in the queue.
Say the queue contained {1, 2, 3 |,<garbage>}.
That means, that after the first pop, the queue became:
{2, 3 |, 3, <garbage>}
and currentValue still held the address of the first element in the array, which is 2.
After the second pop:
{3 |, 3, 3, <garbage>}
and currentValue points to the first element, which value is 3,
The last time, the array is unchanged (as Q->count-- changes Q->count's value to 0), so the conent is
{| 3, 3, 3, <garbage>}
and currentValue is still pointing to a 3.
I assume that you changed the second example to make Queue->currentValue an int.
This way, it retains the original first element (which is popped).
That makes your prints work properly in your test case.
However,
Your implementation will fail if you had a 0 in your queue.
Your implementation adds needless complexity to the pop operation (O(n)). It would be much better to implement a cyclic queue, with head and tail.
Retaining a copy of the popped element in order to return it would not be my first choice. I would suggest implementing an isEmpty() method, check its result in the while loop and while the queue is not empty, simply have pop() return the queue advance its head and return the previous head element.

Resources