/*
一、关于静态队列的约定(目的是在C语言中描述方便)
1.定义:和栈相反,队列是一种先进先出的线性表,它只允许在表的一端进行插入,在另一端进行删除元素。在队列中,允许插入的一端叫队尾,允许删除的一端较队头,即入队只能从队尾入,出队只能从队头出。
2.初始化建空队列时,令front=rear=0;入队时,队尾指针rear增1;出队时队头指针增1。在非空队列中,队头指针front始终指向队列头元素,而队尾指针rear始终指向队列尾元素的下一个位置。
3.在C语言中不能使用动态分配的一维数组来实现循环队列。如果用户程序中有循环队列,则必须为它设定一个最大队列长度,若用户无法预估所用队列最大长度,则宜采用链队列。
*/
#include "ArrayQueue.h"
void arrayQueueCreat(struct arrayQueue * qQ,int lengh)
{
qQ->pBase =(int *)malloc(sizeof(int)*lengh);
if( NULL == qQ->pBase )
{
printf("arrayQueueCreat(): malloc failed!\n");
exit(-1);
}
qQ->arrayLen = lengh;
qQ->queueLen = 0;
qQ->front = 0;
qQ->rear = 0;
}
int arrayQueueIsFull(struct arrayQueue * qQ)
{
if( qQ->front == (qQ->rear+1)%(qQ->arrayLen) )
return 1;
else
return 0;
}
int arrayQueueIsEmpty(struct arrayQueue * qQ)
{
if( qQ->front == qQ->rear )
return 1;
else
return 0;
}
//入队
int enArrayQueue(struct arrayQueue * qQ,int val)
{
if( 1 == arrayQueueIsFull(qQ) )
{
printf("the array queue is full\n");
return 0;
}
qQ->pBase[qQ->rear] = val;//在队尾入
qQ->rear = (qQ->rear+1)%(qQ->arrayLen);
qQ->queueLen++;
return 1;
}
//出队
int outArrayQueue(struct arrayQueue * qQ,int * pVal)
{
if( 1 == arrayQueueIsEmpty(qQ) )
{
printf("the array queue is empty\n");
return 0;
}
*pVal = qQ->pBase[qQ->front];//在队头出
qQ->front = (qQ->front+1)%(qQ->arrayLen);
qQ->queueLen--;
return 1;
}
void traverseArrayQueue(struct arrayQueue * qQ)
{
int i=0;
i = qQ->front;//从队头开始遍历
while( i != qQ->rear )
{
printf("qQ->pBase[%d] = %d\n",i,qQ->pBase[i]);
i = (i+1)% (qQ->arrayLen);
}
printf("\n");
return;
}
相关头文件:
#ifndef ARRAYQUEUE_H
#define ARRAYQUEUE_H
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
struct arrayQueue
{
int * pBase;
int arrayLen;
int queueLen;
int front;
int rear;
};
void arrayQueueCreat(struct arrayQueue * qQ,int lengh);
int arrayQueueIsFull(struct arrayQueue * qQ);
int arrayQueueIsEmpty(struct arrayQueue * qQ);
int enArrayQueue(struct arrayQueue * qQ,int val);
int outArrayQueue(struct arrayQueue * qQ,int * pVal);
void traverseArrayQueue(struct arrayQueue * qQ);
#endif
队列相关约定:
1. 出队只能从对头出,入队只能从队尾入。
2. 对头一般用front的值表示,它表示队列的第一个有效元素,rear表示队尾的下一个元素。
3. 如果队列长度有限,最好用静态数组实现队列,如果队列长度长且不定,最好用动态链表实现。
4. 如果用普通数组实现队列,由于数组长度是固定的,因此必须是循环队列,因为出队front的值必须加一,入队rear的值也必须加一,如果队列不循环,数组的元素长度又是固定的,那么随着不断的出队和入队,就会导致数组的很多元素不属于队列或也造成数组访问越界。
5. 循环队列核心两个参数,一个front,一个rear。两个参数不同场合不同含义:
(1)队列的初始化
front和rear的值都为0
(2)队列非空
front代表队列的第一个元素,rear代表队列最后一个有效元素的下一个元素
(3)队列空
front和rear的值相等,但是不一定为0
6. 入队伪算法
(1)将值存入rear所代表的位置
(2)并且让rear = (rear+1) % (数组的长度),这样做的目的是当rear到达数组的最后一个元素时,再次插入一个元素,rear的值能等于数组第一个元素的下标即0,实现循环。
注意(n-1) % n = n-1。
9. 出队伪算法
front = (front+1) % (数组的长度)
10. 如何判断循环队列是否为空
如果front与rear的值相等,则该队列就一定为空。(前提是长度为n的数组,队列长度为n-1)
11. 如何判断循环队列是否为满
(0)front与rear的值没有必要关联,front有可能比rear小,大,或相等。
(1)当front=rear时,并且判断队列长度是否等于数组长度,如果相等,那么就代表已满。这样做的弊端是要时刻关注这个标记,不简洁。注意如果不增加这个标记那么就和如何判断队列为空矛盾了。
(2)严格控制队列的长度为n-1,数组长度为n,这样front与rear相邻时,就认为队列为满,这样虽然会浪费一个元素,但是避免跟踪一个标记,比较灵活,常用。
12. 队列的算法与应用
主要是入队和出队。只要与时间相关的都可以用到队列,比如操作系统中job调度算法。有些队列是广义的队列,比如操作系统中的消息队列,往往会根据任务或job的优先级选择把job插入到队列的队尾或队头。
如果插入到对头,那么front的值就要减减。