数据结构之美(七)队列的顺序存储结构和链式存储结构

目录

队列

队列的顺序存储结构

队列的链式存储结构

入队操作

出队操作


队列

队列的顺序存储结构

队列队列,顾名思义就是平常我们排队的时候的一种结构,下面JV带你详细看看它的定义。

队列(queue)是只允许在一端进行插入操作(队尾),而在另一端进行删除操作(队头)的线性表。它先进先出(First In First Out),就像排队一样。

为什么删除操作是O(n)呢?因为删除队头之后会有一次元素的移动。那么我们能不能想想办法,优化一下,让删除操作简单一些。

我们说执行删除操作的一端称为队头,但没有要求队头一定在下标为0的地方,因此,我们可以引入两个指针分别指向队列的头尾,这样就不用在删除操作时移动元素,而是移动指针即可,这样时间复杂度就从O(n)变成了O(1)。

OK,现在我们有了两个指针:front和rear,分别指向队头和队尾。

那么,我们怎么判断这个队列是空是满呢?有人会说,很简单呀,既然front指向队头,rear指向队尾,那么只要front=rear,队列就满了呗。这位同学你太天真啦,看看下图。

你看,这两种情况不都满足front=rear么,但是一个队空一个队满,那么到底怎么判断队列的空还是满呢?

其实有两种方法:

1、我们发现这两种情况的同一点在于front=rear,不同点在于一个全空,一个全有。那么我们可以找个队列里最看的顺眼的地方,立个flag标记一下,当front=rear时,我们对flag的地方进行判断,若flag为空,则队列全为空,反之则全为满。

2、修改判断条件,不再让front=rear来判断空满,我们可以重新定义:front=rear时,队空,当还有一个元素空间为空时,队满。

就是这种亚子滴~

我们来讨论讨论为什么这样做,而不是直接定义front=rear+1或front=rear-1呢? 因为用上了指针,我们当然希望队列能够更加具有效率,为了尽可能的利用数组的空间,rear可能出现在front的前面或者后面,而你告诉计算机的时候,又不能有歧义,于是我们定义当还有一个元素空间为空时,队满。

这思路怎么告诉计算机呢?设队列的最大尺寸为QueueSize,那么队列满的条件应该是(rear+1)%QueueSize==front,计算队列长度的公式为:(rear-front+QueueSize)%QueueSize(因为有一个空的,所以它不能算进长度,也就是说,这个公式算的是队列的真实使用长度)   你可以待入前面的队列里,实践一下。

ok,接下来我们就可以开始写代码啦

typedef int QElemType;

typedef struct
{
    QElemType data[MAXSIZE];
    int front;
    int rear;
}SqQueue;


//初始化一个空队列
Status InitQueue(SqQueue *Q)
{
    Q->front=0;
    Q->rear=0;
    return OK;
}

//返回队列的元素个数,即当前长度
int QueueLength(SqQueue Q)
{
    return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}

//入队操作
Status EnQueue(SqQueue *Q,QElemType e)
{
    if((Q->rear+1)%MAXSIZE==Q->front)
        return ERROR;        //判断队列是否满了
    Q->data[Q->rear]=e;        //赋值
    Q->rear=(Q->rear+1)%MAXSIZE; //指向下一个
    return OK;
}

//出队操作,用e返回其值
Status DeQueue(SqQueue *Q,QElemType *e)
{
     if((Q->rear+1)%MAXSIZE==Q->front)
        return ERROR;        //判断队列是否满了
    *e=Q->data[Q->front];//将队头元素赋值给e
    Q->front=(Q->front+1)%MAXSIZE    //front指针向后移动一位
                                     //若到最后则转到数组头部
    return OK;
}

队列的链式存储结构

队列的链式存储结构,其实就是线性表的单链表,只是只能尾进头出而已。

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

typedef int QElemType;

typedef struct QNode  //结点结构
{
    QElemType data;
    struct QNode *next;
}QNode,*QueuePtr;

typedef struct 
{
    QueuePtr front,rear; //队头队尾指针
}LinkQueue;

入队操作

Status EnQueue(LinkQueue *Q,QElemType e)
{
    QueuePtr s=(QueuePtr)malloc(sizeof(QNode))
    if(!s)
        exit(OVERFLOW);
    s->data=e;
    s->next=NULL;
    Q->rear->next=s;
    Q->rear=s;
    return OK;
}

出队操作

//删除队头,并用e返回其值
Status DeQueue(LinkQueue *Q,QElemType *e)
{
    QueuePtr p;
    if(Q->front==Q->rear)   //判断是否为空
        return ERROR;

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

    if(Q->rear==p)
        Q->rear=Q->front;
    free(p);

    return OK;
}
发布了38 篇原创文章 · 获赞 6 · 访问量 1906

猜你喜欢

转载自blog.csdn.net/weixin_43827227/article/details/100903422