数据结构之循环队列

4.10 队列的定义
队列定义:一种先进先出的线性表。允许插入的一端称为队尾,允许删除的一端称为队头。

        队头                           队尾
出队列   a1   a2   a3   a4    .....    an  入队列

队列有类似线性表的各种操作,不同的就是插入数据只能在队尾进行,删除数据只能在队头进行。

线性表有线性存储和链式存储。栈是线性表,有这两种存储方式。
队列作为一种特殊的线性表,也有这两种存储方式。先看队列的线性储存结构。
4.12 循环队列
4.12.1 队列顺序存储的不足

为了避免当只有一个元素时,队头和队尾重合使处理变得麻烦,所以引入两个指针,front指针指向队头元素,rear指针指向队尾元素的下一个位置,这样当front等于rear时,此队列不是还剩一个元素,而是空队列。(删除)

假溢出:假设这个队列的总个数不超过5个,但目前如果接着入队的话,因数组末尾元素已经占用,再向后加,就会产生数组越界的错误,可实际上,我们的队列在下标为0和1的地方还是空闲的。这种现象“假溢出”。


4.12.2 循环队列的定义
所以假溢出的问题就是后面满了就再从头开始,也就是头尾相接的循环。
把队列的这种头尾相接的顺序存储结构称为循环队列。

(1)此时问题是,我们刚才说,空队列时,front等于rear时,现在当队列满时,也是front等于rear,那么如何判断此时的队列究竟是空还是满?(元素入队)
(2)办法一设置一个标志变量flag,当front == rear,且flag = 0时为队列空,当front == rear,且flag = 1时为队列满。
(3)办法二是当队列空时,条件就是front == rear,当队列满时,我们修改其条件,保留一个元素空间。也就是说,队列满时,数组中还有一个空闲单元。

重点讨论第二种方法,由于rear的值可能比front大,也可能比front小,所以尽管他们只相差一个位置时就是满的情况,但也有可能相差整一圈。
所以队列满的条件是  (rear+1)%数组长度 == front 取模的目的就是为了整合rear和front大小为一个问题。

通用的计算队列长度的公式:

(rear - front + 数组长度)% 数组长度

循环队列实现代码如下:

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

//宏定义数组长度
#define LENGTH  6

//循环队列的顺序存储结构
typedef struct Qqueue
{
int *pbase;  //指针指向数组
int front;   //头指针
int rear;    //尾指针,若队列不为空,指向队列尾元素的下一个位置
// int length;  数组长度放这里不合适  
} queue, *pqueue;


//函数声明
//初始化空队列
void init_queue(pqueue list);
//队列满判断
bool full_queue(pqueue list);
//入队操作
bool en_queue(pqueue list,int val);
//队列空操作
bool empty_queue(pqueue list);
//出队操作
bool de_queue(pqueue list,int *val);
//遍历输出
void tranverse_queue(pqueue list);
//返回队列元素个数
int num_queue(pqueue list);


int main(void)
{
queue list; //定义一个队列元素

int val = 0;
int num = 0;

init_queue(&list);
en_queue(&list,1);
en_queue(&list,2);
en_queue(&list,3);
en_queue(&list,4);
en_queue(&list,5);
en_queue(&list,6);

tranverse_queue(&list);
num = num_queue(&list);
printf("队列的元素个数num = %d.\n",num);
if(de_queue(&list,&val))
{
printf("出队成功,出队的元素是:%d.\n",val);
}
else
{
printf("出队失败!\n");
}


tranverse_queue(&list);
num = num_queue(&list);
printf("队列的元素个数num = %d.\n",num);
return 0;
}


//初始化一个空队列,数组的长度length放这里也不合适
void init_queue(pqueue list)
{
list->pbase = (int *)malloc(sizeof(int) * LENGTH);
if(NULL == list->pbase)
{
printf("分配内存失败!\n");
exit(-1);
}
else
{
list->front = 0;
list->rear = 0;
}


return ;
}
//队列满的判断
bool full_queue(pqueue list)
{
if( (list->rear+1)% LENGTH == list->front )
{
return true;
}
else
{
return false;
}
}
//入队
bool en_queue(pqueue list,int val)
{
if(full_queue(list))
{
return false;
}
else
{
list->pbase[list->rear] = val;
list->rear = (list->rear + 1) % LENGTH;


return true; 
}
}
//队列遍历输出
void tranverse_queue(pqueue list)
{
int i;
i = list->front;


while(i != list->rear)
{
printf("%d ",list->pbase[i]);
i = (i + 1) % LENGTH;
}


printf("\n");
}
//判断队列为空
bool empty_queue(pqueue list)
{
if(list->front == list->rear)
{
return true;
}
else
{
return false;
}
}
//出队
bool de_queue(pqueue list,int *val)
{
if(empty_queue(list))
{
return false;
}
else
{
*val = list->pbase[list->front];
list->front = (list->front + 1) % LENGTH;


return true;
}
}
//返回队列元素个数
int num_queue(pqueue list)
{
int num;
num = (list->rear - list->front + LENGTH) % LENGTH;

return num;
}


