队列的基本操作

一、链对列的定义

1、队列类似线性表和栈,也是定义在线性结构上的ADT,与线性表和栈的区别在于,元素的插入和删除分别在表的两端进行。类似日常生活中排队,允许插入的一端为队尾(rear),允许删除端称队头(front)

2、特性:First In First Out先进先出,链对列有头指针和尾指针,其中,头指针指向头结点,头结点的下一个才是第一个元素,尾指针直接指向最后一个元素

链对列只能从队头删除,从队尾插入。(先进先出)
在这里插入图片描述

3、为什么要设立尾指针呢?
队列是先入先出, 从头出, 从尾入,如果只有一个指针, 那么另外一个操作就要遍历整个链表, 导致效率降低.,所以要设立尾指针。

#include <bits/stdc++.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -2


typedef int Status;
typedef ?? QElemType;

using namespace std;

typedef struct QNode
{
    QElemType data;
    struct QNode *next;
}QNode,*QueuePtr;

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

1、链对列的初始化

Status InitQueue(LinkQueue &Q)
{
    Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
    if(!Q.front) exit(OVERFLOW);
    Q.front->next=NULL;//这里千万不要忘记;
    return OK;
}//时间复杂度O(1)

这里赋初值的方式和顺序栈区别开,顺序栈是先给base赋初值,判断base是否分配成功,然后让top=base。但是这里是直接让两者连等,判断的是front是否分配成功,之后对front进行操作。


2、链对列的销毁(会第一种方式就行,需要再写,不熟练)

Status DestoryQueue(LinkQueue &Q)
{
    QueuePtr p=Q.front,postp;
    while(p)//因为是销毁,所以销毁的时候带着头结点也要一起销毁掉;
    {
        postp=p->next;
        free(p);
        p=postp;
    }
    Q.front=NULL;
    Q.rear=NULL;
    return OK;
}//复杂度O(n)

或者

Status DestoryQueue(LinkQueue &Q)
{
    while(Q.front)
    {
        Q.rear=Q.front->next;
        free(Q.front);
        Q.front=Q.rear;
    }
    return OK;
}

销毁链对列的时候,要把头结点也销毁掉,所以while中不是Q.front->next而是Q.front


3、链对列的清空(需要再看)

Status ClearQueue(LinkQueue &Q)
{
    QueuePtr p=Q.front->next,postp;
    while(p!=Q.rear)
    {
        postp=p->next;
        free(p);
        p=postp;
    }
    Q.rear=Q.front;
    return OK;
}

清空需保留头结点,并让Q.rear指向头结点。


4、入队

Status EnQueue(LinkQueue &Q,QElemType e)
{
    QueuePtr p;
    p=(QueuePtr)malloc(sizeof(QNode));
    if(!p) exit(OVERFLOW);
    p->data=e;
    p->next=NULL;//这里千万别忘记;
    Q.rear->next=p;
    Q.rear=p;
    return OK;
}//复杂度O(1)

(1)在队尾插入元素;
(2)千万别忘记p->next=NULL;

p->next=NULL;这里总是忘记


5、链对列删除

Status DeQueue(LinkQueue &Q,QElemType &e)
{
    if(Q.front==Q.rear)  return ERROR;//空队列
    QueuePtr p;
    p=Q.front->next;
    e=p->data;
    Q.front->next=p->next;
    if(p==Q.rear) Q.rear=Q.front;//只1个结点时改尾指针//因为尾指针指向的地方是最后一个元素,所以比较的是p和Q.rear,而不是p->next和Q.rear;
    free(p);
    return OK;
}//复杂度O(1)

不要忘记 if(p==Q.rear) Q.rear=Q.front;这一步的判断。


6、链对列的输出

void PrintQueue(LinkQueue Q)
{
    QueuePtr p;
    p=Q.front->next;
    while(p!=Q.rear)
    {
        printf("%d ",p->date);
        p=p->next;
    }
    printf("%d\n",p->date);
}

二、循环队列的定义

1、为什么不用顺序队列呢?

因为是队头删除,队尾插入,所以如果使用的是顺序队列的话,虽然内存可能是够的,但是,如果,队头前面可能会有没法用的空间,队尾也可能会有没法用的空间,所以说,需要使用循环对列,这样的话,就不会浪费空间。同时,可能造成队尾在队头的情况,这个时候队头后面有元素,队尾前面有元素,中间没有元素。

在这里插入图片描述


2、用循环对列如何判断队空和如何判队列“真”满呢?

为区分队空和队真满,约定只剩一个元素空间时为队满
队空 : front == rear
队满 :(rear+1)%MAXQSIZE==front//M是最大的空间的大小


3、循环队列设有头指针和尾指针,并且,头指针的队列不空则指向队列头元素,尾指针,队列不空则指向队列尾元素下一位置。

#include <bits/stdc++.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -2

#define MAXQSIZE 100//最大对列长度

typedef int Status;
typedef int QElemType;

using namespace std;

typedef struct
{
    QElemType *base;
    int front;// 头指针,队列不空则指向队列头元素
    int rear;//尾指针,队列不空则指向队列尾元素下一位置
}SqQueue;

注意,这里只有对列的最长限度,不会扩展。


1、构造一个空队列

Status InitQueue(SqQueue &Q)
{
    Q.base=(QElemType*)malloc(MAXQSIZE*sizeof(QElemType));
    if(!Q.base)  exit(OVERFLOW);
    Q.front=Q.rear=0;
    return OK;
}//复杂度O(1)

2、销毁一个对列

Status DestroyQueue(SqQueue &Q)
{
    free(Q.base);
    Q.front=Q.rear=0;
    return OK;
}//时间复杂度O(1),比链队列快

4、置空队列(这个需要再看)

Status ClearQueue(SqQueue &Q)
{
    Q.front=Q.rear=0;//只要想等即可
    return OK;
}//复杂度O(1)比链队列快

5、循环队列的插入

Status EnQueue(SqQueue &Q,QElemType e)
{
    if((Q.rear+1)%MAXQSIZE==Q.front)  return ERROR;
    Q.base[Q.rear]=e;
    Q.rear=(Q.rear+1)%MAXQSIZE;
    return OK;
}//时间复杂度O(1)

6、循环队列的删除

Status DeQueue(SqQueue &Q,QElemType &e)
{
    if(Q.front==Q.rear)  return ERROR;
    e=Q.base[Q.front];
    Q.front=(Q.front+1)%MAXQSIZE;//因为可能越界,所以取余;
    return OK;
}//时间复杂度O(1)

7、返回循环队列的长度

int QueueLength(SqQueue Q)
{
    return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
}//时间复杂度O(1),比链队列快,可修改链队列定义

8、判读循环对列是否为空

Status QueueEmpty(SqQueue Q)
{
    if(Q.rear==Q.front)  return TRUE;
    else return FALSE;
}//O(1)

9、返回循环对列首个元素

Status GetHead(SqQueue Q,QElemType &e)
{
    if(Q.front==Q.rear)  return FALSE;
    e=Q.base[Q.front];
    return OK;
}// O(1)若要修改对头元素的值可新设SetHead(&Q,e)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值