aboutsummaryrefslogtreecommitdiff
path: root/src/priority_queue.c
blob: 59d64df3bb15af1c37d4ff692da9e8556a9dab79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include "priority_queue.h"

#include <stdlib.h>
#include <string.h>

void init_priority_queue(priority_queue_t *pq, int cap, int elem_sz,
                         int (*cmp)(void *, void *)) {
    pq->cap = cap;
    pq->size = 0;
    pq->elemsz = elem_sz;
    pq->cmp = cmp;
    pq->buf = malloc(cap * elem_sz);
}

static void swap(priority_queue_t *pq, int a, int b) {
    char buf[pq->elemsz];
    void *tmp = buf;
    int elemsz = pq->elemsz;
    memcpy(tmp, pq->buf + a * elemsz, elemsz);
    memcpy(pq->buf + a * elemsz, pq->buf + b * elemsz, elemsz);
    memcpy(pq->buf + b * elemsz, tmp, elemsz);
}

static int cmp(priority_queue_t *pq, int a, int b) {
    return pq->cmp(pq->buf + a * pq->elemsz, pq->buf + b * pq->elemsz);
}

void priority_queue_push(priority_queue_t *pq, void *elem) {
    if (pq->size + 1 > pq->cap) {
        pq->buf = realloc(pq->buf, 2 * pq->cap * pq->elemsz);
        pq->cap *= 2;
    }
    memcpy(pq->buf + pq->size * pq->elemsz, elem, pq->elemsz);
    pq->size++;
    if (pq->size == 0) {
        return;
    }
    int i = pq->size - 1;
    while (i > 0 && cmp(pq, i, i / 2) > 0) {
        swap(pq, i, i / 2);
        i /= 2;
    }
}

static void heapify(priority_queue_t *pq, int idx) {
    int left, right, largest;
    left = 2 * idx + 1;
    right = 2 * idx + 2;
    if (left < pq->size && cmp(pq, left, idx) > 0) {
        largest = left;
    } else {
        largest = idx;
    }
    if (right < pq->size && cmp(pq, right, largest) > 0) {
        largest = right;
    }
    if (largest != idx) {
        swap(pq, largest, idx);
        heapify(pq, largest);
    }
}

void priority_queue_pop(priority_queue_t *pq) {
    if (pq->size == 0) return;
    memcpy(pq->buf, pq->buf + (pq->size - 1) * pq->elemsz, pq->elemsz);
    pq->size -= 1;
    heapify(pq, 0);
}

void *priority_queue_top(priority_queue_t *pq) {
    if (pq->size == 0) return NULL;
    return pq->buf;
}