Dijkstra’s shortest path algorithm in C - changing paramateres problem - c

this program is made to calculate shortest path between two vertexs. FUnction add_edge is adding edges and also their distance in format add_edge(g, 1, 2, 7);where first parameter is linked list, second and third paramater are edges and last one is distance between them.
Problem is that my program was made to insert it in this format add_edge(g, 'a', 'b', 7);but sending it as integer and in function making it to number with this action int a = a - 'a';.
and after i transformed my code to sending numbers instead of characters it stopped to work. showing no error but returning tash numbers.
Here's old code(working):
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct {
int vertex;
int weight;
} edge_t;
typedef struct {
edge_t **edges;
int edges_len;
int edges_size;
int dist;
int prev;
int visited;
} vertex_t;
typedef struct {
vertex_t **vertices;
int vertices_len;
int vertices_size;
} graph_t;
typedef struct {
int *data;
int *prio;
int *index;
int len;
int size;
} heap_t;
void add_vertex (graph_t *g, int i) {
int j;
if (g->vertices_size < i + 1) {
int size = g->vertices_size * 2 > i ? g->vertices_size * 2 : i + 4;
g->vertices = realloc(g->vertices, size * sizeof (vertex_t *));
for (j = g->vertices_size; j < size; j++)
g->vertices[j] = NULL;
g->vertices_size = size;
}
if (!g->vertices[i]) {
g->vertices[i] = calloc(1, sizeof (vertex_t));
g->vertices_len++;
}
}
void add_edge (graph_t *g, int a, int b, int w) {
a = a - 'a';
b = b - 'a';
add_vertex(g, a);
add_vertex(g, b);
vertex_t *v = g->vertices[a];
if (v->edges_len >= v->edges_size) {
v->edges_size = v->edges_size ? v->edges_size * 2 : 4;
v->edges = realloc(v->edges, v->edges_size * sizeof (edge_t *));
}
edge_t *e = calloc(1, sizeof (edge_t));
e->vertex = b;
e->weight = w;
v->edges[v->edges_len++] = e;
}
heap_t *create_heap (int n) {
heap_t *h = calloc(1, sizeof (heap_t));
h->data = calloc(n + 1, sizeof (int));
h->prio = calloc(n + 1, sizeof (int));
h->index = calloc(n, sizeof (int));
return h;
}
void push_heap (heap_t *h, int v, int p) {
int i = h->index[v] == 0 ? ++h->len : h->index[v];
int j = i / 2;
while (i > 1) {
if (h->prio[j] < p)
break;
h->data[i] = h->data[j];
h->prio[i] = h->prio[j];
h->index[h->data[i]] = i;
i = j;
j = j / 2;
}
h->data[i] = v;
h->prio[i] = p;
h->index[v] = i;
}
int min (heap_t *h, int i, int j, int k) {
int m = i;
if (j <= h->len && h->prio[j] < h->prio[m])
m = j;
if (k <= h->len && h->prio[k] < h->prio[m])
m = k;
return m;
}
int pop_heap (heap_t *h) {
int v = h->data[1];
int i = 1;
while (1) {
int j = min(h, h->len, 2 * i, 2 * i + 1);
if (j == h->len)
break;
h->data[i] = h->data[j];
h->prio[i] = h->prio[j];
h->index[h->data[i]] = i;
i = j;
}
h->data[i] = h->data[h->len];
h->prio[i] = h->prio[h->len];
h->index[h->data[i]] = i;
h->len--;
return v;
}
void dijkstra (graph_t *g, int a, int b) {
int i, j;
a = a - 'a';
b = b - 'a';
for (i = 0; i < g->vertices_len; i++) {
vertex_t *v = g->vertices[i];
v->dist = INT_MAX;
v->prev = 0;
v->visited = 0;
}
vertex_t *v = g->vertices[a];
v->dist = 0;
heap_t *h = create_heap(g->vertices_len);
push_heap(h, a, v->dist);
while (h->len) {
i = pop_heap(h);
if (i == b)
break;
v = g->vertices[i];
v->visited = 1;
for (j = 0; j < v->edges_len; j++) {
edge_t *e = v->edges[j];
vertex_t *u = g->vertices[e->vertex];
if (!u->visited && v->dist + e->weight <= u->dist) {
u->prev = i;
u->dist = v->dist + e->weight;
push_heap(h, e->vertex, u->dist);
}
}
}
v = g->vertices[i];
printf("%d\n", v->dist);
}
int main () {
graph_t *g = calloc(1, sizeof (graph_t));
add_edge(g, 'a', 'b', 7);
add_edge(g, 'a', 'c' ,9);
dijkstra(g, 'a', 'c');
return 0;
}
and here is my new code(that i want to make work):
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct {
int vertex;
int weight;
} edge_t;
typedef struct {
edge_t **edges;
int edges_len;
int edges_size;
int dist;
int prev;
int visited;
} vertex_t;
typedef struct {
vertex_t **vertices;
int vertices_len;
int vertices_size;
} graph_t;
typedef struct {
int *data;
int *prio;
int *index;
int len;
int size;
} heap_t;
void add_vertex (graph_t *g, int i) {
int j;
if (g->vertices_size < i + 1) {
int size = g->vertices_size * 2 > i ? g->vertices_size * 2 : i + 4;
g->vertices = realloc(g->vertices, size * sizeof (vertex_t *));
for (j = g->vertices_size; j < size; j++)
g->vertices[j] = NULL;
g->vertices_size = size;
}
if (!g->vertices[i]) {
g->vertices[i] = calloc(1, sizeof (vertex_t));
g->vertices_len++;
}
}
void add_edge (graph_t *g, int a, int b, int w) {
add_vertex(g, a);
add_vertex(g, b);
vertex_t *v = g->vertices[a];
if (v->edges_len >= v->edges_size) {
v->edges_size = v->edges_size ? v->edges_size * 2 : 4;
v->edges = realloc(v->edges, v->edges_size * sizeof (edge_t *));
}
edge_t *e = calloc(1, sizeof (edge_t));
e->vertex = b;
e->weight = w;
v->edges[v->edges_len++] = e;
}
heap_t *create_heap (int n) {
heap_t *h = calloc(1, sizeof (heap_t));
h->data = calloc(n + 1, sizeof (int));
h->prio = calloc(n + 1, sizeof (int));
h->index = calloc(n, sizeof (int));
return h;
}
void push_heap (heap_t *h, int v, int p) {
int i = h->index[v] == 0 ? ++h->len : h->index[v];
int j = i / 2;
while (i > 1) {
if (h->prio[j] < p)
break;
h->data[i] = h->data[j];
h->prio[i] = h->prio[j];
h->index[h->data[i]] = i;
i = j;
j = j / 2;
}
h->data[i] = v;
h->prio[i] = p;
h->index[v] = i;
}
int min (heap_t *h, int i, int j, int k) {
int m = i;
if (j <= h->len && h->prio[j] < h->prio[m])
m = j;
if (k <= h->len && h->prio[k] < h->prio[m])
m = k;
return m;
}
int pop_heap (heap_t *h) {
int v = h->data[1];
int i = 1;
while (1) {
int j = min(h, h->len, 2 * i, 2 * i + 1);
if (j == h->len)
break;
h->data[i] = h->data[j];
h->prio[i] = h->prio[j];
h->index[h->data[i]] = i;
i = j;
}
h->data[i] = h->data[h->len];
h->prio[i] = h->prio[h->len];
h->index[h->data[i]] = i;
h->len--;
return v;
}
void dijkstra (graph_t *g, int a, int b) {
int i, j;
for (i = 0; i < g->vertices_len; i++) {
vertex_t *v = g->vertices[i];
v->dist = INT_MAX;
v->prev = 0;
v->visited = 0;
}
vertex_t *v = g->vertices[a];
v->dist = 0;
heap_t *h = create_heap(g->vertices_len);
push_heap(h, a, v->dist);
while (h->len) {
i = pop_heap(h);
if (i == b)
break;
v = g->vertices[i];
v->visited = 1;
for (j = 0; j < v->edges_len; j++) {
edge_t *e = v->edges[j];
vertex_t *u = g->vertices[e->vertex];
if (!u->visited && v->dist + e->weight <= u->dist) {
u->prev = i;
u->dist = v->dist + e->weight;
push_heap(h, e->vertex, u->dist);
}
}
}
v = g->vertices[i];
printf("%d\n", v->dist);
}
int main () {
graph_t *g = calloc(1, sizeof (graph_t));
add_edge(g, 1, 2, 7);
add_edge(g, 1, 3 9);
dijkstra(g, 1, 3);
return 0;
}
I would be happy for any suggestion how to make it work even the old one to transform to accept numbers as paramateres and not 'characters'. thanks guys

John Bollinger's comment is right; you are testing different indices. Inside your dijkstra, you are assuming that the graph is fully populated, when it is really very sparse. If I have it correctly, you can ignore the nil nodes:
## -1,3 +1,4 ##
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
## -116,11 +117,17 ##
int i, j;
for (i = 0; i < g->vertices_len; i++) {
vertex_t *v = g->vertices[i];
- v->dist = INT_MAX;
- v->prev = 0;
- v->visited = 0;
+ if (v) {
+ v->dist = INT_MAX;
+ v->prev = 0;
+ v->visited = 0;
+ }
}
vertex_t *v = g->vertices[a];
+ if (v == 0) {
+ printf("-1\n");
+ return;
+ }
v->dist = 0;
heap_t *h = create_heap(g->vertices_len);
push_heap(h, a, v->dist);
## -129,10 +136,12 ##
if (i == b)
break;
v = g->vertices[i];
+ assert(v);
v->visited = 1;
for (j = 0; j < v->edges_len; j++) {
edge_t *e = v->edges[j];
vertex_t *u = g->vertices[e->vertex];
+ assert(u);
if (!u->visited && v->dist + e->weight <= u->dist) {
u->prev = i;
u->dist = v->dist + e->weight;
## -140,8 +149,11 ##
}
}
}
- v = g->vertices[i];
- printf("%d\n", v->dist);
+ if (v = g->vertices[i]) {
+ printf("%d\n", v->dist);
+ } else {
+ printf("-2\n");
+ }
}
At the very least, it doesn't fault with your config.

Related

C compressor - array subscript has type char

I am a real beginner to C so I have no idea why there is this error. I send the code to my friend and it worked for him without any errors and without altering it. I am running it on Oracle VM VirtualBox. There are more files to the compression program. While I want to use the cmake to create a Makefile and a running program this happens.
The error is in the function buildDictionary in condition if(isLeaf(root)).
How should I fix this problem? Any ideas?
#include "huffman.h"
void buildDictionary(struct MinHeapNode *root, int arr[], int top, HuffmanDictionary *dictionary) {
if (root->left) {
arr[top] = 0;
buildDictionary(root->left, arr, top + 1, dictionary);
}
if (root->right) {
arr[top] = 1;
buildDictionary(root->right, arr, top + 1, dictionary);
}
if (isLeaf(root)) {
dictionary->symbol[root->data] = root->data;
dictionary->code[root->data].code = encodeBits(arr, top);
dictionary->code[root->data].size = top;
}
}
void printDictionary(HuffmanDictionary *dictionary) {
for (int i = 0; i < 256; i++) {
int bs[MAX_TREE_HT];
decodeBits(dictionary->code[i].code, dictionary->code[i].size, bs);
printf("%c:", dictionary->symbol[i]);
for (int a = 0; a < dictionary->code[i].size; a++) {
printf("%d", bs[a]);
}
printf("\n");
}
}
long huffman_compress(const uint8_t *src, long size, uint8_t *dst, HuffmanDictionary *dictionary) {
FreqencyData *fd = malloc(sizeof(FreqencyData) * 256);
buildFrequencyData(src, size, fd);
uint8_t words[256];
int frequencies[256];
int count = 0;
for (int a = 0; a < 256; a++) {
if (fd[a].frequency > 0) {
words[count] = (uint8_t) a;
frequencies[count] = fd[a].frequency;
count++;
}
}
struct MinHeapNode *root
= buildHuffmanTree(words, frequencies, count);
int arr[MAX_TREE_HT], top = 0;
buildDictionary(root, arr, top, dictionary);
uint8_t *bits = malloc(size * MAX_TREE_HT);
memset(bits, 0, size * MAX_TREE_HT);
long numOfBits = 0;
for (long i = 0; i < size; i++) {
int n = dictionary->code[src[i]].size;
uint32_t b = dictionary->code[src[i]].code;
int bs[n];
decodeBits(b, n, bs);
for (int a = 0; a < n; a++) {
bits[numOfBits + a] = bs[a];
}
numOfBits += n;
}
long cx = 0;
for (long i = 0; i < numOfBits; i += 8) {
int bs[8];
for (int a = 0; a < 8; a++) {
bs[a] = bits[i + a];
}
dst[cx] = encodeBitsArr(bs);
cx++;
}
return cx;
}
uint32_t encodeBits(int arr[], int n) {
uint32_t ret = 0;
for (int i = 0; i < n; i++) {
if (arr[i] == 1) {
ret += pow(2, i);
}
}
return ret;
}
uint8_t encodeBitsArr(const int arr[8]) {
uint8_t ret = 0;
for (int i = 0; i < 8; i++) {
if (arr[i] == 1) {
ret += pow(2, i);
}
}
return ret;
}
void decodeBits(uint32_t b, int n, int bits[]) {
for (int i = 0; i < n; i++) {
bits[i] = (int) ((b >> i) & ONE_BIT_MASK_32BITS) != 0;
}
}
void decodeBitsFromByte(uint8_t b, int bits[]) {
for (int i = 0; i < 8; i++) {
bits[i] = (int) ((b >> i) & 0x01) != 0;
}
}
int findMatchingSymbol(const int bits[MAX_TREE_HT], HuffmanDictionary *dictionary,int* foundSize) {
for (int i = 0; i < 256; i++) {
int bs[MAX_TREE_HT];
decodeBits(dictionary->code[i].code, dictionary->code[i].size, bs);
bool found = false;
for (int a = 0; a < dictionary->code[i].size; a++) {
if (bs[a] == bits[a]) {
found = true;
} else {
found = false;
break;
}
}
if (found) {
*foundSize = dictionary->code[i].size - 1;
return dictionary->symbol[i];
}
}
return -1;
}
long huffman_extract(const uint8_t *src, long size, uint8_t *dst, HuffmanDictionary *dictionary) {
uint8_t *bits = malloc(size * 8);
memset(bits, 0, size * 8);
for (long i = 0; i < size; i++) {
int bs[8];
decodeBitsFromByte(src[i], bs);
for (int a = 0; a < 8; a++) {
bits[(i * 8) + a] = bs[a];
}
}
long foundBytes = 0;
int bs[MAX_TREE_HT];
for (long l = 0; l < size * 8; l++) {
for (int a = 0; a < MAX_TREE_HT; a++) {
bs[a] = bits[l + a];
}
int* foundSize = malloc(sizeof(int));
uint8_t b = findMatchingSymbol(bs, dictionary, foundSize);
if (b >= 0) {
dst[foundBytes] = b;
l+= *foundSize;
foundBytes++;
}
}
return foundBytes;
}
void buildFrequencyData(const uint8_t *src, long size, FreqencyData *fd) {
for (long i = 0; i < size; i++) {
fd[src[i]].frequency++;
}
}
struct MinHeapNode *newNode(uint8_t data, unsigned freq) {
struct MinHeapNode *temp = (struct MinHeapNode *)malloc(
sizeof(struct MinHeapNode));
temp->left = temp->right = NULL;
temp->data = data;
temp->freq = freq;
return temp;
}
struct MinHeap *createMinHeap(unsigned capacity) {
struct MinHeap *minHeap
= (struct MinHeap *) malloc(sizeof(struct MinHeap));
minHeap->size = 0;
minHeap->capacity = capacity;
minHeap->array = (struct MinHeapNode **)malloc(
minHeap->capacity * sizeof(struct MinHeapNode *));
return minHeap;
}
void swapMinHeapNode(struct MinHeapNode **a,
struct MinHeapNode **b) {
struct MinHeapNode *t = *a;
*a = *b;
*b = t;
}
void minHeapify(struct MinHeap *minHeap, int idx) {
int smallest = idx;
int left = 2 * idx + 1;
int right = 2 * idx + 2;
if (left < minHeap->size
&& minHeap->array[left]->freq
< minHeap->array[smallest]->freq)
smallest = left;
if (right < minHeap->size
&& minHeap->array[right]->freq
< minHeap->array[smallest]->freq)
smallest = right;
if (smallest != idx) {
swapMinHeapNode(&minHeap->array[smallest],
&minHeap->array[idx]);
minHeapify(minHeap, smallest);
}
}
int isSizeOne(struct MinHeap *minHeap) {
return (minHeap->size == 1);
}
struct MinHeapNode *extractMin(struct MinHeap *minHeap) {
struct MinHeapNode *temp = minHeap->array[0];
minHeap->array[0] = minHeap->array[minHeap->size - 1];
--minHeap->size;
minHeapify(minHeap, 0);
return temp;
}
void insertMinHeap(struct MinHeap *minHeap,
struct MinHeapNode *minHeapNode) {
++minHeap->size;
int i = minHeap->size - 1;
while (i
&& minHeapNode->freq
< minHeap->array[(i - 1) / 2]->freq) {
minHeap->array[i] = minHeap->array[(i - 1) / 2];
i = (i - 1) / 2;
}
minHeap->array[i] = minHeapNode;
}
void buildMinHeap(struct MinHeap *minHeap) {
int n = minHeap->size - 1;
int i;
for (i = (n - 1) / 2; i >= 0; --i)
minHeapify(minHeap, i);
}
int isLeaf(struct MinHeapNode *root) {
return !(root->left) && !(root->right);
}
struct MinHeap *createAndBuildMinHeap(uint8_t data[],
int freq[], int size) {
struct MinHeap *minHeap = createMinHeap(size);
for (int i = 0; i < size; ++i)
minHeap->array[i] = newNode(data[i], freq[i]);
minHeap->size = size;
buildMinHeap(minHeap);
return minHeap;
}
struct MinHeapNode *buildHuffmanTree(uint8_t data[],
int freq[], int size) {
struct MinHeapNode *left, *right, *top;
struct MinHeap *minHeap
= createAndBuildMinHeap(data, freq, size);
while (!isSizeOne(minHeap)) {
left = extractMin(minHeap);
right = extractMin(minHeap);
top = newNode('$', left->freq + right->freq);
top->left = left;
top->right = right;
insertMinHeap(minHeap, top);
}
return extractMin(minHeap);
}
I didn't try anything as the code is running normally on other computers, but no on mine.
In the header file huffman.h, the structure MinHeapNode has a member data with type char that can have negative values on some architectures where type char is signed by default. This would cause undefined behavior when indexing dictionary->symbol[root->data] or dictionary->code[root->data] as you would be dereferencing elements outside the array boundaries. Just change the type to unsigned char or uint8_t to avoid this issue and fix the warning, that -Werror turned into an error.

Getting a segmentation fault error on an Open Addressing Hash Map?

I'm getting a segmentation fault error somewhere in my insert function. It says that its due to one of the 'strcmp' comparisons but i cant find the issue after looking at all of them.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define INITIAL_CAPACITY 8
typedef struct node
{
unsigned int val;
char *key;
bool del;
} Node;
typedef Node * NodePtr;
typedef struct hashMap
{
NodePtr array;
size_t capacity;
size_t size;
} HashMap;
typedef HashMap * HMPtr;
//|-------------------------
HMPtr create();
void insert(HMPtr map, char *str);
//y
void resize_insert(HMPtr map, char *str);
//y
void print(HMPtr map);
void destroy(HMPtr *mapPtr);
void resize(HMPtr map);
//y
unsigned int hash(char *str);
//y
unsigned int pop(HMPtr map, char *key);
//y
//|-------------------------
int main(void)
{
HMPtr map = create();
insert(map, "Keathan");
insert(map, "Trey");
insert(map, "Noah");
insert(map, "Kleiner");
insert(map, "data");
insert(map, "Matthew");
print(map);
destroy(&map);
return 0;
}
unsigned int pop(HMPtr map, char *str)
{
unsigned int val = hash(str);
size_t h = (size_t)val;
size_t index = h % map->capacity;
for(size_t i = 0; map->array[index].key && strcmp(str, map->array[index].key);index = (h + ((++i) + i*i)/2)%map->capacity);
if (map->array[index].key)
{
map->array[index].del = true;
return map->array[index].val;
}
return 0;
}
unsigned int hash(char *str)
{
unsigned int out = 0;
unsigned int base = 31;
unsigned int factor = 1;
for (size_t i = 0; str[i] != 0; ++i)
{
out += (unsigned int)str[i] * factor;
factor *= base;
}
return out;
}
void resize(HMPtr map)
{
NodePtr old = map->array;
size_t old_capacity = map->capacity;
map->capacity = old_capacity * 2;
map->array = calloc(map->capacity, sizeof(Node));
for(size_t i = 0; i < old_capacity; ++i)
{
if(old[i].key)
{
if(old[i].del)
free(old[i].key);
else
resize_insert(map, old[i].key);
}
}
free(old);
}
void resize_insert(HMPtr map, char *str)
{
unsigned int val = hash(str);
size_t h = (size_t)val;
size_t index = h % map->capacity;
for (size_t i = 0; map->array[index].key; index = (h + ((++i) + i*i)/2)%map->capacity);
map->array[index].key = str;
map->array[index].val = val;
++(map->size);
}
void insert(HMPtr map, char *str)
{
unsigned int val = hash(str);
size_t h = (size_t)val;
size_t index = h % map->capacity;
size_t i;
NodePtr deleted = NULL;
for(i = 0; map->array[index].key && strcmp(str, map->array[index].key);index = (h + ((++i) + i*i)/2)%map->capacity)
if(!deleted && map->array[index].del)
{
deleted = map->array + index;
for(index = (h + ((++i) + i*i)/2)%map->capacity; map->array[index].key && strcmp(str, map->array[index].key); index = (h + ((++i) + i*i)/2)%map->capacity);
break;
}
if (map->array[index].key == NULL)
{
if(deleted)
{
free(deleted->key);
deleted->del = false;
index = deleted - map->array;
}
else if (++(map->size) >= 0.7*map->capacity)
{
resize(map);
index = h % map->capacity;
for (i = 0; map->array[index].key; index = (h + ((++i) + i*i)/2)%map->capacity);
}
map->array[index].key = calloc(strlen(str)+1, sizeof(char));
strcpy(map->array[index].key, str);
}
else
map->array[index].val = val;
}
HMPtr create()
{
HMPtr newList = malloc(sizeof(HashMap));
newList->size = 0;
newList->capacity = INITIAL_CAPACITY;
newList->array = calloc(newList->capacity, sizeof(NodePtr));
return newList;
}
void destroy(HMPtr *mapPtr)
{
free((*mapPtr)->array);
free(*mapPtr);
*mapPtr = NULL;
}
void print(HMPtr map)
{
for (size_t i = 0; i < map->capacity; ++i)
printf("%s;%u\n", map->array[i].key, map->array[i].val);
}
This is the Error i recieved after running on gdb
'''
Program received signal SIGSEGV, Segmentation fault.
__strcmp_sse2_unaligned ()
at ../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S:30
30 ../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S: No such file or
directory.
'''
If anyone could spot the issue then that would help a lot. Thanks!
sizeof(nodePtr) is size of pointer you need sizeof(struct Node)
HMPtr create()
{
HMPtr newList = malloc(sizeof(HashMap));
newList->size = 0;
newList->capacity = INITIAL_CAPACITY;
newList->array = calloc(newList->capacity, sizeof(*newList->array));
return newList;
}

