队列(C语言)


前言

本篇进行队列的学习。使用C语言实现


概念

排队是体现了“先来先服务”的原则。
在多道程序运行的计算机系统中,可以同时有多个作业运行,他们的运算结果都需要通过通道输出,若通道输入未完成,后来的作业应该排队等待,每当通道输入完成时,则从队列的对头退出作业进行输出操作。凡是申请该通道输出的作业都从队尾进行等待。
队列是另一种限定性的线性表,它只允许插入在表的一端进行,删除在表的另一端进行。允许插入的一端叫做队尾,允许删除的一端叫做队头。队列的插入操作通常称为“入队”或“进队”,而队列的删除操作称为“出队”或“退队”
当队列中无数据时,称为“空队列”
队头元素总是最先进队列,也总是最先出队列,这种表是按照“先进先出”原则组织数据的。因此队列也被称为“先进先出”表

在这里插入图片描述
如图,入队的顺序为0,1,2,3,…,n-1,则队头元素为0,队尾元素为n-1,出队顺序仍是0,1,2,3,…,n-1。

基本操作

  • InitQueue(q):队列初始化。构造了一个空队列
  • InQueue(q,x):入队操作。对于已经存在的队列q,插入一个元素x到队尾,操作成功返回TRUE,否则返回FALSE
  • OutQueue(q,x):出队操作。删除队首元素,返回其值,成功返回TRUE,否则返回FALSE
  • FrontQueue(q,x):读队头元素。读队头元素并返回其值,队列不变。操作成功返回TRUE,否则返回FALSE
  • EmptyQueue(q):判空队列操作。若q为空队列返回TRUE,否则返回FALSE

与线性表,栈类似,队列也有顺序存储和链式存储两种存储方法。队列的顺序存储结构可以简称“顺序队列“
顺序队列师指利用一组地址连续的存储单元一次存放队列中的数据元素
使用一维数组来作为队列的顺序存储空间,另外在设置两个指示器,一个为指向队头元素的指示器front,另一个为指向队尾元素的指示器rear
在C语言中,数组的下标是从0开始的,因此为了算法设计的方便,约定在初始化队列时,空队列的front = rear = -1
还约定在非空队列中,头指示器front总是指向队列中实际队头元素的前一个位置。尾指示器rear总是指向队尾元素。


typedef int ElemType;
#define MAXSIZE 50
typedef struct{
    ElemType elem[MAXSIZE];
    int rear;
    int front;
} SeQueue;
int main(int argc, const char * argv[]) {
    //定义一个指向队列的指针
    SeQueue* sq;
    //申请一个顺序队列的存储空间
    sq = (SeQueue*)malloc(sizeof(SeQueue));
    
    return 0;
}
  • 当设置MAXSIZE = 10,随着入队,出队的进行,会使整个队列整体向后移动,会出现图d的“假溢出”现象。
  • 队尾指针已经移动到了最后,再有元素入队就会出现“溢出”。但是此时队列并未真正满员,这是由“队尾入,队头出”的现象造成的。

在这里插入图片描述

循环队列

  • 上面我们提到了“假溢出”的现象,。接下来说说解决“假溢出‘的方法
  • 可以将队列的数据区域elem[MAXSIZE]-1看作头,尾相接的循环结构。即规定最后一个单元的后继为第一个单元。这样整个数据区就像一个环。将这样的环称为循环队列。
  • 在循环队列中,头,尾指针关系不变,头指针的指示器front总是指向队列中实际队头元素的前面一个位置,尾指针热啊热总是指向队尾元素。

在这里插入图片描述

