1.队列的定义
一种可是实现“先进先出”的存储结构(像是火车站买票一样,后面添加,前面删除)
2.队列的分类
链式队列:用链表实现
静态队列:用数组实现(静态队列通常都必须是循环队列,为了减少内存浪费)
3.循环队列的讲解
3.1静态队列为什么必须是循环队列?
因为如果是普通的数组,当增加,删除元素(入队,出队)的时候rear和front都是往上移动,这样的话下面的空间就不能利用了,浪费空间
附图说明:
3.2循环队列需要几个参数来确定 及其含义
需要2个参数来确定
front
rear
3.3 循环队列各个参数的含义
2个参数不同场合不同的含义?
1)队列初始化
front和rear的值都是零
2)队列非空
front代表队列的第一个元素
rear代表了最后一个有效元素的下一个元素
3)队列空
front和rear的值相等,但是不一定是零
4.循环队列算法
4.1循环队列入队伪算法
两步完成:
1)将值存入r所代表的位置
2)将r后移,正确写法是 rear = (rear+1)%数组长度
错误写法:rear=rear+1;
bool en_queue(QUEUE *pQ,int val)
{
if (full_queue(pQ))
return false;
else
{
pQ->pBase[pQ->rear] = val;
pQ->rear = (pQ->rear + 1) % 6;
return true;
}
}
4.2循环队列出队伪算法讲解
front = (front+1) % 数组长度
bool out_queue(QUEUE * pQ, int *pVal)
{
if (empty_queue(pQ))
return false;
else
{
*pVal = pQ->pBase[pQ->front];
pQ->front = ((pQ->front) + 1) % 6;
return true;
}
}
4.3如何判断循环队列是否为空
如果front与rear的值相等,
则队列一定为空
bool empty_queue(QUEUE * pQ)
{
if (pQ->front == pQ->rear)
return true;
else
return false;
}
4.4如何判断循环队列是否已满
预备知识:
front的值和rear的值没有规律,
即可以大,小,等。
两种方式:
1、多增加一个表标识的参数
2、少用一个队列中的元素(才一个,不影响的)
通常使用第二种方法
如果r和f的值紧挨着,则队列已满
用C语言伪算法表示就是:
if( (r+1)%数组长度 == f )
已满
else
不满
bool full_queue(QUEUE * pQ)
{
if ((pQ->rear) + 1 == pQ->front)
return true;
else
return false;
}
附图讲解:
注意:这里有些错误,第5个元素应该为空,循环队列中为了好判断队列已满这种情况,会浪费掉一个空间,所以这里的f值去掉就正确了,所以说,一般初始化了m个数组大小空间,有用的只有m-1个。
4.5队列的初始化,主函数,遍历
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Queue {
int * pBase;//假设的存储的是int型实际可是任何类型,pBase存储第一个元素的地址
int front;//下标
int rear;//下标
}QUEUE;
void init(QUEUE *);
bool en_queue(QUEUE *,int );
void traverse_queue(QUEUE *);
bool full_queue(QUEUE *);
bool out_queue(QUEUE *, int *);
bool empty_queue(QUEUE *);
int main()
{
QUEUE Q;
int val;
init(&Q);//没有初始化编译时没有问题,但是运行时会出现问题
/*en_queue(&Q, 1);
en_queue(&Q, 2);
en_queue(&Q, 3);
en_queue(&Q, 4);
en_queue(&Q, 5);
traverse_queue(&Q);*/
if (out_queue(&Q, &val))
printf("出队的值为:%d\n", val);
else
printf("出队失败!\n");
//traverse_queue(&Q);
system("pause");
return 0;
}
void init(QUEUE * pQ)//初始化一般不要返回值
{
pQ->pBase = (int*)malloc(sizeof(int) * 6);
pQ->front = pQ->rear = 0;
}
void traverse_queue(QUEUE *pQ)
{
int i=pQ->front;
for (i;i != pQ->rear;i=(i+1)%6)
{
printf("%d,", pQ->pBase[i]);
}//这跟下面的语句相同效果
/*while (i != pQ->rear)
{
printf("%d,", pQ->pBase[i]);
i = (i + 1) % 6;
}*/
printf("\n");
return;
}
5.队列的具体应用:
所有和事件有关的操作都有队列的影子。
(例如操作系统认为先进来的先处理)