您的位置:首页 > 理论基础 > 数据结构算法

数据结构学习笔记 --- 队列(循环队列-队列的顺序表示和实现)

2012-02-12 17:53 1046 查看
1. 引言

本文主要讲解队列顺序表示和实现。队列的顺序表示为什么要采用循环方式? 首先分析一下非循环队列的表示和实现及其存

在的问题。

2.非循环队列的表示和实现

#include "ds.h"

typedef 	int 			QElemType;

#define 	QUEUE_INIT_SIZE 10 // 队列存储空间的初始分配量
#define 	QUEUE_INCREMENT 2 // 队列存储空间的分配增量

// 队列的顺序存储结构(出队元素时不移动元素,只改变队头元素的位置)
struct SqQueue2
{
QElemType *base; // 初始化的动态分配存储空间
int front; // 头指针,若队列不空,指向队列头元素
int rear; // 尾指针,若队列不空,指向队列尾元素的下一个位置
int queuesize; // 当前分配的存储容量(以sizeof(QElemType)为单位)
};

// 顺序队列的基本操作(9个)
void InitQueue(SqQueue2 &Q)
{ // 构造一个空队列Q
if(!(Q.base=(QElemType *)malloc(QUEUE_INIT_SIZE*sizeof(QElemType)))) // 存储分配失败
exit(ERROR);
Q.front=Q.rear=0;
Q.queuesize=QUEUE_INIT_SIZE;
}

void DestroyQueue(SqQueue2 &Q)
{ // 销毁队列Q,Q不再存在
if(Q.base)
free(Q.base);
Q.base=NULL;
Q.front=Q.rear=Q.queuesize=0;
}

void ClearQueue(SqQueue2 &Q)
{ // 将Q清为空队列
Q.front=Q.rear=0;
}

Status QueueEmpty(SqQueue2 Q)
{ // 若队列Q为空队列,则返回TRUE;否则返回FALSE
if(Q.front==Q.rear) // 队列空的标志
return TRUE;
else
return FALSE;
}

Status GetHead(SqQueue2 Q,QElemType &e)
{ // 若队列不空,则用e返回Q的队头元素,并返回OK;否则返回ERROR
if(Q.front==Q.rear) // 队列空
return ERROR;
e=Q.base[Q.front];
return OK;
}

int QueueLength(SqQueue2 Q)
{ // 返回Q的元素个数,即队列的长度
return(Q.rear-Q.front);
}

void EnQueue(SqQueue2 &Q,QElemType e)
{ // 插入元素e为Q的新的队尾元素
if(Q.rear==Q.queuesize)
{ // 队列满,增加存储单元
Q.base=(QElemType *)realloc(Q.base,(Q.queuesize+QUEUE_INCREMENT)*sizeof(QElemType));
if(!Q.base) // 增加单元失败
exit(ERROR);
}
Q.base[Q.rear++]=e;
}

Status DeQueue(SqQueue2 &Q,QElemType &e)
{ // 若队列不空,则删除Q的队头元素,用e返回其值,并返回OK;否则返回ERROR
if(Q.front==Q.rear) // 队列空
return ERROR;
e=Q.base[Q.front++];
return OK;
}

void QueueTraverse(SqQueue2 Q,void(*vi)(QElemType))
{ // 从队头到队尾依次对队列Q中每个元素调用函数vi()
int i=Q.front;
while(i!=Q.rear)
vi(Q.base[i++]);
printf("\n");
}

void print(QElemType i)
{
printf("%d ",i);
}

