队列及其实现

  和栈相反,队列是一种先进先出的特殊线性表,它只允许在表的一段进行插入,而在另一端删除元素,这里需要注意,队列不允许在中间部位进行操作,队列通常有两种实现方式:顺序结构实现、链式结构实现。

队列有下面几个操作:

  • InitQueue()   ——初始化队列
  • EnQueue()        ——进队列
  • DeQueue()        ——出队列
  • IsQueueEmpty()——判断队列是否为空
  • IsQueueFull()    ——判断队列是否已满

  顺序结构实现如下:

  对于顺序队列,入队的新元素是在线性表的最后,时间复杂度O(1),出队时需要将后续的所有元素向前移动,时间复杂度时O(n),那么如何使它的时间复杂度降低到O(1)呢?

  定义front使其始终代表头的下标

出队时将对头元素返回,且front++

  定义rear使其始终代表队尾下一个元素的下标

入队时将新元素插入,且rear++

  顺序队列的关键状态

初始状态:length == 0 , front == 0 , rear == 0;

空队列状态:length == 0 , front == rear;

满队列状态:length == capacity , front == rear;

  循环使用队列中的空间

入列:rear = (rear + 1)%capacity;

出列:front = (front + 1)%capacity;

小结:优化的顺序队列利用顺序空间提高出列操作的效率。

  链式结构如下:

对于链式队列,入队的新元素是在线性表的最后,时间复杂度O(n),出队时需要将后续的所有元素向前移动,时间复杂度时O(1),那么如何使它的时间复杂度降低到O(1)呢?

  定义rear指针始终向链表中的最后一个元素

入队时将新元素通过rear插入队尾,且将rear指向新元素

  链式队列的关键状态

空队列状态:front == NULL , rear == NULL;

  关键操作

入队:

 rear -> next = node;

 rear =  node;

 node -> next = NULL;

出列:

 front = front -> next;

小结:优化的链式队列定义rear指针向队尾元素提高出列操作的效率。

  但是这样的话,空间利用率不高,所以最后再介绍一种队列:循环队列。为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,如下图:

  

  这里需要注意的是,循环队列中,由于入队时尾指针向前追赶头指针;出队时头指针向前追赶尾指针,造成队空和队满时头尾指针均相等。因此,无法通过条件front==rear来判别队列是"空"还是"满"。在C语言中不能够用动态分配的一位数组来实现循环队列,如果用户的应用程序中设有循环队列的话,则必须为它设定一个最长队列长度;若用户无法预估所用队里的最大长度,则应该采用链式队列。具体实现代码如下:

  1 #include<stdio.h>
  2
  3 #include<stdlib.h>
  4
  5 #define MAXSIZE 50                                    //队列是最大长度
  6
  7 typedef struct                                        //点实体结构
  8 {
  9
 10     char name[10];
 11
 12     char id[8];
 13
 14     float x,y,z;
 15
 16 }Point;
 17
 18 typedef struct                                        //循环列表结构
 19 {
 20
 21     Point *base;
 22
 23     int front;
 24
 25     int rear;
 26
 27 }SqQueue;
 28
 29 int initQueue(SqQueue *Q);
 30
 31 int isEmpty(SqQueue *Q);
 32
 33 int isFull(SqQueue *Q);
 34
 35 int enQueue(SqQueue *Q,Point e);
 36
 37 int deQueue(SqQueue *Q,Point *e);
 38
 39 int main(void)
 40 {
 41
 42     char choice;
 43
 44     Point temp;
 45
 46     SqQueue *Q = (SqQueue *)malloc(sizeof(SqQueue));    //声明队列
 47
 48     initQueue(Q);                                        //构造队列
 49
 50     printf("请选择操作:\n"
 51
 52         "a:入队    b:出队    q:退出\n");
 53
 54     while(scanf("%c", &choice) == 1)
 55     {
 56         //元素入队
 57
 58         if(choice == ‘a‘)
 59         {
 60
 61             printf("请输入点名:\n");
 62
 63             scanf("%s", &temp.name);
 64
 65             printf("请输入点号:\n");
 66
 67             scanf("%s", &temp.id);
 68
 69             printf("请输入x坐标:\n");
 70
 71             scanf("%f", &temp.x);
 72
 73             printf("请输入y坐标:\n");
 74
 75             scanf("%f", &temp.y);
 76
 77             printf("请输入z坐标:\n");
 78
 79             scanf("%f", &temp.z);
 80
 81             enQueue(Q, temp);                                //插入元素到队尾
 82
 83             fflush(stdin);                                    //清空输入缓存
 84
 85             printf("请选择操作:\n"
 86
 87                 "a:入队    b:出队    q:退出\n");
 88         }
 89
 90         //元素出队
 91         else if(choice == ‘b‘)
 92         {
 93             //删除失败的情况
 94
 95             if(deQueue(Q, &temp) == -1)
 96
 97             {
 98
 99                 fflush(stdin);                                    //清空输入缓存
100
101                 printf("请选择操作:\n"
102
103                     "a:入队    b:出队    q:退出\n");
104
105                 continue;
106
107             }
108
109             printf("删除的节点的信息为:\n"
110
111                 "点名:%s\n"
112
113                 "点号:%s\n"
114
115                 "x坐标:%.2f\n"
116
117                 "y坐标:%.2f\n"
118
119                 "z坐标:%.2f\n",
120
121                 temp.name, temp.id, temp.x, temp.y, temp.z);
122
123             fflush(stdin);                                    //清空输入缓存
124
125             printf("请选择操作:\n"
126
127                 "a:入队    b:出队    q:退出\n");
128
129         }
130
131         //退出
132
133         else if(choice == ‘q‘)
134
135             break;
136
137         //输入错误
138
139         else
140
141         {
142
143             fflush(stdin);                                    //清空输入缓存
144
145             printf("输入错误,输入应该为‘a’或‘b’或‘q’!\n"
146
147                 "请选择操作:\n"
148
149                 "a:入队    b:出队    q:退出\n");
150
151         }
152
153     }
154
155     free(Q->base);
156
157     free(Q);
158
159     printf("Done!\n");
160
161     return 0;
162
163 }
164
165 //构造一个空队列
166
167 int initQueue(SqQueue *Q)
168
169 {
170
171     Q->base=(Point *)malloc(MAXSIZE * sizeof(Point));
172
173     if(!Q->base)
174
175     {
176
177         printf("分配空间错误,初始化失败!\n");
178
179         return -1;
180
181     }
182
183     Q->front = Q->rear = 0;
184
185     printf("队列初始化成功!\n");
186
187     return 0;
188
189 }
190
191 //判断队列是否为空
192
193 int isEmpty(SqQueue *Q)
194
195 {
196
197     if(Q->front == Q->rear)
198
199         return 1;
200
201     else
202
203         return 0;
204
205 }
206
207 //判断队列是否为满
208
209 int isFull(SqQueue *Q)
210
211 {
212
213     if(Q->front == (Q->rear + 1) % MAXSIZE)
214
215         return 1;
216
217     else
218
219         return 0;
220
221 }
222
223 //插入元素e为Q的新队尾元素
224
225 int enQueue(SqQueue *Q,Point e)
226 {
227
228     if(isFull(Q))
229
230     {
231
232         printf("队列已满,插入失败!\n");
233
234         return -1;
235
236     }
237
238
239
240     Q->base[Q->rear] = e;
241
242     Q->rear = (Q->rear + 1) % MAXSIZE;
243
244     printf("插入成功!\n");
245
246     return 0 ;
247
248 }
249
250 //删除Q的队头元素,用e返回其值
251
252 int deQueue(SqQueue *Q,Point *e)
253
254 {
255
256     if(isEmpty(Q))
257
258     {
259
260         printf("队列为空,删除失败!\n");
261
262         return -1;
263
264     }
265     *e = Q->base[Q->front];
266
267     Q->front = (Q->front + 1) % MAXSIZE;
268
269     printf("删除成功!\n");
270
271     return 0;
272
273 }       

XHqueue

我用Dev-C++的环境编译之后的结果如下,这里我任意输入了几个例子,以供大家体会:

时间: 2024-07-30 09:02:41

队列及其实现的相关文章

redis 学习 四 队列

<?php /** * redis实战 * * 利用列表list实现简单队列 * * @example php cache.php */ header('content-type:text/html;chaeset=utf-8'); $redis = new \Redis(); $redis->connect('127.0.0.1', 6379); // 进队列 $userId = mt_rand(000000, 999999); $redis->rpush('QUEUE_NAME',j

构建队列,数组版本

队列作为基本的数据结构,是每个coder所必须掌握的. 队列在逻辑上就像是一条打饭的长队,排在前面的先打到饭(先进先出). 这里用一个数组用以构造一个队列,并设置两个指向,head指向队首,tail指向队尾,初始状态是head与tail指向同一位置(队列为空) 队列有两个操作:入队与出队. 1.入队:对比打饭排队的场景,新来的人排在后面,这是队尾tail需向后移一位. 2.出队:已经打好饭的人就可以出去了,这时队头也需向后移一位,让后面的人成为队头. 注意: 当head与tail都移到数组末端,

链队列代码及应用

链队列代码 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #define OK 1 #define ERROR 0 #define OVERFLOW -2 #define TRUE 1 #define FALSE 0 typedef int Status; typedef int ElemType; typedef struct Qnode{ int

caffe数据读取的双阻塞队列说明

caffe的datareader类中 class QueuePair { public: explicit QueuePair(int size); ~QueuePair(); BlockingQueue<T*> free_; BlockingQueue<T*> full_; DISABLE_COPY_AND_ASSIGN(QueuePair); }; 这个就是双阻塞队列,先将free队列填充到最大长度,然后按照如下规则: 1,每当生产者push时,先将full队列pop,如果fu

线性结构的常见应用之一 队列

定义:一种可以实现"先进先出"的存储结构 分类 链式队列 --  用链表实现 静态队列 --  用数组实现 静态队列通常都必须是循环队列 循环队列的讲解: 1.静态队列为什么必须是循环队列 2.循环队列需要几个参数来确定   需要两个参数来进行确定:front   rear 3.循环队列各个参数的含义 2个参数在不同的场合有不同的含义 建议初学者先记住,后面再想 1).队列初始化 front 和 rear 的值都是零 2).队列非空 front 代表的是队列的第一个元素 rear 代表

阻塞队列和生产者-消费者模式

阻塞队列提供了可阻塞的put和take方法.如果队列满了put将阻塞到有空间可用,如果队列为空,take将阻塞到有元素可用.队列可以是有界和无界的,无界的队列put将不会阻塞. 阻塞队列支持生产者消费者模式,该模式将找出需要完成的工作,和执行工作分开.生产者-消费者模式能简化开发过程,因为消除了生产者和消费者之间的代码依赖性,此外,该模式还将生产数据的过程和使用数据的过程解耦开来. 在基于阻塞队列构建的生产者-消费者设计中个,当数据生成时,生产者把数据放入队列,当消费者处理数据时,将从队列中获取

MQ队列管理器搭建(一)

多应用单MQ使用场景 如上图所示,MQ独立安装,或者与其中一个应用同处一机.Application1与Application2要进行通信,但因为跨系统,所以引入中间件来实现需求. Application1需要连接MQ,并将消息放入队列Queue中,Application2同样连接MQ,监听在Queue队列上,一旦发现有消息进入则取出该消息进行处理. 下面将给出创建队列管理器和队列的示例: 定义队列管理器名称为Qm1,本地队列名称为Queue,服务器连接通道CHAN_SERVER_CON,监听端口

PHP电商订单自动确认收货redis队列

一.场景 之前做的电商平台,用户在收到货之后,大部分都不会主动的点击确认收货,导致给商家结款的时候,商家各种投诉,于是就根据需求,要做一个订单在发货之后的x天自动确认收货.所谓的订单自动确认收货,就是在在特定的时间,执行一条update语句,改变订单的状态. 二.思路 最笨重的做法,通过linux后台定时任务,查询符合条件的订单,然后update.最理想情况下,如果每分钟都有需要update的订单,这种方式也还行.奈何平台太小,以及卖家发货时间大部分也是密集的,不会分散在24小时的每分钟.那么,

快速入门系列--WCF--06并发限流、可靠会话和队列服务

这部分将介绍一些相对深入的知识点,包括通过并发限流来保证服务的可用性,通过可靠会话机制保证会话信息的可靠性,通过队列服务来解耦客户端和服务端,提高系统的可服务数量并可以起到削峰的作用,最后还会对之前的事务知识做一定补充. 对于WCF服务来说,其寄宿在一个资源有限的环境中,为了实现服务性能最大化,需要提高其吞吐量即服务的并发性.然而在不进行流量控制的情况下,并发量过多,会使整个服务由于资源耗尽而崩溃.因此为相对平衡的并发数和系统可用性,需要设计一个闸门(Throttling)控制并发的数量. 由于

Python3-queue模块-同步队列

Python3中的queue模块实现多生产者,多消费者队列,特别适用于多个线程间的信息的安全交换,主要有三个类 queue.Queue(maxsize=0) 构造一个FIFO(先进先出)的队列 queue.LifoQueue(maxsize=0) 构造一个LIFO(后进先出)的队列 queue.PriorityQueue(maxsize=0) 构造一个具有优先级的队列,存储的是一个元组(n, value),n为数字代表优先级,数字越小,级别越高 这个模块定义了两个异常 queue.Empty 如