出自:大话数据结构、严蔚敏老师之 数据结构
1.1 数组和字符串 2 1.1.1 一维数组的倒置 2 范例1-1 一维数组的倒置 2 ∷相关函数:fun函数 1.1.2 一维数组应用 3 范例1-2 一维数组应用 3 1.1.3 一维数组的高级应用 5 范例1-3 一维数组的高级应用 5 1.1.4 显示杨辉三角 7 范例1-4 显示杨辉三角 7 ∷相关函数:c函数 8 1.1.5 魔方阵 9 范例1-5 魔方阵 9 1.1.6 三维数组的表示 14 范例1-6 三维数组的表示 14 ∷相关函数:InitArray函数 1.1.7 多项式的数组表示 17 范例1-7 多项式数组的表示 17 1.1.8 查找矩阵的马鞍点 19 范例1-8 查找矩阵的马鞍点 19 ∷相关函数:Get_Saddle函数 1.1.9 对角矩阵建立 21 范例1-9 对角矩阵建立 21 ∷相关函数:Store函数 1.1.10 三对角矩阵的建立 22 范例1-10 三对角矩阵的建立 22 ∷相关函数:Store函数 1.1.11 三角矩阵建立 24 范例1-11 三角矩阵建立 24 ∷相关函数:Store函数 1.1.12 对称矩阵的建立 25 范例1-12 对称矩阵的建立 25 ∷相关函数:store函数 1.1.13 字符串长度的计算 28 范例1-13 字符串长度的计算 28 ∷相关函数:strlen函数 1.1.14 字符串的复制 29 范例1-14 字符串的复制 29 ∷相关函数:strcpy函数 1.1.15 字符串的替换 31 范例1-15 字符串的替换 31 ∷相关函数:strrep函数 1.1.16 字符串的删除 33 范例1-16 字符串的删除 33 ∷相关函数:strdel函数 1.1.17 字符串的比较 35 范例1-17 字符串的比较 35 ∷相关函数:strcmp函数 1.1.18 字符串的抽取 36 范例1-18 字符串的抽取 36 ∷相关函数:substr函数 1.1.19 字符串的分割 38 范例1-19 字符串的分割 38 ∷相关函数:partition函数 1.1.20 字符串的插入 40 范例1-20 字符串的插入 40 ∷相关函数:insert函数 1.1.21 字符串的匹配 42 范例1-21 字符串的匹配 42 ∷相关函数:nfind函数 1.1.22 字符串的合并 43 范例1-22 字符串的合并 43 ∷相关函数:catstr函数 1.1.23 文本编辑 45 范例1-23 文本编辑 45 ∷相关函数:StrAssign函数 1.2 栈和队列 54 1.2.1 用数组仿真堆栈 54 范例1-24 用数组仿真堆栈 54 ∷相关函数:push函数 pop函数 1.2.2 用链表仿真堆栈 57 范例1-25 用链表仿真堆栈 57 ∷相关函数:push函数 pop函数 1.2.3 顺序栈公用 59 范例1-26 顺序栈公用 59 ∷相关函数:push函数 pop函数 1.2.4 进制转换问题 61 范例1-27 进制转换问题 61 ∷相关函数:MultiBaseOutput函数 1.2.5 顺序队列操作 64 范例1-28 顺序队列操作 64 ∷相关函数:push函数 pop函数 1.2.6 循环队列 66 范例1-29 循环队列 66 ∷相关函数:EnQueue函数 DeQueue函数 1.2.7 链队列的入队、出队 69 范例1-30 链队列入队、出队 69 ∷相关函数:push函数 pop函数 1.2.8 舞伴问题 71 范例1-31 舞伴问题 71 ∷相关函数:EnQueue函数 DeQueue函数 DancePartner函数 1.3 链表 75 1.3.1 头插法建立单链表 75 范例1-32 头插法建立单链表 75 ∷相关函数:createlist函数 1.3.2 限制链表长度建立单链表 77 范例1-33 限制链表长度建立长单链表 77 ∷相关函数:createlist函数 1.3.3 尾插法建立单链表 79 范例1-34 尾插法建立单链表 79 ∷相关函数:createlist函数 1.3.4 按序号查找单链表 80 范例1-35 按序号查找单链表 80 ∷相关函数:getnode函数 1.3.5 按值查找单链表 82 范例1-36 按值查找单链表 82 ∷相关函数:locatenode函数 1.3.6 链表的插入 84 范例1-37 链表的插入 84 ∷相关函数:insertnode函数 1.3.7 链表的删除 86 范例1-38 链表的删除 86 ∷相关函数:deletelist函数 1.3.8 归并两个单链表 88 范例1-39 归并两个单链表 88 ∷相关函数:concatenate函数 1.3.9 动态堆栈 90 范例1-40
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值