队列与队列运用

1.队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有"先进先出"FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头
在这里插入图片描述

2.队列的实现

队列也可以数组链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较,难度系数大。
在这里插入图片描述

3.队列接口的定义

#include<stdbool.h>
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int INT;
typedef struct QueueNode
{
   //队中数值
   INT val;
   //下位指针
   struct QueueNode*next;
}ST1;
typedef struct Queue
{  //队头
   ST1*p1;
   //队尾
   ST1*p2;
   //队数值
   int size;
}ST2;
//初始化队列
void QueueInit(ST2*pst);
//销毁队列
void Queuestroy(ST2*pst);
//队尾插入队列
void QueuePush(ST2*pst,INT x);
//队头出队列
void  QueuePop(ST2*pst);
//获取队头元素
INT QueueFront(ST2*pst);
//获取队尾元素
INT  QueueBeack(ST2*pst);
//判断队列是否为空
int QueueEmpty(ST2*pst);
//队列中有效位数
int QueueSize(ST2*pst);

4.代码组成与实现

4.1队列初始化

在这里插入图片描述

void QueueInit(ST2*pst)
{
    assert(pst);
    pst->p1=pst->p2=NULL;
    pst->size=0;
}

4.2.队尾插入队列

队列的规则是先进先出,数据是从后向前插入的,也就相当于链表的尾插。

void QueuePush(ST2*pst,INT x)
{
    assert(pst);
    //开辟空间
    ST1*ret=(ST1*)malloc(sizeof(ST1));
    if(ret==NULL)
    {
        perror(" ");
        return ;
    }
    //赋初值
    ret->next=NULL;
    ret->val=x;
    //如果是第一次,则直接插入
    if(pst->p2==NULL)
    {
        pst->p1=pst->p2=ret;
    }
    //否则使篇的下一个节点指向他,并走向下一个节点
    else{
        pst->p2->next=ret;
        pst->p2=ret;
    }
    pst->size++;
}

4.3.队头出队列

队列的规则是先进先出,出数据就是将队头移向下一位,所以只需要将队头下移,有效位减一位即可。
当然不乏出现特殊情况,列如只有一个元素时,就会出现野指针的情况,所以p2要给NULL。

void  QueuePop(ST2*pst)
{
    assert(pst);
    assert(pst->p1);
    //保持p1节点
    ST1*del=pst->p1;
    //使p1走向p1的下一项
    pst->p1=pst->p1->next;
    //从而释放掉p1先节点
    free(del);
    del=NULL;
    //如果p1是最后一个节点或者NULL则尾节点p2指向NULL
    if(pst->p1==NULL)
    {
        pst->p2=NULL;
    }
    pst->size--;
}

4.4.获取队头元素

相对来说没有什么难点,只需要注意是否有值即可。

INT QueueFront(ST2*pst)
{
    assert(pst);
    assert(pst->p1);
    //返回p1节点的值
    return pst->p1->val;
}

4.5.获取队尾元素

INT QueueBeack(ST2*pst)
{
    assert(pst);
    assert(pst->p2);
    //返回p2节点的值
    return pst->p2->val;
}

4.6.判断队列是否为空

bool QueueEmpty(ST2*pst)
{
    assert(pst);
    return pst->p1==NULL;
}

4.7.队列中有效位数

int QueueSize(ST2*pst)
{
    assert(pst);
    return pst->size;
}

4.8.销毁队列

队列是由动态开辟的,释放空间需要逐条释放。

void Queuestroy(ST2*pst)
{
    assert(pst);
    ST1 *cur=pst->p1;
    while(cur)
    {
        ST1*next=cur->next;
        free(cur);
        cur=next;
    }
    pst->p1=pst->p2=NULL;
    pst->size=0;
}

5.扩展

另外扩展了解一下,实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。环形队列可以使用数组实现,也可以使用循环链表实现。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
代码的基本组成分为:初始化队列,插入数据,删除数据,判断是否满,判断是否空,输出头元素,输出尾元素,释放队列。

5.1队列定义

typedef struct {
    //存放数据的数值(队列)
    int *a;
    //队头
    int front;
    //队尾
    int rear;
    //队列大小
    int n;
} MyCircularQueue;

5.2.初始化队列

由于是循环队列无法判断队尾的位置所以多开一个空间来判断队尾。

MyCircularQueue* myCircularQueueCreate(int k)
 {
    MyCircularQueue* obj(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    int * tmp=(int *)malloc(sizeof(int)*(k+1));
    obj->a=tmp;
    obj->front=0;
    obj->rear=0;
    obj->n=k;
    return obj;
}

5.3.判断队是否被装满

在这里插入图片描述

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if((obj->rear+1)%(obj->n+1)==obj->front)
    {
        return true;
    }
    return false;
}

5.4.插入数据

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull( obj))
    {
        return false;
    }
    obj->a[obj->rear]=value;
    obj->rear++;
    //实现数组循环
    obj->rear=obj->rear%(obj->n+1);
    return true;
}

5.5.判断是否空

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    if(obj->front==obj->rear)
    {
        return true;
    }
    return false;
}

5.6删除数据

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty( obj))
    {
        return false;
    }
    //有效位是front到rear之间的数
    obj->front++;
    obj->front=obj->front%(obj->n+1);
    return true;
}

5.7输出头元素

int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty( obj))
    {
        return -1;
    }
    return obj->a[obj->front];
}

5.8输出尾元素

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty( obj))
    {
        return -1;
    }
    //if(obj->rear==0)
    //return obj->a[k];
    //return obj->a[obj->rear-1];
    return  obj->a[(obj->rear-1+obj->n+1)%(obj->n+1)];
}

5.9释放队列

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}

在这里插入图片描述

如果喜欢麻烦免费的小星星点一下。

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值