数据结构之队列

       说起队列(queue),让人更为熟悉的一种表述则是FIFO(First In First Out)。正如其含义,先进先出,数据排队。

https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1532694846140&di=7a3b11ad708a463a625d8d536b4093ec&imgtype=0&src=http%3A%2F%2Fimg.2cto.com%2FCollfiles%2F20150515%2F20150515084328240.gif

        队列的官方定义是这么表述的:队列(queue)是只允许再一端进行插入操作,而在另一端进行删除操作的线性表。允许插入的一端称为队尾,允许删除的一端称为队头。

        生活中有些时候会遇到一些队列操作的现象,比如你的电脑卡顿,点下鼠标的操作过一段时间才会执行,这是为什么呢?因为操作系统对于消息的基本处理机制是按照队列的方式入队,然后出队执行的。再比如银行服务叫号机制,取号等待,那也是一种以队列方式执行的排队模式。队列、堆栈,在数据结构中作为一种基本的模型,应用也颇多。

       由定义知,队列是一种线性表,那么线性表的定义和使用有机会再说,需要注意的是线性表强调的是有限的序列,数据与数据之间像是被线串联在一起。线性表不代表一定是空间连续,因为线性表包含顺序表和链表。链表存储空间不一定是连续的,只要除了首尾元素外所有元素有唯一前驱和后继即可,且数据相“连”。

 

一、队列的基本编程表述

基本操作函数(Operation):

InitQueue(*Q); //初始化操作,一般是为队列开辟一个空间

DestroyQueue(*Q); //销毁队列,释放空间

ClearQueue(*Q); //清空队列数据,队列依然存在

QueueIsEmpty(Q);//判断队列是否为空

QueueIsFull(Q);//判断队列是否已满

GetHead(Q, *e);//获取队列首元素,即队头元素

EnQueue(*Q, e);//数据入队操作

DeQueue(*Q, *e);//数据出队操作

QueueLength(Q);//获取队列存储的数据长度

 

队列作为一种抽象的结构,不是说存储的数据只是一个int、char、float什么的数据,可以是结构体类型的数,包含各种类型数据的一个数据块。根据实际应用的需求,写出需要的函数即可,上面所列出来的操作只是说是常用的一些操作,未必全用,当然也可以自己再写一些其他的特殊操作,比如你想获取当前队列中某一个位置的元素,这些都是可以实现的。这些函数的命名也只是比较规范的一种总结,其实还有很多人用什么PopQueue()、PushQueue()….自己喜欢就好。

 

二、队列的基本编程实现

数组队列的实现

数组实现队列是比较直接的一种方式,一般会定义一个结构体变量用于存储数组以及队头和队尾标识。

//队列存储的数据类型

typedef int QElemType;


//定义队列结构体

typedef struct

{

         QElemType data[MAXSIZE];

         int front;

         int rear;

}SqQueue;

       其中QElemType 是一个宏观意义上的类型,你可以定义其他结构体变量存入数组,笨拙的办法也可以不要这样的结构体,你知道队头队尾只是标识就好,用一个简单的数组,每次存入数据,将队尾标识加1即可,当然入队操作你要先判断队列(数组)是否已经存满。存满了要将数组中数据从第二个数据开始往前移动一个空间。覆盖队头数据,这样就可以持续存入了。出队的效果也差不多,出队其实就是用后面的数据移位覆盖队头数据,然后把队尾下标减1。这么一说,其实不难发现这样的移位操作是很不高效的,我们以循环移动front和rear标识来实现数据覆盖则显得更科学,即循环队列。循环队列中front和rear可以一直进行加1操作的原因是因为队列是线性存储,在已开辟的空间中地址是循环的,而不是表面意义上的数值增大。

 

循环队列的基本实现办法:

基本操作函数的实现

/*初始化操作,一般是为队列开辟一个空间*/

SqQueue * InitQueue(void)

{

         SqQueue *Q;

    Q = (SqQueue *)malloc(sizeof(SqQueue)); //开辟队列空间

         //初始化队头队尾

         Q->front = 0;

         Q->rear  = 0;



         return Q;

}



/*获取队列存储的数据长度*/

unsigned char QueueLength(SqQueue *Q)

{

         return (Q->rear - Q->front + MAXSIZE) % MAXSIZE;  //循环队列取余操作

}



/*数据入队操作*/

void EnQueue(SqQueue *Q, QElemType e)

{

         if (QueueLength(Q) != MAXSIZE - 1)  //队列没有存满

         {

                   Q->rear = (Q->rear + 1) % MAXSIZE;     //首指针前移

                   Q->data[Q->rear] = e;

                   printf("%d", Q->data[Q->rear]);

         }

         else //队列存满循环覆盖

         {

                   Q->front = (Q->front + 1) % MAXSIZE;   //首指针前移

                   Q->rear = (Q->rear + 1) % MAXSIZE;     //尾指针前移

                   Q->data[Q->rear] = e;

         }



}



/*数据出队操作*/

void DeQueue(SqQueue *Q, QElemType *e)

{

         //使用中应该判断队列是否为空

         Q->front = (Q->front + 1) % MAXSIZE; //首指针前移

         *e = Q->data[Q->front]

}

 

        这张图是从网上找的,和代码不是很相合,代码实现过程中front所在的地址是不存储有效数据的。完整代码可留言,不过队列操作并不难,所以不放全代码了。函数的形式并不死板,按照实际需要可以做一些调整。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值