使用链接列表的循环队列

时间:2015-01-18 14:38:07

标签: c linked-list queue circular-list circular-queue

我想使用链表创建一个循环队列,我也希望创建该数据结构(队列)的实例而不仅仅是一个队列,多个队列而不重复代码。这就是我想出来的......

#include <stdio.h>
#include <stdlib.h>
struct queue
{
    int info;
    struct queue *next;
    struct queue *front;
    struct queue *rear;
};
void create(struct queue **q)
{
    (*q)->next = 0;
    (*q)->front = 0;
    (*q)->rear = 0;
}
struct queue* makenode(int item){
    struct queue* p = (struct queue*)malloc(sizeof (struct queue));
    if (p) p->info = item;
    return p;
}
void addLast(struct queue **q, int item){
    struct queue* p = makenode(item);
    if ((*q)->front == NULL){

        (*q)->front = (*q)->rear = p;
        (*q)->front->next = (*q)->front;
        (*q)->rear->next = (*q)->rear;
    }
    else
    {
        (*q)->rear->next = p;
        p->next = (*q)->front;
        (*q)->rear = p;
    }
}
int delFirst(struct queue **q){

    struct queue *p = (*q)->front;

    if ((*q)->front == 0)
        printf("\nEmpty Queue\n");
    else
    {

        int temp = (*q)->front->info;
        if (((*q)->front->next) != ((*q)->front))
        {
            (*q)->front = (*q)->front->next;
            (*q)->rear->next = (*q)->front;
        }
        else
        {
            (*q)->front = 0;
        }
        return temp;
    }
    free(p);
}
void main()
{
    struct queue *premium, *normal;
    create(&premium);
    create(&normal);
    addLast(&premium, 5);
    addLast(&premium, 10);
    addLast(&normal, 20);
    addLast(&normal, 30);
    printf("%i\n", delFirst(&premium));
    printf("%i\n", delFirst(&premium));
    delFirst(&premium);
    printf("%i\n", delFirst(&normal));
    printf("%i\n", delFirst(&normal));
    delFirst(&normal);
    getch();
}

有什么好办法吗?我觉得我的代码很复杂。我是C编程的新手,我只学习了关于队列和链表的基础知识。所以我甚至不知道我的代码是100%正确还是优雅的代码。我使用DevC ++编译此代码工作正常,但是当我使用MS Visual Studio 2013编译它时,它给了我一个例外“访问违规写入位置....”所以我非常确定我的代码不是那么好。请帮助我出去了。谢谢

2 个答案:

答案 0 :(得分:3)

问题1:数据结构

你有一个结构,包含链表项(信息和下一个元素)和队列结构(前面和后面,对于所有元素应该是相同的。

我建议使用:

struct queue_item
{
    int info;
    struct queue_item *next;
};
struct queue
{
    struct queue_item *front;
    struct queue_item *rear;
};

问题2:队列创建

当您致电create()时,您传递的地址指针(例如premium)尚未初始化。它可以指向任何地方!肯定是无效的位置。它还没有指向队列。因此,当您执行(*q)->next = 0;之类的操作时,您会尝试覆盖非法位置。

根据上面提出的数据结构,我提出以下建议:

struct queue* create (struct queue *q)  /* q points to a queue already allocated, or it is NULL */ 
{
    if (q==NULL) 
       q = malloc(sizeof (struct queue)); 
    if (q) {
        q->front = 0;
        q->rear = 0;
    }
    return q; 
}

main()中,您可以选择:

struct queue *premium, normal;
premium = create(NULL);  /* allocate the queue structure */
create(&normal);         /* use an allocated structure */

问题3:节点指针未在节点创建时初始化

malloc()不会初始化它返回的内存。如果你没有初始化链接指针,那么这些指针实际上可能包含NULL之外的其他内容。

struct queue_item* makenode(int item){
    struct queue* p = (struct queue_item*)malloc(sizeof (struct queue_item));
    if (p) {
        p->info = item;
        p->next = NULL;   /* There is no link yet, so make it clear to avoid any surprises later. */
    }
    return p;
}

问题4:添加/删除项目时出现不一致

使用新的数据结构,您必须调整addLast()delFirst()。但它会更清晰,因为frontrear位于队列级别,next仅位于项目级别。

从签名中,可以避免双重间接,因为这些操作永远不会改变指向队列的指针:

void addLast(struct queue *q, int item);      
int delFirst(struct queue *q);

答案 1 :(得分:1)

您的第一个问题是您在未初始化的指针上调用create()

void create(struct queue **q)
{
    (*q)->next = 0;
    …
}

int main()
{
    struct queue *premium, *normal;
    create(&premium);
    create(&normal);

您需要在makenode()函数或create()内调用main(),或者您需要提供premiumnormal的结构以指向

选项A:

void create(struct queue **q)
{
    *q = makenode(0);
    if (*q != 0)
    {
        (*q)->next = 0;
        …
    }
}

选项B:

int main()
{
    struct queue q_premium, q_normal;
    struct queue *premium = &q_premium;
    struct queue *normal  = &q_normal;
    create(&premium);
    create(&normal);

任何一种技术都可以使用,但是选项B需要小心,因为结构q_premiumq_normal没有被分配(尽管它们可能是必要的)。但是,create()的签名表明选项A是预期的,因为选项B确实不需要create()中的双指针。

我不清楚,如果有的话,三个指针 - frontrearnext的组合会对你的结构有所帮助。为了自己的利益,我实现了一个循环DLL,只是为了看看可能涉及的内容,我只需要一个数据指针以及下一个和前一个指针。从列表中的任何元素,您都可以访问列表中的每个其他元素。您可以在给定节点之前或之后插入,删除给定节点,将函数应用于所有节点,或查找与函数提供的谓词匹配的第一个节点(并获取下一个节点,上一个节点或数据),或者销毁整个清单。

我的印象是,如果没有指针,您的代码会更简单。

随着选项A的变化,代码编译并且似乎有效,产生:

5
10

Empty Queue
20
30

Empty Queue