在 C 中使用链表实现队列

Implement Queue using Linked List in C

提问人:ahnherin092 提问时间:11/13/2023 更新时间:11/13/2023 访问量:62

问:

此代码用于使用链表在 C 语言中实现队列和一些操作。我得到了意想不到的输出,尤其是“删除前面项目后:”一行,但我不知道为什么。

这是我的代码:

// C program to implement linked list queue
#include <stdio.h>
#include <stdlib.h>

// Define a queue using linked list
typedef struct _Node {
    int data;
    struct _Node *next;
}Node;

typedef struct _Queue {
    Node *pFront, *pBack;
    int size;
}Queue;

// Initialize queue
Queue *init (void) {
    Queue *q = malloc(sizeof(*q));
    if (q) {
    q->size = 0;
    q->pFront = q->pBack = NULL;
    }
    return q;
}

// Check if queue is empty
int isEmpty (Queue q) {
    return (q.pFront == NULL);
}

// Length of train
int Length(Queue *q) {
    return q->size;
}

// Add new item
void enqueue (Queue *q, int val)
{
    Node *p = (Node*)malloc(sizeof(Node));
    p->data = val;
    p->next = NULL;

    // If queue is empty
    if (q->pFront == NULL)
        q->pFront = q->pBack = p;

    // If queue has at least 1 element
    else {
        p->next = q->pBack;
        q->pBack = p;
    }
    q->size++;
}

// Remove item
int dequeue (Queue *q)
{
    if (isEmpty(*q))
        return 0;
    else {
        if (q->size == 1) {
            q->pFront = q->pBack = NULL;
            q->size--;
        }
        else {
            Node *p = q->pBack;
            while (p->next != q->pFront)
                p = p->next;
            q->pFront = p;
            q->pFront->next = NULL;
            q->size--;
        }
    }
    return 1;
}

// Display queue
void display(Queue *q) {
    Node *p = q->pBack;
    while (p != NULL) {
        printf("%d\t", p->data);
        p = p->next;
    }
}

// Free all memory used by the stack
void freeMemory(Queue *q) {
    Node* p = q->pFront;
    Node* next;

    while (p != NULL) {
        next = p->next;
        free(p);
        p = next;
    }

    q->pFront = NULL;
    q->size = 0;
}

int main()
{
    Queue *q;
    q = init();
    if (q)
    {
    enqueue(q, 10);
    enqueue(q, 20);
    enqueue(q, 30);
    printf("Queue:\n");
    display(q);

    printf("\nAfter removing front item: %d", dequeue(q));
    display(q);

    printf("\nLength of the queue after all modification: %d", Length(q));

    freeMemory(q);
    return 0;
    }
}

意外输出: ** 队列: 10 20 30 移除前项后:110 20 所有修改后的队列长度:2 **

c 链接列表 队列 输出

评论

1赞 0___________ 11/13/2023
太复杂了。我将使用两个单独的指针 - 和 .您仅从 .无需遍历。headtailheadtail
0赞 John Bollinger 11/13/2023
我同意,@0____,但值得一提的是,避免以这种方式遍历列表需要双链表,而 OP 目前使用的是单链表。
0赞 John Bollinger 11/13/2023
函数需要从后面开始,而不是从前面开始,完成后,它也需要将队列的后退指针设置为 null。freeMemory()
0赞 John Bollinger 11/13/2023
代码都是你自己的作品吗?这在风格上不一致足以让我感到疑惑。
0赞 0___________ 11/13/2023
@JohnBollinger不,它不需要。

答:

2赞 John Bollinger 11/13/2023 #1

您的输出误导了您,因为您没有始终如一地在末尾打印换行符。特别是这里:

    printf("\nAfter removing front item: %d", dequeue(q));
    display(q);

...打印返回值 (Always 1 或 0),然后打印其余队列项的值,不带任何前导空格。你dequeue()

110 20

因此可以分解为 1(返回值)、10(队列项)、20(队列项)。dequeue()

这是错误的,因为第一个出列的项目应该是第一个入队的项目 (10)。但是,这不是您的程序为我打印的内容。当我运行你的程序时,我得到

After removing front item: 130  20
Length of the queue after all modification: 2

这显示已删除正确的项目。但是,我幼稚的期望是队列将按照元素出列的顺序打印,这与程序发出的顺序相反。

至少,将那些缺少的换行符添加到程序的输出中。还要验证所需的输出顺序,并在需要时进行修复。display()

0赞 storsan 11/21/2023 #2

只是在前面的答案上加一点......

将项目排队到队列中时,您将添加到队列的后面,根据 FIFO 原则,这是正确的。Node

但是,当从队列中取出 时,代码无法直接删除当前位于队列前面的节点。随着指针指向的方向,输入的代码需要从队列的后面开始,并遍历整个节点链表以到达队列的前面。如果队列前面的节点在 O(1) 时间内直接访问并删除,那将是一个更好的实现,但在当前 OP 提交的代码中,不能将其设置为指向 FIFO 列表中的下一个节点,因为当前从 FIFO 列表前面删除的节点没有指向其前一个节点的指针( 对于前面的节点是始终为 NULL)。Nodenextdequeue()pFrontpFrontpFront->next

此外,由于每个节点的指针指向的方向,该函数只能从队列的后面打印到前面,而不能从队列的前面打印到后面。nextdisplay()

您还应该在函数中将单个节点出列时释放每个单独节点项的内存,否则对于已出列的节点,您就会发生内存泄漏,因为您只是在调用程序时释放队列中剩余的节点。dequeue()freeMemory()