繁体   English   中英

在 C 中使用链表实现队列

[英]Implementing Queue using Linked list in C

我正在尝试使用链表实现队列。 这是我的程序

#include <stdio.h>
#include <stdlib.h>

struct queue_struct{
    int ele;
    struct queue_struct *next;
};

struct Queue{
    struct queue_struct *front, *rear;
};

int isEmpty(struct Queue *q){
    return (q->front==NULL||q->rear==NULL);
}

void enqueue(struct Queue *q, int x){
    struct queue_struct *temp=(struct queue_struct *)malloc(sizeof(struct queue_struct));
    temp->ele=x;
    temp->next=NULL;
    if(isEmpty(q)){
        q->front=q->rear=temp;
        return;
    }
    q->rear=temp;
    printf("The item %d has been enqueued into the queue\n", x);
}

void dequeue(struct Queue *q){
    if(isEmpty(q)){
        printf("The queue is already empty. No more elements can be removed!\n");
        return;
    }
    struct queue_struct *temp=q->front;
    printf("The item %d has been dequeued from the queue\n", temp->ele);
    q->front=q->front->next;
    if(q->front=NULL)
        q->rear=NULL;
    free(temp);
}

void display(struct Queue *q){
    struct queue_struct *temp=q->front;
    int len;
    printf("The contents of the queue are:\n");
    if(isEmpty(q)){
        printf("Nothing to be shown, the queue is empty.\n");
        return;
    }
    while(temp!=NULL){
        temp=temp->next;
        len++;
    }
    temp=q->front;
    for(int i=1;i<len-1;i++){
        printf("|  %d  |\n", temp->ele);
        printf(" ------ \n");
        temp=temp->next;
    }
    printf("|  %d  |\n", temp->ele);
}

int main()
{
    int choice, element;
    printf("LET'S START WITH AN EMPTY QUEUE\n\n");
    struct Queue *q=(struct Queue *)malloc(sizeof(struct Queue));
    q->front=q->rear=NULL;
    while(1){
        printf("\nMENU\n");
        printf("----\n");
        printf("\t1. Enqueue\n");
        printf("\t2. Dequeue\n");
        printf("\t3. Display queue\n");
        printf("\t4. Exit\n");
        printf("Enter your choice: ");
        scanf("%d", &choice);
        switch(choice){
            case 1: printf("Enter the element to be enqueued: ");
                    scanf("%d", &element);
                    enqueue(q, element);
                    break;
            case 2: dequeue(q);
                    break;
            case 3: display(q);
                    break;
            case 4: printf("Program terminated successfully!\n");
                    return 0;
            default: printf("Invalid input");
        }
    }
}

但是,当我尝试将元素排入队列时,我遇到了分段错误

经过调试,我发现我的 isEmpty() function 是罪魁祸首,但我似乎找不到问题所在。 考虑到问题的性质,我认为前面或后面应该是 NULL 队列为空。 我的理解错了吗? 任何帮助表示赞赏。

编辑
正如@interjay 所建议的,我对main()方法的q=NULL部分进行了更改。 但是,我的display方法现在出错了。 我不明白为什么。

有一些问题。

main中,做q = NULL; 是 memory 泄漏,会产生段错误。 初始化空队列的正确方法是:

q->front = NULL;
q->rear = NULL;

队列显示使用while循环来查找队列的末尾,从而保证了在随后for循环(即segfault)中tempNULL 只需要for循环

enqueue无法正确处理附加到非空列表。

dequeue有一个 if 语句,它使用赋值运算符if (q->front = NULL)而不是相等运算符if (q->front == NULL) 但是,即使进行了该修复,它仍然无法正确处理操作。

isEmpty function 与其他功能真的没什么用,因为他们可以/应该只检查front

不要malloc的返回值。 请参阅: 我是否会转换 malloc 的结果? 进行演员表可能会引入微妙的、难以发现的错误。


这是修复问题的重构版本。 我对一些struct名称进行了一些清理/重命名,以便对 function 更具描述性。

在下面的代码中,我使用cpp条件来显示更改(例如):

#if 0
// old code
#else
// new code
#endif

我已经尽可能地注释了错误:

#include <stdio.h>
#include <stdlib.h>

typedef struct queue_element QElement;
struct queue_element {
    int ele;
    QElement *next;
};

typedef struct Queue {
    QElement *front, *rear;
} Queue;

int
isEmpty(Queue *q)
{
    return (q->front == NULL || q->rear == NULL);
}

void
enqueue(Queue *q, int x)
{
    QElement *temp = malloc(sizeof(*temp));

    temp->ele = x;
    temp->next = NULL;

// NOTE/BUG: this does _not_ append correctly to a non-empty list
#if 0
    if (isEmpty(q)) {
        q->front = q->rear = temp;
        return;
    }

    q->rear = temp;
#else
    // link old rear node to new node
    if (q->rear != NULL)
        q->rear->next = temp;

    // set new rear node
    q->rear = temp;

    // set the front of the list if it was empty
    if (q->front == NULL)
        q->front = temp;
#endif

    printf("The item %d has been enqueued into the queue\n", x);
}

void
dequeue(Queue *q)
{
    QElement *temp = q->front;

    if (temp == NULL) {
        printf("The queue is already empty. No more elements can be removed!\n");
        return;
    }

    printf("The item %d has been dequeued from the queue\n", temp->ele);

    q->front = temp->next;
    if (q->rear == temp)
        q->rear = NULL;

    free(temp);
}

void
dequeue_OLD(Queue *q)
{
    if (isEmpty(q)) {
        printf("The queue is already empty. No more elements can be removed!\n");
        return;
    }
    QElement *temp = q->front;

    printf("The item %d has been dequeued from the queue\n", temp->ele);
    q->front = q->front->next;
// NOTE/BUG: this if is invalid -- it is using the assignment operator in
// place of the [desired] equality operator
// NOTE/BUG: even with this fix, the dequeue is still broken -- see the fix
// above
#if 0
    if (q->front = NULL)
        q->rear = NULL;
#else
    if (q->front == NULL)
        q->rear = NULL;
#endif
    free(temp);
}

void
display(Queue *q)
{
    QElement *temp = q->front;

    printf("The contents of the queue are:\n");

    if (temp == NULL) {
        printf("Nothing to be shown, the queue is empty.\n");
        return;
    }

// NOTE/BUG: doing the while loop ensures that temp will be NULL so that the
// for loop will try to dereference temp and it will segfault
#if 0
    int len;
    while (temp != NULL) {
        temp = temp->next;
        len++;
    }
    for (int i = 1; i < len - 1; i++) {
        printf("|  %d  |\n", temp->ele);
        printf(" ------ \n");
        temp = temp->next;
    }
    printf("|  %d  |\n", temp->ele);
#else
    int sep = 0;
    for (;  temp != NULL;  temp = temp->next) {
        if (sep)
            printf(" ------ \n");
        sep = 1;
        printf("|  %d  |\n", temp->ele);
    }
#endif
}

int
main(void)
{
    int choice, element;

    printf("LET'S START WITH AN EMPTY QUEUE\n\n");
    Queue *q = malloc(sizeof(*q));
// NOTE/BUG: setting q to NULL ensures a segfault and is a memory leak
#if 0
    q = NULL;
#else
    q->front = NULL;
    q->rear = NULL;
#endif

    while (1) {
        printf("\nMENU\n");
        printf("----\n");
        printf("\t1. Enqueue\n");
        printf("\t2. Dequeue\n");
        printf("\t3. Display queue\n");
        printf("\t4. Exit\n");
        printf("Enter your choice: ");
        scanf("%d", &choice);
        switch (choice) {
        case 1:
            printf("Enter the element to be enqueued: ");
            scanf("%d", &element);
            enqueue(q, element);
            break;
        case 2:
            dequeue(q);
            break;
        case 3:
            display(q);
            break;
        case 4:
            printf("Program terminated successfully!\n");
            return 0;
        default:
            printf("Invalid input");
            break;
        }
    }

    return 0;
}

有以下问题:

  • 您不应该将NULL分配给q ,因为这是指向您刚刚分配的rear的指针,并且它包含指针front和 back ,即使队列为空,您也将始终需要它们。 相反,您应该将这些front指针NULL rear

     q->front = q->rear = NULL;
  • dequeue中,你在if条件中有一个赋值,你实际上想要一个compare 改变这个:

     if(q->front=NULL)

    至:

     if(q->front==NULL)
  • display中,您在第一个循环之后取消引用temp ,您确定它实际上是NULL 所以这将引发一个异常。 你应该只有一个循环。 任何尝试使用相同的temp指针在列表上再次循环都需要将temp指针重置为front 这是您的display function 的简单替换:

     void display(struct Queue *q){ struct queue_struct *temp=q->front; printf("The contents of the queue are:\n"); if(isEmpty(q)){ printf("Nothing to be shown, the queue is empty.\n"); return; } while(temp,=NULL){ printf("%d->"; temp->ele); temp=temp->next; } printf("NULL\n"); }

    如果您还希望显示i计数器,则只需在上面的同一循环中递增它。

通过这些更改,您的代码将起作用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM