commit
7b2ccbde29
@ -0,0 +1,107 @@
|
|||||||
|
#include "heap.h"
|
||||||
|
|
||||||
|
/* Byte-wise swap two items of size SIZE. */
|
||||||
|
#define SWAP(a, b, size) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
register size_t __size = (size); \
|
||||||
|
register char *__a = (a), *__b = (b); \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
char __tmp = *__a; \
|
||||||
|
*__a++ = *__b; \
|
||||||
|
*__b++ = __tmp; \
|
||||||
|
} while (--__size > 0); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
inline char *__vector_GetPtr(Vector *v, size_t pos) {
|
||||||
|
return v->data + (pos * v->elemSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __sift_up(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *)) {
|
||||||
|
size_t len = last - first;
|
||||||
|
if (len > 1) {
|
||||||
|
len = (len - 2) / 2;
|
||||||
|
size_t ptr = first + len;
|
||||||
|
if (cmp(__vector_GetPtr(v, ptr), __vector_GetPtr(v, --last)) < 0) {
|
||||||
|
char t[v->elemSize];
|
||||||
|
memcpy(t, __vector_GetPtr(v, last), v->elemSize);
|
||||||
|
do {
|
||||||
|
memcpy(__vector_GetPtr(v, last), __vector_GetPtr(v, ptr), v->elemSize);
|
||||||
|
last = ptr;
|
||||||
|
if (len == 0)
|
||||||
|
break;
|
||||||
|
len = (len - 1) / 2;
|
||||||
|
ptr = first + len;
|
||||||
|
} while (cmp(__vector_GetPtr(v, ptr), t) < 0);
|
||||||
|
memcpy(__vector_GetPtr(v, last), t, v->elemSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __sift_down(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *), size_t start) {
|
||||||
|
// left-child of __start is at 2 * __start + 1
|
||||||
|
// right-child of __start is at 2 * __start + 2
|
||||||
|
size_t len = last - first;
|
||||||
|
size_t child = start - first;
|
||||||
|
|
||||||
|
if (len < 2 || (len - 2) / 2 < child)
|
||||||
|
return;
|
||||||
|
|
||||||
|
child = 2 * child + 1;
|
||||||
|
|
||||||
|
if ((child + 1) < len && cmp(__vector_GetPtr(v, first + child), __vector_GetPtr(v, first + child + 1)) < 0) {
|
||||||
|
// right-child exists and is greater than left-child
|
||||||
|
++child;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we are in heap-order
|
||||||
|
if (cmp(__vector_GetPtr(v, first + child), __vector_GetPtr(v, start)) < 0)
|
||||||
|
// we are, __start is larger than it's largest child
|
||||||
|
return;
|
||||||
|
|
||||||
|
char top[v->elemSize];
|
||||||
|
memcpy(top, __vector_GetPtr(v, start), v->elemSize);
|
||||||
|
do {
|
||||||
|
// we are not in heap-order, swap the parent with it's largest child
|
||||||
|
memcpy(__vector_GetPtr(v, start), __vector_GetPtr(v, first + child), v->elemSize);
|
||||||
|
start = first + child;
|
||||||
|
|
||||||
|
if ((len - 2) / 2 < child)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// recompute the child based off of the updated parent
|
||||||
|
child = 2 * child + 1;
|
||||||
|
|
||||||
|
if ((child + 1) < len && cmp(__vector_GetPtr(v, first + child), __vector_GetPtr(v, first + child + 1)) < 0) {
|
||||||
|
// right-child exists and is greater than left-child
|
||||||
|
++child;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we are in heap-order
|
||||||
|
} while (cmp(__vector_GetPtr(v, first + child), top) >= 0);
|
||||||
|
memcpy(__vector_GetPtr(v, start), top, v->elemSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Make_Heap(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *)) {
|
||||||
|
if (last - first > 1) {
|
||||||
|
// start from the first parent, there is no need to consider children
|
||||||
|
for (int start = (last - first - 2) / 2; start >= 0; --start) {
|
||||||
|
__sift_down(v, first, last, cmp, first + start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void Heap_Push(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *)) {
|
||||||
|
__sift_up(v, first, last, cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void Heap_Pop(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *)) {
|
||||||
|
if (last - first > 1) {
|
||||||
|
SWAP(__vector_GetPtr(v, first), __vector_GetPtr(v, --last), v->elemSize);
|
||||||
|
__sift_down(v, first, last, cmp, first);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef __HEAP_H__
|
||||||
|
#define __HEAP_H__
|
||||||
|
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Make heap from range
|
||||||
|
* Rearranges the elements in the range [first,last) in such a way that they form a heap.
|
||||||
|
* A heap is a way to organize the elements of a range that allows for fast retrieval of the element with the highest
|
||||||
|
* value at any moment (with pop_heap), even repeatedly, while allowing for fast insertion of new elements (with
|
||||||
|
* push_heap).
|
||||||
|
* The element with the highest value is always pointed by first. The order of the other elements depends on the
|
||||||
|
* particular implementation, but it is consistent throughout all heap-related functions of this header.
|
||||||
|
* The elements are compared using cmp.
|
||||||
|
*/
|
||||||
|
void Make_Heap(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *));
|
||||||
|
|
||||||
|
|
||||||
|
/* Push element into heap range
|
||||||
|
* Given a heap in the range [first,last-1), this function extends the range considered a heap to [first,last) by
|
||||||
|
* placing the value in (last-1) into its corresponding location within it.
|
||||||
|
* A range can be organized into a heap by calling make_heap. After that, its heap properties are preserved if elements
|
||||||
|
* are added and removed from it using push_heap and pop_heap, respectively.
|
||||||
|
*/
|
||||||
|
void Heap_Push(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *));
|
||||||
|
|
||||||
|
|
||||||
|
/* Pop element from heap range
|
||||||
|
* Rearranges the elements in the heap range [first,last) in such a way that the part considered a heap is shortened
|
||||||
|
* by one: The element with the highest value is moved to (last-1).
|
||||||
|
* While the element with the highest value is moved from first to (last-1) (which now is out of the heap), the other
|
||||||
|
* elements are reorganized in such a way that the range [first,last-1) preserves the properties of a heap.
|
||||||
|
* A range can be organized into a heap by calling make_heap. After that, its heap properties are preserved if elements
|
||||||
|
* are added and removed from it using push_heap and pop_heap, respectively.
|
||||||
|
*/
|
||||||
|
void Heap_Pop(Vector *v, size_t first, size_t last, int (*cmp)(void *, void *));
|
||||||
|
|
||||||
|
#endif //__HEAP_H__
|
@ -0,0 +1,36 @@
|
|||||||
|
#include "priority_queue.h"
|
||||||
|
#include "heap.h"
|
||||||
|
|
||||||
|
PriorityQueue *__newPriorityQueueSize(size_t elemSize, size_t cap, int (*cmp)(void *, void *)) {
|
||||||
|
PriorityQueue *pq = malloc(sizeof(PriorityQueue));
|
||||||
|
pq->v = __newVectorSize(elemSize, cap);
|
||||||
|
pq->cmp = cmp;
|
||||||
|
return pq;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t Priority_Queue_Size(PriorityQueue *pq) {
|
||||||
|
return Vector_Size(pq->v);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Priority_Queue_Top(PriorityQueue *pq, void *ptr) {
|
||||||
|
return Vector_Get(pq->v, 0, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t __priority_Queue_PushPtr(PriorityQueue *pq, void *elem) {
|
||||||
|
size_t top = __vector_PushPtr(pq->v, elem);
|
||||||
|
Heap_Push(pq->v, 0, top, pq->cmp);
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Priority_Queue_Pop(PriorityQueue *pq) {
|
||||||
|
if (pq->v->top == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Heap_Pop(pq->v, 0, pq->v->top, pq->cmp);
|
||||||
|
pq->v->top--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Priority_Queue_Free(PriorityQueue *pq) {
|
||||||
|
Vector_Free(pq->v);
|
||||||
|
free(pq);
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef __PRIORITY_QUEUE_H__
|
||||||
|
#define __PRIORITY_QUEUE_H__
|
||||||
|
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
|
/* Priority queue
|
||||||
|
* Priority queues are designed such that its first element is always the greatest of the elements it contains.
|
||||||
|
* This context is similar to a heap, where elements can be inserted at any moment, and only the max heap element can be
|
||||||
|
* retrieved (the one at the top in the priority queue).
|
||||||
|
* Priority queues are implemented as Vectors. Elements are popped from the "back" of Vector, which is known as the top
|
||||||
|
* of the priority queue.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
Vector *v;
|
||||||
|
|
||||||
|
int (*cmp)(void *, void *);
|
||||||
|
} PriorityQueue;
|
||||||
|
|
||||||
|
/* Construct priority queue
|
||||||
|
* Constructs a priority_queue container adaptor object.
|
||||||
|
*/
|
||||||
|
PriorityQueue *__newPriorityQueueSize(size_t elemSize, size_t cap, int (*cmp)(void *, void *));
|
||||||
|
|
||||||
|
#define NewPriorityQueue(type, cap, cmp) __newPriorityQueueSize(sizeof(type), cap, cmp)
|
||||||
|
|
||||||
|
/* Return size
|
||||||
|
* Returns the number of elements in the priority_queue.
|
||||||
|
*/
|
||||||
|
size_t Priority_Queue_Size(PriorityQueue *pq);
|
||||||
|
|
||||||
|
/* Access top element
|
||||||
|
* Copy the top element in the priority_queue to ptr.
|
||||||
|
* The top element is the element that compares higher in the priority_queue.
|
||||||
|
*/
|
||||||
|
int Priority_Queue_Top(PriorityQueue *pq, void *ptr);
|
||||||
|
|
||||||
|
/* Insert element
|
||||||
|
* Inserts a new element in the priority_queue.
|
||||||
|
*/
|
||||||
|
size_t __priority_Queue_PushPtr(PriorityQueue *pq, void *elem);
|
||||||
|
|
||||||
|
#define Priority_Queue_Push(pq, elem) __priority_Queue_PushPtr(pq, &(typeof(elem)){elem})
|
||||||
|
|
||||||
|
/* Remove top element
|
||||||
|
* Removes the element on top of the priority_queue, effectively reducing its size by one. The element removed is the
|
||||||
|
* one with the highest value.
|
||||||
|
* The value of this element can be retrieved before being popped by calling Priority_Queue_Top.
|
||||||
|
*/
|
||||||
|
void Priority_Queue_Pop(PriorityQueue *pq);
|
||||||
|
|
||||||
|
/* free the priority queue and the underlying data. Does not release its elements if
|
||||||
|
* they are pointers */
|
||||||
|
void Priority_Queue_Free(PriorityQueue *pq);
|
||||||
|
|
||||||
|
#endif //__PRIORITY_QUEUE_H__
|
@ -0,0 +1,38 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "heap.h"
|
||||||
|
#include "assert.h"
|
||||||
|
|
||||||
|
int cmp(void *a, void *b) {
|
||||||
|
int *__a = (int *) a;
|
||||||
|
int *__b = (int *) b;
|
||||||
|
return *__a - *__b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int myints[] = {10, 20, 30, 5, 15};
|
||||||
|
Vector *v = NewVector(int, 5);
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
Vector_Push(v, myints[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Make_Heap(v, 0, v->top, cmp);
|
||||||
|
|
||||||
|
int n;
|
||||||
|
Vector_Get(v, 0, &n);
|
||||||
|
assert(30 == n);
|
||||||
|
|
||||||
|
Heap_Pop(v, 0, v->top, cmp);
|
||||||
|
v->top = 4;
|
||||||
|
Vector_Get(v, 0, &n);
|
||||||
|
assert(20 == n);
|
||||||
|
|
||||||
|
Vector_Push(v, 99);
|
||||||
|
Heap_Push(v, 0, v->top, cmp);
|
||||||
|
Vector_Get(v, 0, &n);
|
||||||
|
assert(99 == n);
|
||||||
|
|
||||||
|
Vector_Free(v);
|
||||||
|
printf("PASS!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
|||||||
|
#include <printf.h>
|
||||||
|
#include "assert.h"
|
||||||
|
#include "priority_queue.h"
|
||||||
|
|
||||||
|
int cmp(void* i1, void* i2) {
|
||||||
|
int *__i1 = (int*) i1;
|
||||||
|
int *__i2 = (int*) i2;
|
||||||
|
return *__i1 - *__i2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
PriorityQueue *pq = NewPriorityQueue(int, 10, cmp);
|
||||||
|
assert(0 == Priority_Queue_Size(pq));
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
Priority_Queue_Push(pq, i);
|
||||||
|
}
|
||||||
|
assert(5 == Priority_Queue_Size(pq));
|
||||||
|
|
||||||
|
Priority_Queue_Pop(pq);
|
||||||
|
assert(4 == Priority_Queue_Size(pq));
|
||||||
|
|
||||||
|
Priority_Queue_Push(pq, 10);
|
||||||
|
Priority_Queue_Push(pq, 20);
|
||||||
|
Priority_Queue_Push(pq, 15);
|
||||||
|
int n;
|
||||||
|
Priority_Queue_Top(pq, &n);
|
||||||
|
assert(20 == n);
|
||||||
|
|
||||||
|
Priority_Queue_Pop(pq);
|
||||||
|
Priority_Queue_Top(pq, &n);
|
||||||
|
assert(15 == n);
|
||||||
|
|
||||||
|
Priority_Queue_Free(pq);
|
||||||
|
printf("PASS!");
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue