队列(queue)
队列是一种先进先出(first in first out,FIFO)的线性表。它只允许在表的一端(队尾/rear)插入元素,而在另一端(队头/front)删除元素。插入操作称为入队或进队,删除操作称为出队或离队。队列示意图如下:
1、 顺序队
队列的顺序存储结构需要使用一个数组和两个整型变量来实现,数组用于存储队列中的所有元素,两个整型变量分别用于存储队头元素和队尾元素的下标位置,分别称为队头指针和队尾指针。
假定队列的元素个数不超过MaxSize,所有的元素的数据类型都是ElemType,则顺序队列类型SqQueue定义如下:
typedefstruct
{
ElemType data[MaxSize];
Int front,rear;
}SqQueue;
在顺序队列*q中,队空的条件是q->front==q->rear;队满的条件是q->rear==MaxSize-1;元素e入队的操作是先将队尾指针加1,然后将元素e放入队尾;出队操作是先将队头指针加1,然后取出队头处的元素;队尾指针总是指向当前队列中的队尾元素,而队头指针总是指向当前队列中队头元素的前一个位置。
顺序队的基本运算实现如下:
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 20 //队列元素最大个数
typedef char ElemType; //队列元素类型
typedef struct //顺序队
{
ElemType data[MaxSize]; //数据元素
int front; //对头指针
int rear; //队尾指针
}SqQueue;
void InitQueue(SqQueue *&q) //初始化队列
{
q=(SqQueue *)malloc(sizeof(SqQueue));
q->front=q->rear=-1;
}
void DestoryQueue(SqQueue *&q) //销毁队列
{
free(q);
}
bool QueueEmpty(SqQueue *q) //判断队列是否为空
{
return (q->front==q->rear);
}
bool QueueFull(SqQueue *q) //判断队列是否已满
{
return (q->rear==MaxSize-1);
}
bool EnQueue(SqQueue *&q, ElemType e) //入队(插入元素)
{
if(q->rear==MaxSize-1) //队列已满,不能再插入
return false;
q->rear++;
q->data[q->rear]=e;
return true;
}
bool DeQueue(SqQueue *&q, ElemType &e) //出队(删除元素)
{
if(q->front==q->rear) //队列为空,无法删除
return false;
q->front++;
e=q->data[q->front];
return true;
}
int main()
{
...;
return 0;
}
2、 环形队列
将数组的前端和后端连接起来,形成环形的顺序表——环形队列。
环形队列的基本运算实现如下:
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 10 //队列元素最大个数
typedef char ElemType; //队列元素类型
typedef struct //环形队列
{
ElemType data[MaxSize]; //数据元素
int front; //对头指针
int rear; //队尾指针
}QuType;
void InitQueue(QuType *&qu) //初始化队列
{
qu=(QuType *)malloc(sizeof(QuType));
qu->front=qu->rear=0;
}
void DestoryQueue(QuType *&qu) //销毁队列
{
free(qu);
}
bool QueueEmpty(QuType *&qu) //判断队列是否为空
{
return (qu->front==qu->rear);
}
bool QueueFull(QuType *&qu) //判断队列是否已满
{
return (qu->front==(qu->rear+1)%MaxSize);
}
bool EnQueue(QuType *&qu, ElemType e) //入队
{
if(qu->front==(qu->rear+1)%MaxSize) //注意!
return false;
qu->rear=(qu->rear+1)%MaxSize;
qu->data[qu->rear]=e;
return true;
}
bool DeQueue(QuType *&qu, ElemType &e) //出队
{
if(qu->front==qu->rear)
return false;
qu->front=(qu->front+1)%MaxSize;
e=qu->data[qu->front];
return true;
}
int main()
{
...;
return 0;
}
3、 链队
队列的链式存储结构通过由结点构成的单链表实现,此时只允许在单链表的表头进行删除操作和在单链表的表尾进行插入操作,因此需要两个指针:队首指针front和队尾指针rear。用front指向队首结点,用rear指向队尾结点。用于存储队列的单链表成为链队。
链队(带头结点)中数据结点的类型QNode定义如下:
typedefstruct qnode
{
ElemType data;
struct qnode *next;
}QNode; //链队数据结点类型定义
链队结点的类型LinkQueue定义如下:
typedefstruct
{
QNode *front;
QNode *rear;
}LinkQueue; //链队类型定义
链队的基本运算实现如下:
#include<stdio.h>
#include<stdlib.h>
typedef char ElemType;
typedef struct qNode
{
ElemType data;
struct qNode *next;
}QNode; //数据结点
typedef struct
{
QNode *front; //队头指针
QNode *rear; //队尾指针
}LinkQueue; //链队结点
void InitQueue(LinkQueue *&q) //初始化链队
{
QNode *p=(QNode *)malloc(sizeof(QNode)); //创建头结点
if(!p)
{
printf("内存分配失败\n");
exit(1);
}
p->next=NULL;
q=(LinkQueue *)malloc(sizeof(LinkQueue)); //分配链队结点空间
if(!q)
{
printf("内存分配失败\n");
exit(1);
}
q->front=q->rear=p;
}
void DestoryQueue(LinkQueue *&q) //销毁链队
{
QNode *p;
while(q->front!=NULL)
{
p=q->front;
q->front=p->next;
}
free(p);
}
bool QueueEmpty(LinkQueue *q) //判断队列是否为空
{
return (q->front->next==NULL);
}
void EnQueue(LinkQueue *&q, ElemType e) //入队
{
QNode *p;
p=(QNode *)malloc(sizeof(QNode)); //创建新结点
if(!p)
{
printf("内存分配失败!\n");
exit(1);
}
p->data=e;
p->next=NULL;
q->rear->next=p;
q->rear=p;
}
bool DeQueue(LinkQueue *&q, ElemType &e) //出队
{
QNode *p;
if(q->front->next==NULL) //队列为空,操作无效
return false;
p=q->front->next;
e=p->data;
q->front->next=p->next;
if(p->next==NULL) //删除最后一个结点后,将尾指针指向头结点
q->rear=q->front;
free(p);
return true;
}
int main()
{
...;
return 0;
}
几个注意点:
1、顺序队和环形队列的队空条件均是q->front==q->rear;顺序队的队满条件是p->rear==MaxSize-1,而环形队列的队满条件是q->front==(q->rear+1)%MaxSize;
2、顺序队和环形队列初始化的不同,导致最后存储空间上的元素不一样。顺序队的初始化:q->front=q->rear=-1,所以元素从q->data[0]开始存储;而环形队列的初始化:q->front=q->rear=0,所以元素从q->data[1]开始存储,q->data[0]空闲;
3、顺序队列满足队满条件时可能是假溢出(如p->rear==MaxSize-1,此时即使出队几个数据仍然满足了队满条件,但已经腾出了若干个空间,此时就是假溢出),而环形队列满足队满条件就是没有多余的存储空间了;
4、顺序队中的元素个数是rear-front,环形队列中的元素个数是(rear-front+MaxSize)%MaxSize;
5、链队的初始化,创建头结点的同时,为链队结点分配内存空间;
6、出队时,当删除最后一个结点后,尾指针也随之释放,所以应该将尾指针重新赋值,指向头结点。
2014年7月29日星期二