Вы не инициализируете head
и tail
до NULL
в make_queue
, и у вас неверный тест на пустоту,
bool is_empty_queue(queue q) {
if(q->head)
return 1;
return 0;
}
, что заставляет enqueue
вести себя странно.
void enqueue(void *value, queue q) {
struct node * newNode = (struct node *)malloc(sizeof(struct node));
newNode->data = value;
if(is_empty_queue(q))
q->tail = newNode;
newNode->next = q->head;
q->head = newNode;
}
Случай 1, случайность head
и tail
равны NULL
изначально
head -> 0; tail -> 0 // now enqueue 1
is_empty_queue(q) returns 0 since q->head == NULL, so q->tail still points to 0
n(1)->next = 0
head = n(1)
results in
head -> n(1) -> 0; tail -> 0 // next enqueue 2
is_empty_queue(q) returns 1 since q->head = n(1) != 0, so
q->tail = n(2)
n(2)->next = n(1)
q->head = n(2)
result:
head -> n(2) -> n(1) -> 0; tail -> n(2)
и все дальнейшие enqueue
операции уйдут head == tail
. Но если вы сейчас dequeue
:
struct node * to_dequeue = q->tail; // n(2)
void * data = q->tail->data;
struct node * trace = q->head; // n(2)
while(trace->next && trace->next != q->tail) // n(2) -> n(1) -> 0
trace = trace->next; // trace = n(1)
free(to_dequeue); // free n(2)
q->tail = trace; // tail -> n(1)
q->tail->next = NULL; // already had that
и head
- висячий указатель.
Случай 2, случайность head
изначально не NULL
.
head -> x; tail -> y // enqueue 1
is_empty_queue(q) returns 1 because q->head == x != 0
q->tail = n(1)
n(1)->next = x
q->head = n(1)
head -> n(1) -> x; tail -> n(1) // now enqueue 2
is_empty_queue(q) returns 1 because q->head == n(1)
q->tail = n(2)
n(2)->next = n(1)
q->head = n(2)
head -> n(2) -> n(1) -> x; tail -> n(2)
Единственное отличие состоит в том, что теперь n(1)->next != 0
, тогда, если вы удаляете из очереди, trace
будет установлен в дикий 'указатель' x
, а затем проверяется x->next
, но поскольку x
был неопределенным битом шаблон, который часто вызывает segfault.
Если я что-то упустил, инициализация head
и tail
на конструкции, исправление is_empty_queue
и проверка на пустоту на dequeue
даст вам рабочую программу.
Но если очередь длинная, операция удаления медленная, так как она должна пройти всю очередь, чтобы найти предпоследний элемент для обновления tail
. Вы можете выполнять операции enqueue
и dequeue
, O (1), если ставите в очередь в позиции tail
и dequeue
с head
.