Reversing the order of a popped priority queue in c

I have this code which pops the highest priority node from the queue. Currently the highest priority is defined as 1. I would like to change this so the highest priority is from 10 -> 1. To clarify the problem is in the pop function, others are added simply for context.
Node and heap definitions:
struct intnode {
int value;
int priority;
};
typedef struct intnode IntNode;
struct heap {
IntNode *nodes;
int len;
int size;
};
typedef struct heap heap_t;
Here is the push function of the queue:
void push (heap_t *h, int priority, int value) {
if (h->len + 1 >= h->size) {
if(h->size) {
h->size = h->size * 2;
}
else {
h->size = 4;
}
h->nodes = (IntNode *)realloc(h->nodes, h->size * sizeof (IntNode));
}
int i = h->len + 1;
int j = i / 2;
while (i > 1 && h->nodes[j].priority > priority) {
h->nodes[i] = h->nodes[j];
i = j;
j = j / 2;
}
h->nodes[i].value = value;
h->nodes[i].priority = priority;
h->len++;
}
The pop function of the queue:
int pop (heap_t *h) {
int i, j, k;
if (!h->len) {
return -1;
}
int value = h->nodes[1].value;
h->nodes[1] = h->nodes[h->len];
h->len--;
i = 1;
while (1) {
k = i;
j = 2 * i;
if (j <= h->len && h->nodes[j].priority < h->nodes[k].priority) {
k = j;
}
if (j + 1 <= h->len && h->nodes[j + 1].priority < h->nodes[k].priority) {
k = j + 1;
}
if (k == i) {
break;
}
h->nodes[i] = h->nodes[k];
i = k;
}
h->nodes[i] = h->nodes[h->len + 1];
return value;
}
Thank you for your time!
Just push your Elements with 11 - your priority

How to modify the priority of a value in a max-heap?

