队列是一种对数据的"存"和"取"受限制的线性存储结构。
与栈结构不同的是,队列的两端都"开口",要求数据只能从一端进,从另一端出,
通常,称进数据的一端为 “队尾”,出数据的一端为 “队头”,数据元素进队列的过程称为 “入队”,出队列的过程称为 “出队”。
队列的实现
队列存储结构的实现有以下两种方式:
顺序队列:在顺序表的基础上实现的队列结构;
链队列:在链表的基础上实现的队列结构;
顺序队列,即采用顺序表模拟实现的队列结构
顺序队列:队列的顺序存储结构称为顺序队列。它是运算受限的顺序表。
①和顺序表一样,顺序队列用一个向量空间来存放当前队列中的元素。
②由于队列的队头和队尾的位置是变化的,设置两个指针front和rear分别指示队头元素和队尾元素在向量空间中的位置,它们的初值在队列初始化时均应置为0。
1. AddQueue(ElemType x)
——在队列的尾部插入一个新的元素x。队尾的位置由rear指出。
2. DelQueue(Q)
——删除队列的队头的元素。队头的位置由front指出。
3. EmptyQueue(Q)
——测试队列Q是否为空队。当队列为空时返回一个真值,否则返回一个假值。
4. FrontQueue(Q)
——取得队列Q的队头元素。该运算与DelQ(Q)不同,后者要修改队头元素指针。
5. SetNULL(Q)
——创建一个空队Q,这个运算与线性表置空表类似。
顺序队列:队列的顺序存储结构称为顺序队列。它是运算受限的顺序表。
①和顺序表一样,顺序队列用一个向量空间来存放当前队列中的元素。
②由于队列的队头和队尾的位置是变化的,设置两个指针front和rear分别指示队头元素和队尾元素在向量空间中的位置,它们的初值在队列初始化时均应置为0。
解决“假溢出”的方法有两种:
(1) 采用平移元素的方法,即一旦发生“假溢出”就把整个队列的元素平移到存储区的首部。平移元素的方法效率是很低的。
(2) 将整个队列作为循环队列来处理,。这样,虽然物理上队尾在队首之前,但逻辑上队首仍然在前,作插入和删除运算时仍按"先进先出"的原则。
队列的顺序存储结构可描述为:
#define MAXSIZE 100
typedef int DATATYPE;
typedef struct tagQUEUE
{
DATATYPE elem[MAXSIZE];
int front, rear; //队列头和队列尾的位置标记
}QUEUE;
顺序队列的基本操作
①入队时:将新元素插入rear所指的位置,然后将rear加1。
②出队时:删去front所指的元素,然后将front加1并返回被删元素。
注意:
①当头尾指针相等时,队列为空。
②在非空队列里,队头指针始终指向队头元素,尾指针始终指向队尾元素的下一位置。
顺序队列中的溢出现象
① "下溢"现象
当队列为空时,做出队运算产生的溢出现象。“下溢”是正常现象,常用作程序控制转移的条件。
② "真上溢"现象
当队列满时,做进队运算产生空间溢出的现象。“真上溢”是一种出错状态,应设法避免。
③ "假上溢"现象
由于入队和出队操作中,头尾指针只增加不减小,致使被删元素的空间永远无法重新利用。当队列中实际的元素个数远远小于向量空间的规模时,也可能由于尾指针已超越向量空间的上界而不能做入队操作。该现象称为"假上溢"现象。
循环队列
为充分利用向量空间,克服"假上溢"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。
拥有MAXSIZE个数组元素的数组仅能表示一个长度为MAXSIZE-1的循环队列。
循环队列满的条件:(rear + 1) % MAXSIZE == front
循环队列空的条件:rear == front
循环队列出队:front = (front + 1) % MAXSIZE
循环队列入队:rear = (rear + 1) % MAXSIZE
循环队列的长度:(MAXSIZE + rear – front)% MAXSIZE
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 1024
typedef struct queue {
int front;
int rear;
int *array;
int count;
}Queue,*pQueue;
void IinitQueue(pQueue q)
{
q->array=(int *)malloc(sizeof(int)*MAXSIZE);
q->front = 0;
q->rear = 0;
q->count = 0;
}
int isFull(pQueue q)
{
if ((q->rear + 1) % MAXSIZE == q->front)
return 1;
else
return 0;
}
int isEmpty(pQueue q)
{
if (q->rear== q->front)
return 1;
else
return 0;
}
int InQueue(pQueue q, int num)
{
if (isFull(q))
{
printf("队满\n");
return 1;
}
q->array[q->rear] = num;
q->rear = (q->rear + 1) % MAXSIZE;
q->count++;
return 0;
}
int OutQueue(pQueue q)
{
if (isEmpty(q))
{
printf("对空\n");
return 1;
}
q->count--;
q->front = (q->front + 1) % MAXSIZE;
return q->array[q->front-1];
}
int OutputQueueValue(pQueue q)
{
int i = 0;
if (isEmpty(q))
{
printf("队空\n");
return 1;
}
while (i<q->count)
{
printf("%d\n",q->array[i]);
i++;
}
return 0;
}
int main()
{
int i = 0;
Queue q;
IinitQueue(&q);
for (i = 0; i < 5; i++)
{
InQueue(&q, i);
}
OutputQueueValue(&q);
while (!isEmpty(&q))
{
printf("%d\n", OutQueue(&q));
}
system("pause");
return 0;
}