132 lines
2.7 KiB
C
132 lines
2.7 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
typedef struct { void * data; int pri; } q_elem_t;
|
|
typedef struct { q_elem_t *buf; int n, alloc; } pri_queue_t, *pri_queue;
|
|
|
|
#define priq_purge(q) (q)->n = 1
|
|
#define priq_size(q) ((q)->n - 1)
|
|
/* first element in array not used to simplify indices */
|
|
pri_queue priq_new(int size)
|
|
{
|
|
if (size < 4) size = 4;
|
|
|
|
pri_queue q = malloc(sizeof(pri_queue_t));
|
|
q->buf = malloc(sizeof(q_elem_t) * size);
|
|
q->alloc = size;
|
|
q->n = 1;
|
|
|
|
return q;
|
|
}
|
|
|
|
void priq_push(pri_queue q, void *data, int pri)
|
|
{
|
|
q_elem_t *b;
|
|
int n, m;
|
|
|
|
if (q->n >= q->alloc) {
|
|
q->alloc *= 2;
|
|
b = q->buf = realloc(q->buf, sizeof(q_elem_t) * q->alloc);
|
|
} else
|
|
b = q->buf;
|
|
|
|
n = q->n++;
|
|
/* append at end, then up heap */
|
|
while ((m = n / 2) && pri < b[m].pri) {
|
|
b[n] = b[m];
|
|
n = m;
|
|
}
|
|
b[n].data = data;
|
|
b[n].pri = pri;
|
|
}
|
|
|
|
/* remove top item. returns 0 if empty. *pri can be null. */
|
|
void * priq_pop(pri_queue q, int *pri)
|
|
{
|
|
void *out;
|
|
if (q->n == 1) return 0;
|
|
|
|
q_elem_t *b = q->buf;
|
|
|
|
out = b[1].data;
|
|
if (pri) *pri = b[1].pri;
|
|
|
|
/* pull last item to top, then down heap. */
|
|
--q->n;
|
|
|
|
int n = 1, m;
|
|
while ((m = n * 2) < q->n) {
|
|
if (m + 1 < q->n && b[m].pri > b[m + 1].pri) m++;
|
|
|
|
if (b[q->n].pri <= b[m].pri) break;
|
|
b[n] = b[m];
|
|
n = m;
|
|
}
|
|
|
|
b[n] = b[q->n];
|
|
if (q->n < q->alloc / 2 && q->n >= 16)
|
|
q->buf = realloc(q->buf, (q->alloc /= 2) * sizeof(b[0]));
|
|
|
|
return out;
|
|
}
|
|
|
|
/* get the top element without removing it from queue */
|
|
void* priq_top(pri_queue q, int *pri)
|
|
{
|
|
if (q->n == 1) return 0;
|
|
if (pri) *pri = q->buf[1].pri;
|
|
return q->buf[1].data;
|
|
}
|
|
|
|
/* this is O(n log n), but probably not the best */
|
|
void priq_combine(pri_queue q, pri_queue q2)
|
|
{
|
|
int i;
|
|
q_elem_t *e = q2->buf + 1;
|
|
|
|
for (i = q2->n - 1; i >= 1; i--, e++)
|
|
priq_push(q, e->data, e->pri);
|
|
priq_purge(q2);
|
|
}
|
|
|
|
int main()
|
|
{
|
|
int i, p;
|
|
const char *c, *tasks[] ={
|
|
"Clear drains", "Feed cat", "Make tea", "Solve RC tasks", "Tax return" };
|
|
int pri[] = { 3, 4, 5, 1, 2 };
|
|
|
|
/* make two queues */
|
|
pri_queue q = priq_new(0), q2 = priq_new(0);
|
|
|
|
/* push all 5 tasks into q */
|
|
for (i = 0; i < 5; i++)
|
|
priq_push(q, tasks[i], pri[i]);
|
|
|
|
/* pop them and print one by one */
|
|
while ((c = priq_pop(q, &p)))
|
|
printf("%d: %s\n", p, c);
|
|
|
|
/* put a million random tasks in each queue */
|
|
for (i = 0; i < 1 << 20; i++) {
|
|
p = rand() / ( RAND_MAX / 5 );
|
|
priq_push(q, tasks[p], pri[p]);
|
|
|
|
p = rand() / ( RAND_MAX / 5 );
|
|
priq_push(q2, tasks[p], pri[p]);
|
|
}
|
|
|
|
printf("\nq has %d items, q2 has %d items\n", priq_size(q), priq_size(q2));
|
|
|
|
/* merge q2 into q; q2 is empty */
|
|
priq_combine(q, q2);
|
|
printf("After merge, q has %d items, q2 has %d items\n",
|
|
priq_size(q), priq_size(q2));
|
|
|
|
/* pop q until it's empty */
|
|
for (i = 0; (c = priq_pop(q, 0)); i++);
|
|
printf("Popped %d items out of q\n", i);
|
|
|
|
return 0;
|
|
}
|