I am writing a max-heap, which can change the priority/value. However, I have problems to understand what is wrong in my code.
I have followed this as reference: ref
This is my code (I have hide some functions since it not the focus here)
static void swap(MAX_HEAP *heap, int i, int j);
static void swim(MAX_HEAP *heap, int k);
static void sink(MAX_HEAP *heap, int k);
void swap(MAX_HEAP *heap, int i, int j) {
HEAP_ELEM s;
int k;
s = heap->binary_heap[i];
k = heap->keys[s.fu];
heap->binary_heap[i] = heap->binary_heap[j];
heap->keys[k] = heap->keys[heap->binary_heap[j].fu];
heap->keys[heap->binary_heap[j].fu] = k;
heap->binary_heap[j] = s;
}
void swim(MAX_HEAP *heap, int k) {
int m;
m = k / 2.0;
while (k > 1 && heap->binary_heap[m].priority < heap->binary_heap[k].priority) {
swap(heap, k, m);
k = m;
m = k / 2.0;
}
}
void sink(MAX_HEAP *heap, int k) {
int j;
while (2 * k <= heap->n) {
j = 2 * k;
if (j < heap->n && heap->binary_heap[j].priority < heap->binary_heap[j + 1].priority)
j++;
if (!(heap->binary_heap[k].priority < heap->binary_heap[j].priority))
break;
swap(heap, k, j);
k = j;
}
}
MAX_HEAP *create_maxheap(int capacity) {
int i;
MAX_HEAP *ret;
ret = (MAX_HEAP*) malloc(sizeof (MAX_HEAP));
ret->n = 0;
ret->binary_heap = (HEAP_ELEM*) malloc(sizeof (HEAP_ELEM) * (capacity + 1));
ret->binary_heap[0].fu = 0;
ret->binary_heap[0].priority = 0;
ret->max = capacity;
ret->keys = (int*) malloc(sizeof (int) * (capacity + 1));
for (i = 0; i <= capacity + 1; i++) {
ret->keys[i] = -1;
}
return ret;
}
HEAP_ELEM get_maxheap(MAX_HEAP *heap) {
HEAP_ELEM ret;
if (heap->n == 0) {
return;
}
ret = heap->binary_heap[1];
heap->keys[ret.fu] = -1;
swap(heap, 1, heap->n);
heap->n--;
sink(heap, 1);
return ret;
}
void insert_maxheap(MAX_HEAP *heap, int fu, int p) {
if (heap->n + 1 >= heap->max) {
int i;
heap->max *= 2;
heap->keys = (int*) realloc(heap->keys, sizeof (int) * (heap->max + 1));
heap->binary_heap = (HEAP_ELEM*) realloc(heap->binary_heap, sizeof (HEAP_ELEM) * (heap->max + 1));
for (i = heap->n+1; i < heap->max + 1; i++) {
heap->keys[i] = -1;
}
}
heap->n++;
heap->binary_heap[heap->n].fu = fu;
heap->binary_heap[heap->n].priority = p;
heap->keys[fu] = heap->n;
swim(heap, heap->n);
}
void modify_maxheap(MAX_HEAP *heap, int fu, int p) {
int i;
i = heap->keys[fu];
int old;
if (i == -1) {
insert_maxheap(heap, fu, p);
return;
}
old = heap->binary_heap[i].priority;
heap->binary_heap[i].fu = fu;
heap->binary_heap[i].priority = p;
heap->keys[fu] = i;
if (old < p) {
/* we need to bubble up*/
swim(heap, i);
} else if (old > p) {
//we need to bubble down
sink(heap, i);
}
}
When I have the following execution, it gives bad results... what is wrong here? For instance...
int main(int argc, char** argv) {
MAX_HEAP *heap, *heap2;
HEAP_ELEM he;
heap = create_maxheap(3);
modify_maxheap(heap, 1, 7);
modify_maxheap(heap, 2, 10);
modify_maxheap(heap, 3, 78);
modify_maxheap(heap, 4, 3);
modify_maxheap(heap, 5, 45);
printf("heap 1\n\n");
while(heap->n > 0) {
he = get_maxheap(heap);
printf("..fu: %d; value: %d\n", he.fu, he.priority);
}
printf("max size of heap1: %d\n", heap->max);
printf("\n\n");
heap2 = create_maxheap(10);
modify_maxheap(heap2, 3, 90);
modify_maxheap(heap2, 1, 7);
modify_maxheap(heap2, 2, 10);
modify_maxheap(heap2, 3, 9);
modify_maxheap(heap2, 3, 92);
modify_maxheap(heap2, 4, 3);
modify_maxheap(heap2, 3, 90);
modify_maxheap(heap2, 1, 99);
modify_maxheap(heap2, 5, 45);
modify_maxheap(heap2, 1, 89);
printf("heap 2\n\n");
while(heap2->n > 0) {
he = get_maxheap(heap2);
printf("fu: %d; value: %d\n", he.fu, he.priority);
}
return (EXIT_SUCCESS);
}
Note that I am using an array to store the indices of HEAP_ELEM in order to know the position of a HEAP_ELEM (which has as primary key the "fu" and change its priority. This is my output:
heap 1
..fu: 3; value: 78
..fu: 5; value: 45
..fu: 2; value: 10
..fu: 1; value: 7
..fu: 4; value: 3
max size of heap1: 6
heap 2
fu: 1; value: 99
fu: 3; value: 90
fu: 1; value: 89
fu: 5; value: 45
fu: 4; value: 3
I have changed my modify_maxheap function and it worked:
void modify_maxheap(MAX_HEAP *heap, int fu, int p) {
int i;
i = heap->keys[fu];
if (i == -1) {
insert_maxheap(heap, fu, p);
return;
}
heap->binary_heap[i].priority = p;
swim(heap, i);
sink(heap, i);
}
The reason is that we have to bubble-up and bubble-down in case of any modification to guarantee the heap condition. I hope it can serve as base for someone.

Pointers and Dynamic Memory

I have a function that returns a pointer to an array. I'm running it in a loop and free() seems to be giving me problems. I'm not sure where, but it appears that somewhere in the main loop the memory that I'm trying to free is being used. I'm using Xcode 3.2.1 in 10.6 | Debug | x86_64 build.
The program will run through the main loop one time; the second time it encounters the free() it gives me the following error:
malloc: *** error for object 0x100100180: incorrect checksum for freed object -
object was probably modified after being freed.
Can someone point out (no pun intended) what I'm doing wrong with pointers here?
Here is the program:
int main(int argc, char **argv) {
int *partition;
int lowerLimit;
int upperLimit;
// snip ... got lowerLimit and upperLimit from console arguments
// this is the 'main loop':
for (int i = lowerLimit; i <= upperLimit; i += 2) {
partition = goldbachPartition(i);
printOutput(partition[0], partition[1], i);
free(partition); // I get problems on the second iteration here
}
return 0;
}
int *goldbachPartition(int x) {
int solved = 0;
int y, z;
int *primes;
int *result;
result = intAlloc(2);
primes = atkinsPrimes(x);
for (int i = intCount(primes)-1; i >= 0; i--) {
y = primes[i];
for (int j = 0; j < y; j++) {
z = primes[j];
if (z + y >= x) {
break;
}
}
if (z + y == x) {
solved = 1;
result[0] = y;
result[1] = z;
break;
} else if (y == z) {
result[0] = 0;
result[1] = 0;
break;
}
}
free(primes);
return result;
}
int *atkinsPrimes(int limit) {
int *primes;
int *initialPrimes;
int *filtered;
int *results;
int counter = 0;
int sqrtLimit;
int xLimit;
int resultsSize;
primes = intAlloc(limit+1);
intFillArray(primes, limit+1, 0);
sqrtLimit = floor(sqrt(limit));
xLimit = floor(sqrt((limit+1) / 2));
// these loops are part of the Atkins Sieve implementation
for (int x = 1; x < xLimit; x++) {
int xx = x*x;
for (int y = 1; y < sqrtLimit; y++) {
int yy = y*y;
int n = 3*xx + yy;
if (n <= limit && n % 12 == 7) {
primes[n] = (primes[n] == 1) ? 0 : 1;
}
n += xx;
if (n <= limit && (n % 12 == 1 || n % 12 == 5)) {
primes[n] = (primes[n] == 1) ? 0 : 1;
}
if (x > y) {
n -= xx + 2*yy;
if (n <= limit && n % 12 == 11) {
primes[n] = (primes[n] == 1) ? 0 : 1;
}
}
}
}
for (int n = 5; n < limit; n++) {
if (primes[n] == 1) {
for (int k = n*n; k < limit; k += n*n) {
primes[k] = 0;
}
}
}
initialPrimes = intAlloc(2);
if (limit >= 2) {
initialPrimes[counter++] = 2;
}
if (limit >= 3) {
initialPrimes[counter++] = 3;
}
filtered = intFilterArrayKeys(primes, limit+1);
results = intMergeArrays(initialPrimes, filtered, counter, trueCount(primes, limit+1));
resultsSize = counter + trueCount(primes, limit+1);
free(primes);
free(initialPrimes);
free(filtered);
results[resultsSize] = 0;
return results;
}
int trueCount(int *subject, int arraySize) {
int count = 0;
for (int i = 0; i < arraySize; i++) {
if (subject[i] == 1) {
count++;
}
}
return count;
}
int intCount(int *subject) {
// warning: expects 0 terminated array.
int count = 0;
while (*subject++ != 0) {
count++;
}
return count;
}
void intFillArray(int *subject, int arraySize, int value) {
for (int i = 0; i < arraySize; i++) {
subject[i] = value;
}
}
int *intFilterArrayKeys(int *subject, int arraySize) {
int *filtered;
int count = 0;
filtered = intAlloc(trueCount(subject, arraySize));
for (int i = 0; i < arraySize; i++) {
if (subject[i] == 1) {
filtered[count++] = i;
}
}
return filtered;
}
int *intMergeArrays(int *subject1, int *subject2, int arraySize1, int arraySize2) {
int *merge;
int count = 0;
merge = intAlloc(arraySize1 + arraySize2);
for (int i = 0; i < arraySize1; i++) {
merge[count++] = subject1[i];
}
for (int i = 0; i < arraySize2; i++) {
merge[count++] = subject2[i];
}
return merge;
}
int *intAlloc(int amount) {
int *ptr;
ptr = (int *)malloc(amount * sizeof(int));
if (ptr == NULL) {
printf("Error: NULL pointer\n");
}
return ptr;
}
void printOutput(int num1, int num2, int rep) {
if (num1 == 0) {
printf("%d: No solution\n", rep);
exit(0);
} else {
printf("%d = %d + %d\n", rep, num1, num2);
}
}
Why is intAlloc not returning int* ?
int *intAlloc(int amount) {
int *ptr;
ptr = (int *)malloc(amount * sizeof(int));
if(ptr == NULL) {
printf("Error: NULL pointer\n");
exit(1);
}
return ptr; //like this
}
EDIT (after your update):
On atkinsPrimes() where is filtered being intAlloc()ed?
int *atkinsPrimes(int limit) {
int *primes;
int *initialPrimes;
int *filtered;
int *results;
int resultsSize;
primes = intAlloc(limit+1);
// ...
initialPrimes = intAlloc(2);
// ...
resultsSize = counter + trueCount(primes, limit+1);
free(primes);
free(initialPrimes);
free(filtered); // Where was it intAlloc()ed?
results[resultsSize] = 0; // make the array 0-terminated to make it easier to work with
return results;
}
EDIT (after your N-th update):
This is a compilable version of your code. It ran smooth on my machine, no crashes. Compiled with g++ (due to declarations of variables inside the for statement):
g++ (Debian 4.3.2-1.1) 4.3.2
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int *goldbachPartition(int x);
int *atkinsPrimes(int limit);
int trueCount(int *subject, int arraySize);
int intCount(int *subject) ;
void intFillArray(int *subject, int arraySize, int value);
int *intFilterArrayKeys(int *subject, int arraySize);
int *intAlloc(int amount);
void printOutput(int num1, int num2, int rep) ;
int *intMergeArrays(int *subject1, int *subject2, int arraySize1, int arraySize2);
int main(int argc, char **argv) {
if (argc < 3) {
printf("Usage: ./program <lower> <upper>\n");
return 0;
}
int *partition;
int lowerLimit = atoi(argv[1]);
int upperLimit = atoi(argv[2]);
// snip ... got lowerLimit and upperLimit from console arguments
// this is the 'main loop':
for (int i = lowerLimit; i <= upperLimit; i += 2) {
partition = goldbachPartition(i);
printOutput(partition[0], partition[1], i);
free(partition); // I get problems on the second iteration here
}
return 0;
}
int *goldbachPartition(int x) {
int solved = 0;
int y, z;
int *primes;
int *result;
result = intAlloc(2);
primes = atkinsPrimes(x);
for (int i = intCount(primes)-1; i >= 0; i--) {
y = primes[i];
for (int j = 0; j < y; j++) {
z = primes[j];
if (z + y >= x) {
break;
}
}
if (z + y == x) {
solved = 1;
result[0] = y;
result[1] = z;
break;
} else if (y == z) {
result[0] = 0;
result[1] = 0;
break;
}
}
free(primes);
return result;
}
int *atkinsPrimes(int limit) {
int *primes;
int *initialPrimes;
int *filtered;
int *results;
int counter = 0;
int sqrtLimit;
int xLimit;
int resultsSize;
primes = intAlloc(limit+1);
intFillArray(primes, limit+1, 0);
sqrtLimit = floor(sqrt(limit));
xLimit = floor(sqrt((limit+1) / 2));
for (int x = 1; x < xLimit; x++) {
int xx = x*x;
for (int y = 1; y < sqrtLimit; y++) {
int yy = y*y;
int n = 3*xx + yy;
if (n <= limit && n % 12 == 7) {
primes[n] = (primes[n] == 1) ? 0 : 1;
}
n += xx;
if (n <= limit && (n % 12 == 1 || n % 12 == 5)) {
primes[n] = (primes[n] == 1) ? 0 : 1;
}
if (x > y) {
n -= xx + 2*yy;
if (n <= limit && n % 12 == 11) {
primes[n] = (primes[n] == 1) ? 0 : 1;
}
}
}
}
for (int n = 5; n < limit; n++) {
if (primes[n] == 1) {
for (int k = n*n; k < limit; k += n*n) {
primes[k] = 0;
}
}
}
initialPrimes = intAlloc(2);
if (limit >= 2) {
initialPrimes[counter++] = 2;
}
if (limit >= 3) {
initialPrimes[counter++] = 3;
}
filtered = intFilterArrayKeys(primes, limit+1);
results = intMergeArrays(initialPrimes, filtered, counter, trueCount(primes, limit+1));
resultsSize = counter + trueCount(primes, limit+1);
free(primes);
free(initialPrimes);
free(filtered);
results[resultsSize] = 0;
return results;
}
int trueCount(int *subject, int arraySize) {
int count = 0;
for (int i = 0; i < arraySize; i++) {
if (subject[i] == 1) {
count++;
}
}
return count;
}
int intCount(int *subject) {
// warning: expects 0 terminated array.
int count = 0;
while (*subject++ != 0) {
count++;
}
return count;
}
void intFillArray(int *subject, int arraySize, int value) {
for (int i = 0; i < arraySize; i++) {
subject[i] = value;
}
}
int *intFilterArrayKeys(int *subject, int arraySize) {
int *filtered;
int count = 0;
filtered = intAlloc(trueCount(subject, arraySize));
for (int i = 0; i < arraySize; i++) {
if (subject[i] == 1) {
filtered[count++] = i;
}
}
return filtered;
}
int *intMergeArrays(int *subject1, int *subject2, int arraySize1, int arraySize2) {
int *merge;
int count = 0;
merge = intAlloc(arraySize1 + arraySize2);
for (int i = 0; i < arraySize1; i++) {
merge[count++] = subject1[i];
}
for (int i = 0; i < arraySize2; i++) {
merge[count++] = subject2[i];
}
return merge;
}
int *intAlloc(int amount) {
int *ptr;
ptr = (int *)malloc(amount * sizeof(int));
if (ptr == NULL) {
printf("Error: NULL pointer\n");
}
return ptr;
}
void printOutput(int num1, int num2, int rep) {
if (num1 == 0) {
printf("%d: No solution\n", rep);
exit(0);
} else {
printf("%d = %d + %d\n", rep, num1, num2);
}
}
Since you are still omitting some source, I can only imagine that the problem is hidden there.
EDIT: (my last update)
To assist your debugging, you should replace your main() function by the one below:
int main(int argc, char **argv)
{
int *primes = NULL;
primes = atkinsPrimes(44); // Evil magic number
free(primes);
return 0;
}
Having a minimal example to reproduce the behavior you pointed out is much better then the whole thing. Have fun with atkinsPrimes(44)

Resources