int main()
{
Status j;
int i,n=11;
QElemType d;
SqQueue2 Q;
InitQueue(Q);
printf("初始化队列后,队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
printf("队列长度为:%d\n",QueueLength(Q));
printf("请输入%d个整型队列元素:\n",n);
for(i=0;i<n;i++)
{
scanf("%d",&d);
EnQueue(Q,d);
}
printf("队列长度为:%d\n",QueueLength(Q));
printf("现在队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
printf("现在队列中的元素为: \n");
QueueTraverse(Q,print);
DeQueue(Q,d);
printf("删除队头元素%d\n",d);
printf("队列中的元素为: \n");
QueueTraverse(Q,print);
j=GetHead(Q,d);
if(j)
printf("队头元素为: %d\n",d);
else
printf("无队头元素(空队列)\n");
ClearQueue(Q);
printf("清空队列后, 队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
j=GetHead(Q,d);
if(j)
printf("队头元素为: %d\n",d);
else
printf("无队头元素(空队列)\n");
DestroyQueue(Q);
}


可以看非循环队列出队列的每个存储空间自始至终只能存一个元素,即使这个元素出队后,其它的队列元素也不能占用这个存

储空间。尤其在队列长度不长,入队出队频繁的情况下,存储空间浪费较大。由于没有其它元素覆盖,当对头元素出队后,其值还

保留在队列中。

为了克服存储空间浪费较大的缺点,采用循环队列:当队尾元素占据了存储空间的最后一个单元时,如再有新的元素入队,不

是申请新的空间,而是将新的元素插到存储空间的第一个单元,只要这个单元为空(元素已出队列)。通过头尾指针对存储空间

MAX_QSIZE求余做到这一点,形成循环队列。

在循环队列中,队尾指针可能小于对头指针。入队元素时,队尾指针加1。当队列满时,队尾指针等于对头指针,和队列空条

件一样。为了区别队列满和队列空,在循环队列中少用一个存储单元。也就是在存储空间为MAX_QSIZE的循环队列中,最多只能存

放MAX_QSIZE-1个元素。这样,队列空的条件仍为队尾指针等于队头指针,队列满的条件改为(队尾指针+1)对MAX_QSIZE求余

等于队头指针。

3. 循环队列的表示和实现

#include "ds.h"

#define 	MAX_QSIZE 		5

typedef 	int 			QElemType;

struct SqQueue
{
QElemType 	*base;		// 初始化的动态分配存储空间
int 		front;		// 头指针,若队列不空,指向队列头元素
int 		rear;		// 尾指针,若队列不空,指向队尾元素的下一个位置
};

void InitQueue(SqQueue &Q);
void DestroyQueue(SqQueue &Q);
void ClearQueue(SqQueue &Q);
Status QueueEmpty(SqQueue Q);
int QueueLength(SqQueue Q);
Status GetHead(SqQueue Q, QElemType &e);
Status EnQueue(SqQueue &Q, QElemType e);
Status DeQueue(SqQueue &Q, QElemType &e);
void QueueTraverse(SqQueue Q);

void InitQueue(SqQueue &Q)
{
Q.base = (QElemType*)malloc(sizeof(QElemType) * MAX_QSIZE);
if (!Q.base) exit(OVERFLOW);

Q.front = Q.rear = 0;
}
void DestroyQueue(SqQueue &Q)
{
if (Q.base)
free(Q.base);
Q.base = NULL;
Q.front = Q.rear = 0;
}
// 将Q清为空队列
void ClearQueue(SqQueue &Q)
{
Q.front = Q.rear = 0;
}
Status QueueEmpty(SqQueue Q)
{
if (Q.front == Q.rear)
return TRUE;
else
return FALSE;
}
int QueueLength(SqQueue Q)
{
return (Q.rear - Q.front + MAX_QSIZE)%MAX_QSIZE;
}
Status GetHead(SqQueue Q, QElemType &e)
{
if (Q.front == Q.rear)
return ERROR;
memcpy(&e, Q.base + Q.front, sizeof(QElemType));
return OK;
}
Status EnQueue(SqQueue &Q, QElemType e)
{
if ((Q.rear + 1)%MAX_QSIZE == Q.front)
return FALSE;
memcpy(Q.base+Q.rear, &e, sizeof(QElemType));
Q.rear = (Q.rear + 1)%MAX_QSIZE;

return OK;
}
Status DeQueue(SqQueue &Q, QElemType &e)
{
if (!Q.base || Q.front == Q.rear)
return FALSE;

memcpy(&e, Q.base + Q.front, sizeof(QElemType));
Q.front = (Q.front + 1)%MAX_QSIZE;
return OK;
}
void QueueTraverse(SqQueue Q, void(*vi)(QElemType))
{
int i = Q.front;
while (i != Q.rear)
{
vi(Q.base[i]);
i = (i+1)%MAX_QSIZE;
}
printf("\n");
}

void print(QElemType i)
{
printf("%d ",i);
}

int main()
{
Status j;
int i=0,l;
QElemType d;
SqQueue Q;
InitQueue(Q);
printf("初始化队列后,队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
printf("请输入整型队列元素(不超过%d个),-1为提前结束符: ",MAX_QSIZE-1);
do
{
scanf("%d",&d);
if(d==-1)
break;
i++;
EnQueue(Q,d);
}while(i<MAX_QSIZE-1);
printf("队列长度为: %d\n",QueueLength(Q));
printf("现在队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
printf("连续%d次由队头删除元素,队尾插入元素:\n",MAX_QSIZE);
for(l=1;l<=MAX_QSIZE;l++)
{
DeQueue(Q,d);
printf("删除的元素是%d,请输入待插入的元素: ",d);
scanf("%d",&d);
EnQueue(Q,d);
}
l=QueueLength(Q);
printf("现在队列中的元素为:\n");
QueueTraverse(Q,print);
printf("共向队尾插入了%d个元素\n",i+MAX_QSIZE);
if(l-2>0)
printf("现在由队头删除%d个元素: \n",l-2);
while(QueueLength(Q)>2)
{
DeQueue(Q,d);
printf("删除的元素值为%d\n",d);
}
j=GetHead(Q,d);
if(j)
printf("现在队头元素为: %d\n",d);
ClearQueue(Q);
printf("清空队列后, 队列空否?%u(1:空 0:否)\n",QueueEmpty(Q));
DestroyQueue(Q);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: