数据结构 - 顺序队列的实行(C语言)
一、什么是顺序队列?
队列的顺序储存结构:用数组存储队列,为了避免当只有一个元素时,队头和队尾重合使得处理变得麻烦,所以引入两个指针:front 指针指向队头元素,rear 指针指向队尾元素的下一个位置,当 front=rear 时,为空队列,结构如下图所示:
顺序队列的结构代码如下:
typedef int ElemType; /* ElemType类型根据实际情况而定,这里假设为int */
/* 循环队列的顺序存储结构 */
typedef struct
{
ElemType data[MAXSIZE];
int front; /* 头指针 */
int rear; /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
}SeqQueue;
假设是长度为 5 的数组,初始状态,空队列如下图左所示,front 与 rear 指针均指向下标为 0 的位置。然后入队 a1、a2、a3、a4,front 指针依然指向下标为 0 位置,而 rear 指针指向下标为 4 的位置,如下图右所示:
出队 a1、a2,则 front 指针指向下标为 2 的位置,rear 不变,如下图左所示,再入队 a5,此时 front 指针不变,rear 指针移动到数组之外。数组之外, 那将是哪里?如下图右所示:
问题还不止于此。假设这个队列的总个数不超过5个,但目前如果接着入队的话,因数组末尾元素已经占用,再向后加,就会产生数组越界的错误,可实际上,我们的队列在下标为0和1的地方还是空闲的。我们把这种现象叫做 “假溢出"。
二、什么是顺序循环队列?
所以解决 "假溢出" 的办法就是后面满了,就再从头开始,也就是头尾相接的循环。我们把队列的这种头尾相接的顺序存储结构称为顺序循环队列。
刚才的例子继续,上图的 rear 可以改为指向下标为 0 的位置,这样就不会造成指针指向不明的问题了,如下图所示:
接着入队 a6,将它放置于下标为 0 处,rear 指针指向下标为 1 处,如下图左所示。若再入队 a7,则 rear 指针就与 front 指针重合,同时指向下标为 2 的位置,如下图右所示:
此时问题又出来了,我们刚才说,空队列时,front 等于 rear,现在当队列满时,也是 front 等于 rear,那么如何判断此时的队列究竟是空还是满呢?
- 办法一是设置一个标志变量 flag, 当 front == rear,且 flag = 0 时为队列空,当 front== rear,且 flag= 1 时为队列满。
- 办法二是当队列空时,条件就是 front = rear,当队列满时,我们修改其条件,保留一个元素空间。也就是说,队列满时,数组中还有一个空闲单,例如下图所示,我们就认为此队列已经满了,也就是说,我们不允许上图右的情况出现:
我们重点来讨论第二种方法,由于 rear 可能比 front 大,也可能比 front 小,所以尽管它们只相差一个位置时就是满的情况,但也可能是相差整整一圈。 所以若队列的最大尺寸为 QueueSize,那么队列满的条件是(rear+1) % QueueSize == front
,因此通用的计算队列长度公式为:(rear - front + QueueSize) % QueueSize
。
注意:front 指针和 rear 指针后移不能直接使用 ++,而要使用Q->front = (Q->front + 1) % MAXSIZE
,因为到达数组尾后需要移动到数组开头。
三、基本操作
3.1 初始化队列操作
实现代码如下:
// 初始化队列操作
Status initQueue(SeqQueue *Q)
{
Q->front = 0;
Q->rear = 0;
return TRUE;
}
3.2 入队操作
实现代码如下:
// 入队操作
Status enQueue(SeqQueue *Q, const ElemType e)
{
// 判断队列是否已满
if ((Q->rear + 1) % MAXSIZE == Q->front)
return FALSE;
Q->data[Q->rear] = e; // 将元素e赋值给队尾
Q->rear = (Q->rear + 1) % MAXSIZE; // rear指针向后移一位置,若到最后则转到数组头部
return TRUE;
}
3.3 出队操作
实现代码如下:
// 出队操作
Status deQueue(SeqQueue *Q, ElemType *e)
{
// 判断是否为空队
if (Q->front == Q->rear)
return FALSE;
*e = Q->data[Q->front]; // 将队头元素赋值给e
Q->front = (Q->front + 1) % MAXSIZE; // front指针向后移一位置,若到最后则转到数组头部
return TRUE;
}
3.3 遍历队列操作
实现代码如下:
// 遍历队列操作
Status tarverseQueue(const SeqQueue Q)
{
int cur = Q.front; // 当前指针
while (cur != Q.rear) // 直到cur指向了队尾元素的下一个位置,即Q.rear,结束循环
{
printf("%d ", Q.data[cur]);
cur = (cur + 1) % MAXSIZE; // 当前指针向后推移
}
printf("\n");
return TRUE;
}
四、完整程序
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define MAXSIZE 5 /* 存储空间初始分配量 */
typedef int Status;
typedef int ElemType; /* ElemType类型根据实际情况而定,这里假设为int */
/* 顺序循环队列的顺序存储结构 */
typedef struct
{
ElemType data[MAXSIZE];
int front; // 头指针
int rear; // 尾指针,若队列不空,指向队列尾元素的下一个位置
}SeqQueue;
Status initQueue(SeqQueue *Q); // 初始化队列操作
Status enQueue(SeqQueue *Q, const ElemType e); // 入队操作
Status deQueue(SeqQueue *Q, ElemType *e); // 出队操作
Status tarverseQueue(const SeqQueue Q); // 遍历队列操作
Status clearQueue(SeqQueue *Q); // 清空队列操作
Status isEmpty(const SeqQueue Q); // 判断是否为空队列
Status getHead(const SeqQueue Q, ElemType *e); // 获得队头元素
int getLength(const SeqQueue Q); // 获得队列的长度
// 初始化队列操作
Status initQueue(SeqQueue *Q)
{
Q->front = 0;
Q->rear = 0;
return TRUE;
}
// 入队操作
Status enQueue(SeqQueue *Q, const ElemType e)
{
// 判断队列是否已满
if ((Q->rear + 1) % MAXSIZE == Q->front)
return FALSE;
Q->data[Q->rear] = e; // 将元素e赋值给队尾
Q->rear = (Q->rear + 1) % MAXSIZE; // rear指针向后移一位置,若到最后则转到数组头部
return TRUE;
}
// 出队操作
Status deQueue(SeqQueue *Q, ElemType *e)
{
// 判断是否为空队
if (Q->front == Q->rear)
return FALSE;
*e = Q->data[Q->front]; // 将队头元素赋值给e
Q->front = (Q->front + 1) % MAXSIZE; // front指针向后移一位置,若到最后则转到数组头部
return TRUE;
}
// 遍历队列操作
Status tarverseQueue(const SeqQueue Q)
{
int cur = Q.front; // 当前指针
while (cur != Q.rear) // 直到cur指向了队尾元素的下一个位置,即Q.rear,结束循环
{
printf("%d ", Q.data[cur]);
cur = (cur + 1) % MAXSIZE; // 当前指针向后推移
}
printf("\n");
return TRUE;
}
// 清空队列操作
Status clearQueue(SeqQueue *Q)
{
Q->front = Q->rear = 0;
return TRUE;
}
// 判断是否为空队列
Status isEmpty(const SeqQueue Q)
{
return Q.front == Q.rear ? TRUE : FALSE;
}
// 获得队头元素
Status getHead(const SeqQueue Q, ElemType *e)
{
if (Q.front == Q.rear) // 判断是否为空队列
return FALSE;
*e = Q.data[Q.front];
return TRUE;
}
// 获得队列的长度
int getLength(const SeqQueue Q)
{
return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}
int main()
{
SeqQueue Q;
// 初始化队列
initQueue(&Q);
// 入队操作
for (int i = 0; i < MAXSIZE - 1; i++)
enQueue(&Q, i);
printf("入队操作(0、1、2、3)! \n\n");
// 出队操作
ElemType d;
deQueue(&Q, &d);
printf("删除的元素是%d \n\n", d);
// 遍历队列
printf("遍历队列: ");
tarverseQueue(Q);
printf("\n");
// 判断是否为空队列
printf("现在队列空否? %u (1:空 0:否)\n\n", isEmpty(Q));
// 获得队列的长度
printf("队列长度为: %d \n\n", getLength(Q));
// 获得队头元素
getHead(Q, &d);
printf("队头元素是%d \n\n", d);
return 0;
}
输出结果如下图所示:
参考:
《大话数据结构 - 第4章》 栈与队列
数据结构 - 顺序队列的实行(C语言)的更多相关文章
- 数据结构——顺序队列(sequence queue)
/* sequenceQueue.c */ /* 顺序队列 */ #include <stdio.h> #include <stdlib.h> #include <std ...
- 数据结构 - 顺序栈的实行(C语言)
数据结构-顺序栈的实现 1 顺序栈的定义 既然栈是线性表的特例,那么栈的顺序存储其实也是线性表顺序存储的简化,我们简称为顺序栈.线性表是用数组来实现的,对于栈这种只能一头插入删除的线性表来说,用数组哪 ...
- 数据结构 - 链队列的实行(C语言)
数据结构-链队列的实现 1 链队列的定义 队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已, 我们把它简称为链队列.为了操作上的方便,我们将队头指针指向链队列的头结点,而队尾指针指 ...
- C语言数据结构-循环队列的实现-初始化、销毁、清空、长度、队列头元素、插入、删除、显示操作
1.数据结构-循环队列的实现-C语言 #define MAXSIZE 100 //循环队列的存储结构 typedef struct { int* base; //基地址 int _front; //头 ...
- 队列的含义以及C语言实现顺序队列
队列,和栈一样,也是一种对数据的"存"和"取"有严格要求的线性存储结构. 什么是队列 与栈结构不同的是,队列的两端都"开口",要求数据只能从 ...
- C语言顺序队列
顺序队列是一种只能在一头进和另一头出的数据结构,所以结构体里设2个指针分别指向头部和尾部,用数组来存储数据. #define MAXSIZE 1024 typedef int elemtype; ty ...
- C语言数据结构-顺序线性表的实现-初始化、销毁、长度、查找、前驱、后继、插入、删除、显示操作
1.数据结构-顺序线性表的实现-C语言 #define MAXSIZE 100 //结构体定义 typedef struct { int *elem; //基地址 int length; //结构体当 ...
- 数据结构Java实现07----队列:顺序队列&顺序循环队列、链式队列、顺序优先队列
一.队列的概念: 队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其 ...
- Javascript数据结构与算法--队列(顺序队列、优先队列、循环队列)的实现与用法
前言 队列和栈非常类似,前面已经讲过了栈的实现与用法,现在我们来说说队列. 队列介绍 队列遵循FIFO(First In First Out,先进先出)原则的一组有序的项. 队列是一种特殊的线性表,特 ...
随机推荐
- ModelAndView对象作用
ModelAndView ModelAndView对象有两个作用: 作用一 :设置转向地址,如下所示(这也是ModelAndView和ModelMap的主要区别) ModelAndView mv = ...
- 教你如何查看CAD文件是哪个版本的来自http://blog.sina.com.cn/s/blog_4c9fa4dd0101il1v.html
教你如何查看CAD文件是哪个版本的 http://blog.sina.com.cn/s/blog_4c9fa4dd0101il1v.html (2013-03-10 22:24:52) 转载▼ 标签: ...
- IntelliJ 中类似于Eclipse ctrl+q的是Ctrl+Shift+Backspace
IntelliJ 中类似于Eclipse ctrl+q的是Ctrl+Shift+Backspace 回到刚刚编辑的地方: ctrl+alt+Left 是回到刚刚浏览的地方,不一定是编辑的地方,可能已经 ...
- Linux 上运行 mapreduce 类型错误
1.ClassCastException 错误代码 /** * */ /** * @author hadoop * */ package WordCount; import java.io.IOExc ...
- ExpandableListView的使用以及信息的高亮显示
ExpandableListView是ListView控件的延伸,它能够对数据进行分组显示和隐藏,并统计总数量.可进行滚动,对某一内容高亮显示. <1>编写xml布局文件,用于获取Expa ...
- Angular2.x-显示heroes列表
在此页面中,您将展开Tour of Heroes应用程序以显示heroes列表,并允许用户选择heroes并显示heroes的详细信息. 6.X 你需要一些heroes来展示. 最终你会从远程数据服务 ...
- 战五渣系列之八(绝杀AOP)
开发不用aop.程序猿的人生该会浪费多少时间.我想是时候让程序猿打败alpha狗了.程序猿解救世界. 1.概念 面向切面编程.这意味着,一切不在流水线上的东西.包含权限.日志.缓存.校验.资源.事物. ...
- 【Mongodb教程 第一课 】 MongoDB下载安装
MongoDB是一个高性能,开源,无模式的文档型数据库,是当前NoSql数据库中比较热门的一种.它在许多场景下可用于替代传统的关系型数据库或键/值存储方式.Mongo使用C++开发.以window平台 ...
- PHP记录商品历史纪录
/* 记录浏览历史 */ if (!empty($_COOKIE['history'])) { if(stripos($_COOKIE['history'].',',$goods_id.',')=== ...
- 积跬步,聚小流------Bootstrap学习记录(3)
响应式作为Bootstrap的一大特色.栅格系统可谓是功不可没,既然如此,那我们就来看一下栅格系统是怎样帮助bootstrap实现响应式布局的呢? 1.什么是栅格系统 我们能够从Bootstrap的官 ...