数据结构与算法 | 栈和队列——队列

                                                                队列

 •与栈相反,队列是一种先进先出(First In First Out, FIFO)的线性表。只允许在表尾一端进行插入操作而在表头一端进行删除操作。

队列既可以用链表实现,也可以用顺序表实现。

跟栈相反的是,栈一般我们用顺序表来实现,而队列我们常用链表来实现,简称为链队列。

//队列的链式表示和实现
typedef struct QNode{
    ElemType data;
    struct QNode *next;
}QNode, *QueuePtr;
typedef struct{
    QueuePtr front;//队头指针
    QueuePtr rear;//队尾指针
}LinkQueue;

 将队头指针指向链队列的头结点,而队尾指针指向终端结点。(头结点不是必要的)

空队列时,front和rear都指向头结点。

以下将

构造一个空队列、往队列中插入元素、删除元素、销毁队列都用C语言描述

和之前的线性表类似,所以在学习这部分的时候就轻松得多。

注意:c语言中->和.的区别——->用于指针, .用于对象

"->"用于指向结构成员,它的左边应为指向该结构类型的指针(结构指针),而"."的左边应为该结构类型的变量(结构变量),如已定义了一个结构体struct student,里面有一个int a;然后有一个结构体变量struct student stu及结构体变量指针struct student *p;且有p=&stu,那么p->a和stu.a表示同一个意思。

 实践:编写一个链队列,任意输入一串字符,以#作为结束标志,然后将队列中的元素显示到屏幕上

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

typedef char ElemType;

typedef struct QNode{
    ElemType data;
    struct QNode *next;
}QNode, *QueuePtr;
typedef struct{
    QueuePtr front;//队头指针
    QueuePtr rear;//队尾指针
}LinkQueue;

int InitQueue(LinkQueue *q)
{
    q->front = q->rear = (QueuePtr)malloc(sizeof(QNode));
    if(!q->front)
    {
        exit(0);//存储分配失败
    }
    q->front->next = NULL;
    return 1;
}
int InsertQueue(LinkQueue *q,ElemType e)
{
    QueuePtr p;
    p = (QueuePtr)malloc(sizeof(QNode));
    if(!q->front)
        exit(0);
    p->data = e;
    p->next = NULL;
    q->rear->next = p;
    q->rear = p;
    return 1;
}
int DeleteQueue(LinkQueue *q,ElemType *e)
{
    QueuePtr p;

    if(q->front == q->rear)
        return 0;

    p = q->front->next;
    *e = p->data;
    q->front->next = p->next;

    if(q->rear == p)//队列中仅有一个元素,删除后队列为空
        q->rear = q->front;
    free(p);
    return 1;
}
int DestroyQueue(LinkQueue *q)
{
    while(q->front)
    {
        q->rear = q->front->next;
        free(q->front);
        q->front = q->rear;
    }
    return 1;
}
int main()
{
    ElemType e;
    LinkQueue q;
    InitQueue(&q);
    printf("请输入一个字符串,并以#号键结束输入:");
    scanf("%c",&e);

    while(e !='#')
    {
        InsertQueue(&q, e);
        scanf("%c",&e);
    }

    printf("打印队列中的元素:");
    while( q.front != q.rear )
    {
        DeleteQueue(&q,&e);
        printf("%c",e);
    }
    return 0;
}

                                                      循环队列

队列的顺序存储结构:影响程序效率,也容易出现数组越界的错误。

解决假溢出的办法就是队列满了之后就再从头开始,也就是头尾相接的循环队列。

•循环队列它的容量是固定的,并且它的队头和队尾指针都可以随着元素入出队列而发生改变,这样循环队列逻辑上就好像是一个环形存储空间。

队列空条件:q.front == q.rear

队列满条件:(q.rear +1)%maxsize == 0 (此时队列实际容量为maxsize -1)

//定义一个循环队列
#define MAXSIZE 100
typedef struct
{
ElemType *base; // 用于存放内存分配基地址
// 这里也可以用数组存放
int front;
int rear;
}SqQueue;

//初始化一个循环队列
Status InitQueue(SqQueue *q)
{
    q->base = (ElemType *) malloc (MAXSIZE * sizeof(ElemType));
    if( !q->base )//存储分配失败
        exit(0);
    q->front = q->rear = 0;
    return OK;
}
//插入元素e
Status EnQueue(SqQueue *q,ElemType e)
{
    if((q->rear+1)%MAXSIZE == q->front)
        return ERROR;
    q->base[q->rear] = e;
    q->rear = (q->rear+1)%MAXSIZE;
    return OK;
}
//出队列操作
DeleteQueue(SqQueue *q, ElemType *e)
{
    if( q->front == q->rear )
        return ERROR; // 队列为空
    *e = q->base[q->front];
    q->front = (q->front+1) % MAXSIZE;
    return OK;
}

猜你喜欢

转载自blog.csdn.net/qq_35924276/article/details/81448816