Commit db40734d authored by Christian Würdig's avatar Christian Würdig
Browse files

initial checkin of priority queue implementation

[r12714]
parent d3b4ae2f
#include "array.h"
#include "pqueue.h"
/**
* Implements a heap.
*
* Implementation note: It might seem strange that we start indexing at 0
* but use 2*i and 2*i+1 to find the left and right sucessor of an index.
* The trick is that for index 0 the left successor is 0 again, and the
* right successor is 1 in this scheme. For the right successor 1 everything
* works like usual. We simply took care in the algorithms that they still
* work with the left child of 0 being 0 again. This was possible without
* any extra ifs or arithmetic.
* Thus we can save the wastage of 1 array position you can see in other
* implementations or the ugly (i+1)*2 - 1 and (i+1)*2 for calculating the
* left and right child. (At the expense that stuff easily breaks when you make
* changes and don't think that the left child of 0 is 0 :-/)
* @author matze
*
*/
typedef struct _pqueue_el_t {
void *data;
int key;
} pqueue_el_t;
struct _pqueue_t {
pqueue_el_t *elems;
};
/**
* Enforces the heap characteristics if the queue
* starting from element at position @p pos.
*/
static void pqueue_heapify(pqueue *q, int pos) {
int len = ARR_LEN(q->elems);
while (pos * 2 < len) {
pqueue_el_t tmp;
int exchange = pos;
if (q->elems[exchange].key < q->elems[pos * 2].key) {
exchange = pos * 2;
}
if ((pos * 2 + 1) < len && q->elems[exchange].key < q->elems[pos * 2 + 1].key) {
exchange = pos * 2 + 1;
}
if (exchange == pos)
break;
tmp = q->elems[pos];
q->elems[pos] = q->elems[exchange];
q->elems[exchange] = tmp;
pos = exchange;
}
}
/**
* Sifts up a newly inserted element at position @p pos.
*/
static void pqueue_sift_up(pqueue *q, int pos) {
while(q->elems[pos].key > q->elems[pos / 2].key) {
pqueue_el_t tmp;
tmp = q->elems[pos];
q->elems[pos] = q->elems[pos / 2];
q->elems[pos / 2] = tmp;
pos /= 2;
}
}
/**
* Creates a new priority queue.
* @return A priority queue of initial length 0.
*/
pqueue *new_pqueue() {
pqueue *res = xmalloc(sizeof(*res));
res->elems = NEW_ARR_F(pqueue_el_t, 0);
return res;
}
/**
* Frees all memory allocated by the priority queue.
* @param q The priority queue to destroy.
*/
void del_pqueue(pqueue *q) {
DEL_ARR_F(q->elems);
free(q);
}
/**
* Inserts a new element into a priority queue.
* @param q The priority queue the element should be inserted to.
* @param data The actual data which should be stored in the queue.
* @param key The priority for the data.
*/
void pqueue_put(pqueue *q, void *data, int key) {
pqueue_el_t el;
el.data = data;
el.key = key;
ARR_APP1(pqueue_el_t, q->elems, el);
pqueue_sift_up(q, ARR_LEN(q->elems));
}
/**
* Returns and removes the first element, ie. that one with the highest priority, from the queue.
* @param q The priority queue.
* @return The first element of the queue. Asserts if queue is empty.
*/
void *pqueue_get(pqueue *q) {
switch(ARR_LEN(q->elems)) {
case 0:
assert(0 && "Attempt to retrieve element from empty priority queue.");
return NULL;
break;
case 1:
ARR_SHRINKLEN(q->elems, 0);
return q->elems[0].data;
break;
default: {
void *data = q->elems[0].data;
int len = ARR_LEN(q->elems) - 1;
q->elems[0] = q->elems[len];
ARR_SHRINKLEN(q->elems, len);
pqueue_heapify(q, 0);
return data;
}
}
}
/**
* Get the length of the priority queue.
* @param q The priority queue.
* @return The length of the queue.
*/
int pqueue_length(pqueue *q) {
return ARR_LEN(q->elems);
}
/**
* Returns true if queue is empty.
* @param q The priority queue.
* @return 1 if the queue is empty, 0 otherwise.
*/
int pqueue_empty(pqueue *q) {
return ARR_LEN(q->elems) == 0;
}
/**
* @file pqueue.h
* @date 18.04.2007
* @author Christian Wuerdig
* @brief Implementation of a priority queue. This is the ported version of the
* original Java implementation by Matthias Braun.
* @version $Id$
*/
#ifndef _PQUEUE_H_
#define _PQUEUE_H_
typedef struct _pqueue_t pqueue;
/**
* Creates a new priority queue.
* @return A priority queue of initial length 0.
*/
pqueue *new_pqueue();
/**
* Frees all memory allocated by the priority queue.
* @param q The priority queue to destroy.
*/
void del_pqueue(pqueue *q);
/**
* Inserts a new element into a priority queue.
* @param q The priority queue the element should be inserted to.
* @param data The actual data which should be stored in the queue.
* @param key The priority for the data.
*/
void pqueue_put(pqueue *q, void *data, int key);
/**
* Returns and removes the first element, ie. that one with the highest priority, from the queue.
* @param q The priority queue.
* @return The first element of the queue. Asserts if queue is empty.
*/
void *pqueue_get(pqueue *q);
/**
* Get the length of the priority queue.
* @param q The priority queue.
* @return The length of the queue.
*/
int pqueue_length(pqueue *q);
/**
* Returns true if queue is empty.
* @param q The priority queue.
* @return 1 if the queue is empty, 0 otherwise.
*/
int pqueue_empty(pqueue *q);
#endif /* _PQUEUE_H_ */
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment