队列

目录

一、基本概念

二、顺序队列

三、链式队列

四、双端队列


       

           之前提到了栈,它是只能在一端插入删除的线性表。对照它,队列好比生活中的排队,总人数减少就是队头的人离开,总人数增多就是有新的人排在队尾。

一、基本概念

队列是一种限定存取位置的线性表。它只允许在一段出入,在另一端删除。

队头:允许删除的一端

队尾:允许插入的一端

空队列:不含任何元素的空表

基本操作:

  • InitQueue(&Q):初始化队列,构造一个空队列Q
  • QueueEmpty(Q):判队列空,若队列Q为返回true,否则返回false
  • EnQueue(&Q,x):入队,若队列Q未满,将x加入,使之称为新的队尾
  • DeQueue(&Q,&x):出队,若队列非空,则将队头元素赋值给x
  • GetHead(Q,&x):读队头元素,若队列Q非空,则将队头元素赋值给x

(注意:队列操作首先,许多线性表的操作不能用,比如不能随便读取队列中间某个数据)

线性表分为顺序表和链表,有顺序栈和链栈,同样队列按照存储方式分为顺序队和链队

二、顺序队列

1.队列的顺序实现是在连续存储单元中存放队列的元素,并设置front指针指示队头,rear指示队尾

初始化队列令front=rear=0

每当添加一个元素,先将元素添加到reara所指的位置,再让队尾指针加1,因此rear指示了实际队尾位置的后一位置。,即下一个元素应当加入的位置。而队头指针front指向队头元素。

但这种设定存在问题。

上图中初始的空队,有Q.front==Q.rear==0成立,但队满时,不能最后用Q.rear==MaxSize作为队满的条件,上图中最后满足

Q.rear==MaxSize ,但是队列中仍有一个元素。这种现象被称为假溢出

为了解决上面的问题,又引入了循环队列

2.   将顺序队列从逻辑上视为一个环。当队首指针Q.front=MaxSize-1后,在前进一个位置就自动到0

  • 初始时:Q.front=Q.rear=0
  • 队首指针进1:Q.front= (Q.front+1)%MaxSize
  • 队尾指针进1:Q.rear= (Q.rear+1)%MaxSize
  • 队列长度:(Q.rear+MaxSize-Q.front)%MaxSize
  • 出队入队时:指针都按顺时针方向进1

队列顺序存储

#define MaxSize 100             //定义队列中元素的最大个数

typedef struct{

          ElemType data[MaxSize];                 //存放队列元素

          int front,rear;                                 //队头指针和队尾指针

}SqQueue;

队空条件:Q.front=Q.rear

当入队元素速度远大于出队元素,队尾指针很快会赶上队首指针,则队满时也有Q.front=Q.rear

为了区分队空和队满有三种区分方式

(1)牺牲一个 单元来区分队空和队满:约定(队头指针在队尾指针的下一位置作为队满的标志)

       队满条件:(Q.rear+1)%MaxSize==Q.front

      队空条件:Q.front=Q.rear

      队列中元素个数:(Q.rear-Q.front+MaxSize)%MaxSize

(2)类型中增设表示元素个数的数据成员。

       队满条件:Q.size==0

       队空条件:Q.size==MaxSize

(3)类型增设tag数据成员,以区分队满还是队空。tag为0,若因删除导致Q.front==Q.rear,则为队空;tag等于1,若因插入导致           Q.front==Q.rear,则为队满

3.循环队列的操作

(1)初始化
void InitQueue(SeQueue &Q){
    Q.rear=Q.front=0;   //初始化队首、队尾指针
}
(2)判队队空
bool isEmpty(SeQueue &Q,ElemType x){
    if(Q.rear==Q.front)       //队空条件
        return ftrue;
    else 
        return false;
}
(3)入队
bool EnQueue(SeQueue &Q,ElemType x){
    if((Q.rear+1)%MaxSize==Q.front)   //队满
        return false;
    Q.data[Q.rear]=x;
    Q.rear=(Q.rear+1)%MaxSize;        //队尾指针+1取模
        return true;
}
(4)出队
bool DeQueue(SeQueue &Q,ElemType x){
    if(Q.rear=Q.front)   //队空,报错
        return false;
    x=Q.data[Q.front]
    Q.front=(Q.front+1)%MaxSize;        //队头指针+1取模
        return true;
}

三、链式队列

1.基本概念

队列的链式存储称为链队列。实际为一个同时带有队头指针和队尾指针的单链表。头指针指向队头结点,尾指针指向队尾结点。(不带头结点的如下图)

链式队:

typedef struct{               //链式队列结点

          ElemType data;

          struct LinkNode *next;

}LinkNode;

typedef struct{             //链式队列

           LinkNode *front,*rear;                        //队列的队头和队尾指针

}LinkQueue;

当Q.front==NULL 且 Q.rear==NULL时,队列为空

           出队时,首先判断队是否为空,若非空,则取出队头元素,将其从链表删除,并让Q.front指向下一个结点。

           入队时,建立一个新结点,将新结点插入到链表的尾部,并改让Q.rear指向这个新插入的结点。

不带头结点的链式队列在操作上麻烦,所以设计为带头结点的使得插入删除操作统一。

2.基本操作

(1)初始化
void InitQueue(LinkQueue &Q){
    Q.front=Q.rear=(LinkNode*)malloc(sizeof(LinkNode)); //建立头结点
    Q.front->next=NULL;                //初始为空
}
(2)判队空
bool IsEmpty(LinkQueue Q){
    if(Q.front==Q.rear) return true;
    else return false;
}
(3)入队
void EnQueue(LinkQueue){
    LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
    s->data=x;             //创建新结点,插入到链尾
    s->next=NULL;
    Q.rear->next=s;
    Q.rear=s;
}
(4)出队
bool DeQueue(LinkQueue &Q,ElemType &x){
    if(Q.front==Q.rear) return false;   //空队
    LinkNode *p=Q.front->next;
    x=p->data;
    Q.front->next=p->next;
    if(Q.rear==p)
        Q.rear=Q.front;           //若原队列中只有一个结点,删除后为空
    free(p);
    return true;
}

四、双端队列

双端队列是指允许两端都可以进行入队和出队操作的队列,其元素的逻辑结构仍是线性结构。将队列的两端分别称为前端和后端,两端都可以入队出队

在双端队列出队时,无论前端还是后端出队,先出的元素排在后出的元素前面

                 由普通的双端队列又可改造为:

(1)输出受限的双端队列:允许在一端插入和删除,但在另一端只允许插入的双端队列

(2)输入受限的双端队列:允许在一端插入和删除,但在另一端只允许删除的双端队列

//收藏大佬代码,https://www.cnblogs.com/wychen5/p/10445264.html
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

#define true 1
#define false 0
#define BUF_SIZE 8
typedef struct Queue
{
    int * BUF;
    int front;
    int rear;
}QUEUE;

void initQueue(QUEUE *queue_q)
{
    queue_q->BUF = (int *)malloc(sizeof(int)*BUF_SIZE);
    if(queue_q->BUF != NULL)     //队列内存分配成功
    {
        queue_q->front = queue_q->rear = 0; //初始化头尾指针 
    }
   
}

//判空
unsigned char isemptyQueue(QUEUE *queue_q)
{
    if(queue_q->front == queue_q->rear)
    {
        return true;
    }
    else
        return false;
}
 
//判满
unsigned char is_fullQueue(QUEUE *queue_q)
{
    if((queue_q->rear +1)%BUF_SIZE == queue_q->front)
    {
        return true;
    }else
        return false;
}

//入队
 
void In_Queue(QUEUE *queue_q , int value)
{
    if(is_fullQueue(queue_q) != true)        //队列未满
    {
        queue_q->BUF[queue_q->rear] = value;
        queue_q->rear = (queue_q->rear + 1)%BUF_SIZE ;    //尾指针偏移 
    }
}
 

//出队 
 void out_Queue(QUEUE *queue_q , int *value)
 {
     if(isemptyQueue(queue_q) != true)        //队列未空
     {
        *value = queue_q->BUF[queue_q->front];
        queue_q->front = (queue_q->front + 1)%BUF_SIZE ;
     }
}

void bianli_a(QUEUE *queue_q)
{
    if(isemptyQueue(queue_q) != true)
    {
        int ret=queue_q->front;
        while(ret != queue_q->rear)
        { 
            printf("%d  ",queue_q->BUF[ret]);
            ret=(ret+1)%BUF_SIZE;
        }
    }
}

int  main()
{
    int val;
    QUEUE m;
    initQueue(&m);
    In_Queue(&m,1);
    In_Queue(&m,2);
    In_Queue(&m,3);
    bianli_a(&m);
    printf("\n");
    out_Queue(&m,&val);
    bianli_a(&m); 
    return 0;
}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值