//入队时尾指针+1的操作
sq->rear = (sq->rear+1)%MAXSIZE;   
//出队时队头指针+1的操作尾
sq->rear = (sq->front+1)%MAXSIZE;
  • 图a中具有A、B、C、D四个元素,此时front = 4,rear = 8,随着E、F、G、H、I、J入队,队中有了10个元素,已经队满。此时front = 热啊热= 4。
  • 可得在队满的情况下rear = front。
  • 若在a的情况下A、B、C、D出队,此时队空。front = rear =8。
  • 可得在空对的情况下front = rear。就是说队满和队空的条件是一样的。
  • 我们可以通过少用一个元素空间来解决队满和队空条件相同的问题,把d所示的情况视为队满,此时rear + 1 就会等于front。这种情况下队满的条件是(rear + 1 )%MAXSIZE = front。就可以和队空区别开来。
  • 也可以附设一个存储队列中的元素个数的变量,num,当num = 0时队空。当num = MAXSIZE时队满。

在这里插入图片描述

少用一个元素空间


typedef int ElemType;
#define MAXSIZE 50
typedef struct{
    ElemType elem[MAXSIZE];
    int rear;
    int front;
} SeQueue;
//置空队列
SeQueue* InitSeQueue(){
    q = (SeQueue*)malloc(sizeof(SeQueue));
    q->front = q->rear = MAXSIZE - 1;
    return q;
}
//入队
int InSeQueue(SeQueue* q,ElemType x){
    if ((q->rear+1)%MAXSIZE == q->front){
        return FALSE;
    }else{
        q->rear = (q->rear+1)%MAXSIZE;
        q->elem[q->rear] = x;
        return TRUE;
    }
}
//出队
int OutSeQueue(SeQueue* q,ElemType* x){
    if (q->front == q->rear){
        return FALSE;
    }else{
        q->front = (q->front + 1)%MAXSIZE;
        *x = q->elem[q->front];
        return TRUE;
    }
}
//判空队列
int EmptySeQueue(SeQueue* q){
    if (q->front == q->rear){
        return TRUE;
    }else{
        return FALSE;
    }
}

栈队列

在程序设计语言中不可能动态分配一维数组来实现循环队列。如果要使用循环队列,则必须为它分配最大长度的空间,若用户无法预计所需队列的最大空间,则可以采用链式结构来存储队列,链式存储结构称为“链队列”,和链栈类似,可以使用单链表来实现链队列。根据队列FIFO原则,链队列中为了操作方便,可以采用带头结点的单链表表示队列,并设置一个队头指针front和一个队尾指针rear。头结点始终指向头结点,尾直接指向当前最后一个元素的结点。

在这里插入图片描述
链队列的数据类型描述如下:


typedef struct{
    ElemType data;
    struct node* next;
} QNode;
typedef struct{
    QNode* front;
    QNode* rear;
} LQNode;

建立带头结点的链队列:

链队列的各种操作的实现也和单链表类似,只是限定插入操作在表尾进行,删除操作在表头进行。它的插入和删除是单链表的特殊情况,
在链队列的删除操作中,如果仅有一个元素结点,删除后还需要修改尾指针。

在这里插入图片描述

//创建一个带头结点的空队
LQueue* Init_LQueue(){
    LQueue* q;
    QNode* p;
    q = (LQNode*)malloc(sizeof(LQNode));
    p = (QNode*)malloc(sizeof(QNode));
    p->next = NULL;
    q->front = q->rear = p;
    return q;
}
//入队
void InLQueue(LQueue* q,DataType* x){
    QNode* p;
    p = (QNode*)malloc(sizeof(QNode));
    p->data = x;
    p->next = NULL;
    q->rear->next = p;
    q->rear = p;
}
//队判空
int Empty_LQueue(LQueue* q){
    if (q->front == q->rear){
        return 0;
    } else{
        return TRUE;
    }
}
//出队
int Out_LQueue(LQueue* q,DataType* x){
    QNode* p;
    if (Empty_LQueue(q)){
        return FALSE;
    } else{
        p = q->front->next;
        q->front->next = p->next;
        *x = p->data;
        free(p);
        if (q->front->next == NULL){
            q->rear = q->front;
        }
    }
    return TRUE;
}
  • 14
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河丘壑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值