Skip to content

Commit

Permalink
dttools: priority queue data structure fix (#4042)
Browse files Browse the repository at this point in the history
* init

* enqueue on priority update

* lint
  • Loading branch information
JinZhou5042 authored Feb 5, 2025
1 parent 8c9088e commit 23059fd
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 43 deletions.
71 changes: 43 additions & 28 deletions dttools/src/priority_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ See the file COPYING for details.
#include <float.h>

#define DEFAULT_CAPACITY 127
#define MAX_PRIORITY DBL_MAX
#define MIN_PRIORITY DBL_MIN

struct element {
void *data;
Expand All @@ -27,8 +25,8 @@ struct priority_queue {
struct element **elements;

/* The following three cursors are used to iterate over the elements in the numerical order they are stored in the array, which is
different from the order of priorities. Each of them has different concerns when traverse the queue Though the tipical priority-based
traversal is done by the repeated invocation of priority_queue_peak_top and priority_queue_pop APIs, rather than using any cursors. */
different from the order of priorities. Each of them has different concerns when traverse the queue Though the typical priority-based
traversal is done by the repeated invocation of priority_queue_peek_top and priority_queue_pop APIs, rather than using any cursors. */
int base_cursor; // Used in PRIORITY_QUEUE_BASE_ITERATE. It iterates from the first position and never be reset automatically.
int static_cursor; // Used in PRIORITY_QUEUE_STATIC_ITERATE. It iterates from the last position and never be reset automatically.
int rotate_cursor; // Used in PRIORITY_QUEUE_ROTATE_ITERATE. It iterates from the last position and can be reset when certain events happen.
Expand Down Expand Up @@ -101,7 +99,7 @@ static int priority_queue_double_capacity(struct priority_queue *pq)

/****** External Methods ******/

struct priority_queue *priority_queue_create(double init_capacity)
struct priority_queue *priority_queue_create(int init_capacity)
{
struct priority_queue *pq = (struct priority_queue *)malloc(sizeof(struct priority_queue));
if (!pq) {
Expand Down Expand Up @@ -142,17 +140,17 @@ int priority_queue_size(struct priority_queue *pq)
int priority_queue_push(struct priority_queue *pq, void *data, double priority)
{
if (!pq) {
return 0;
return -1;
}

if (pq->size >= pq->capacity) {
if (!priority_queue_double_capacity(pq)) {
return 0;
return -1;
}
}
struct element *e = (struct element *)malloc(sizeof(struct element));
if (!e) {
return 0;
return -1;
}
e->data = data;
e->priority = priority;
Expand Down Expand Up @@ -185,7 +183,7 @@ void *priority_queue_pop(struct priority_queue *pq)
return data;
}

void *priority_queue_peak_top(struct priority_queue *pq)
void *priority_queue_peek_top(struct priority_queue *pq)
{
if (!pq || pq->size == 0) {
return NULL;
Expand All @@ -203,7 +201,7 @@ double priority_queue_get_priority(struct priority_queue *pq, int idx)
return pq->elements[idx]->priority;
}

void *priority_queue_peak_at(struct priority_queue *pq, int idx)
void *priority_queue_peek_at(struct priority_queue *pq, int idx)
{
if (!pq || pq->size < 1 || idx < 0 || idx > pq->size - 1) {
return NULL;
Expand All @@ -215,7 +213,7 @@ void *priority_queue_peak_at(struct priority_queue *pq, int idx)
int priority_queue_update_priority(struct priority_queue *pq, void *data, double new_priority)
{
if (!pq) {
return 0;
return -1;
}

int idx = -1;
Expand All @@ -226,8 +224,9 @@ int priority_queue_update_priority(struct priority_queue *pq, void *data, double
}
}

/* If the data isn’t already in the queue, enqueue it. */
if (idx == -1) {
return 0;
return priority_queue_push(pq, data, new_priority);
}

double old_priority = pq->elements[idx]->priority;
Expand All @@ -247,7 +246,7 @@ int priority_queue_update_priority(struct priority_queue *pq, void *data, double
int priority_queue_find_idx(struct priority_queue *pq, void *data)
{
if (!pq) {
return 0;
return -1;
}

for (int i = 0; i < pq->size; i++) {
Expand All @@ -256,13 +255,13 @@ int priority_queue_find_idx(struct priority_queue *pq, void *data)
}
}

return 0;
return -1;
}

int priority_queue_static_next(struct priority_queue *pq)
{
if (!pq || pq->size == 0) {
return 0;
return -1;
}

int static_idx = pq->static_cursor;
Expand Down Expand Up @@ -291,7 +290,7 @@ Advance the base cursor and return it, should be used only in PRIORITY_QUEUE_BAS
int priority_queue_base_next(struct priority_queue *pq)
{
if (!pq || pq->size == 0) {
return 0;
return -1;
}

int base_idx = pq->base_cursor;
Expand All @@ -316,7 +315,7 @@ void priority_queue_rotate_reset(struct priority_queue *pq)
int priority_queue_rotate_next(struct priority_queue *pq)
{
if (!pq || pq->size == 0) {
return 0;
return -1;
}

int rotate_idx = pq->rotate_cursor;
Expand All @@ -335,26 +334,40 @@ int priority_queue_remove(struct priority_queue *pq, int idx)
return 0;
}

struct element *e = pq->elements[idx];
pq->size--;
pq->elements[idx] = pq->elements[pq->size];
pq->elements[pq->size] = NULL;
struct element *to_delete = pq->elements[idx];
struct element *last_elem = pq->elements[pq->size - 1];

double old_priority = to_delete->priority;
double new_priority = last_elem->priority;

sink(pq, idx);
free(to_delete);

if (pq->static_cursor == idx) {
pq->size--;
if (idx != pq->size) {
pq->elements[idx] = last_elem;
pq->elements[pq->size] = NULL;

if (new_priority > old_priority) {
swim(pq, idx);
} else if (new_priority < old_priority) {
sink(pq, idx);
}
} else {
pq->elements[pq->size] = NULL;
}

if (pq->static_cursor == idx && pq->static_cursor > 0) {
pq->static_cursor--;
}
if (pq->base_cursor == idx) {
if (pq->base_cursor == idx && pq->base_cursor > 0) {
pq->base_cursor--;
}
if (pq->rotate_cursor == idx) {
if (pq->rotate_cursor == idx && pq->rotate_cursor > 0) {
pq->rotate_cursor--;
}
free(e);

// reset the rotate cursor if the removed element is before/equal to it
if (idx <= pq->rotate_cursor) {
// reset the rotate cursor if the removed element is before/equal to it
priority_queue_rotate_reset(pq);
}

Expand All @@ -368,7 +381,9 @@ void priority_queue_delete(struct priority_queue *pq)
}

for (int i = 0; i < pq->size; i++) {
free(pq->elements[i]);
if (pq->elements[i]) {
free(pq->elements[i]);
}
}
free(pq->elements);
free(pq);
Expand Down
24 changes: 12 additions & 12 deletions dttools/src/priority_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ void *data = someDataPointer;
priority_queue_push(pq, data, priority);
data = priority_queue_pop(pq);
void *headData = priority_queue_peak_top(pq);
void *headData = priority_queue_peek_top(pq);
</pre>
To list all of the items in a priority queue, use a simple loop:
<pre>
for (int i = 0; i < priority_queue_size(pq); i++) {
void *data = priority_queue_peak_at(pq, i);
void *data = priority_queue_peek_at(pq, i);
printf("Priority queue contains: %p\n", data);
}
</pre>
Expand All @@ -94,7 +94,7 @@ Element with a higher priority is at the top of the heap.
@param init_capacity The initial number of elements in the queue. If zero, a default value will be used.
@return A pointer to a new priority queue.
*/
struct priority_queue *priority_queue_create(double init_capacity);
struct priority_queue *priority_queue_create(int init_capacity);

/** Count the elements in a priority queue.
@param pq A pointer to a priority queue.
Expand Down Expand Up @@ -122,15 +122,15 @@ Similar to @ref priority_queue_pop, but the element is not removed.
@param pq A pointer to a priority queue.
@return The pointer to the top of the queue if any, failure otherwise
*/
void *priority_queue_peak_top(struct priority_queue *pq);
void *priority_queue_peek_top(struct priority_queue *pq);

/** Get an element from a priority queue by a specified index.
The first accessible element is at index 0.
@param pq A pointer to a priority queue.
@param index The index of the element to get.
@return The pointer to the element if any, failure otherwise
*/
void *priority_queue_peak_at(struct priority_queue *pq, int index);
void *priority_queue_peek_at(struct priority_queue *pq, int index);

/** Get the priority of an element at a specified index.
@param pq A pointer to a priority queue.
Expand All @@ -150,15 +150,15 @@ int priority_queue_update_priority(struct priority_queue *pq, void *data, double
/** Find the index of an element in a priority queue.
@param pq A pointer to a priority queue.
@param data The pointer to the element to find.
@return The index of the element if found, 0 on failure.
@return The index of the element if found, -1 on failure.
*/
int priority_queue_find_idx(struct priority_queue *pq, void *data);

/** Advance the static_cursor to the next element and return the index.
The static_cursor is used to globally iterate over the elements by sequential index.
The position of the static_cursor is automatically remembered and never reset.
@param pq A pointer to a priority queue.
@return The index of the next element if any, 0 on failure.
@return The index of the next element if any, -1 on failure.
*/
int priority_queue_static_next(struct priority_queue *pq);

Expand All @@ -170,7 +170,7 @@ void priority_queue_base_reset(struct priority_queue *pq);

/** Advance the base_cursor to the next element and return the index.
@param pq A pointer to a priority queue.
@return The index of the next element if any, 0 on failure.
@return The index of the next element if any, -1 on failure.
*/
int priority_queue_base_next(struct priority_queue *pq);

Expand All @@ -185,7 +185,7 @@ void priority_queue_rotate_reset(struct priority_queue *pq);

/** Advance the rotate_cursor to the next element and return the index.
@param pq A pointer to a priority queue.
@return The index of the next element if any, 0 on failure.
@return The index of the next element if any, -1 on failure.
*/
int priority_queue_rotate_next(struct priority_queue *pq);

Expand Down Expand Up @@ -235,16 +235,16 @@ PRIORITY_QUEUE_ROTATE_ITERATE( pq, idx, data, iter_count, iter_depth ) {
#define PRIORITY_QUEUE_BASE_ITERATE( pq, idx, data, iter_count, iter_depth ) \
iter_count = 0; \
priority_queue_base_reset(pq); \
while ((iter_count < iter_depth) && ((idx = priority_queue_base_next(pq)) >= 0) && (data = priority_queue_peak_at(pq, idx)) && (iter_count += 1))
while ((iter_count < iter_depth) && ((idx = priority_queue_base_next(pq)) >= 0) && (data = priority_queue_peek_at(pq, idx)) && (iter_count += 1))

/* Iterate from last position, never reset. */
#define PRIORITY_QUEUE_STATIC_ITERATE( pq, idx, data, iter_count, iter_depth ) \
iter_count = 0; \
while ((iter_count < iter_depth) && ((idx = priority_queue_static_next(pq)) >= 0) && (data = priority_queue_peak_at(pq, idx)) && (iter_count += 1))
while ((iter_count < iter_depth) && ((idx = priority_queue_static_next(pq)) >= 0) && (data = priority_queue_peek_at(pq, idx)) && (iter_count += 1))

/* Iterate from last position, reset to the begining when needed. */
#define PRIORITY_QUEUE_ROTATE_ITERATE( pq, idx, data, iter_count, iter_depth ) \
iter_count = 0; \
while ((iter_count < iter_depth) && ((idx = priority_queue_rotate_next(pq)) >= 0) && (data = priority_queue_peak_at(pq, idx)) && (iter_count += 1))
while ((iter_count < iter_depth) && ((idx = priority_queue_rotate_next(pq)) >= 0) && (data = priority_queue_peek_at(pq, idx)) && (iter_count += 1))

#endif
6 changes: 3 additions & 3 deletions dttools/src/priority_queue_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ int main()
}

// Get the head of the priority queue
char *head = (char *)priority_queue_peak_top(pq);
char *head = (char *)priority_queue_peek_top(pq);
if (head) {
printf("\nElement at the head of the queue: %s\n", head);
} else {
Expand All @@ -56,7 +56,7 @@ int main()

// Access an element by index
idx = 4;
char *element = (char *)priority_queue_peak_at(pq, idx);
char *element = (char *)priority_queue_peek_at(pq, idx);
if (element) {
printf("\nElement at index %d: %s\n", idx, element);
} else {
Expand Down Expand Up @@ -164,7 +164,7 @@ int main()

// Pop elements from the priority queue using priority_queue_pop
printf("\nPopping elements from the priority queue:\n");
while ((item = (char *)priority_queue_peak_top(pq)) != NULL) {
while ((item = (char *)priority_queue_peek_top(pq)) != NULL) {
printf("Popped element: %s Priority: %d\n", item, (int)priority_queue_get_priority(pq, 0));
priority_queue_pop(pq);
}
Expand Down

0 comments on commit 23059fd

Please sign in to comment.