链队列-队列的链式表示和实现

// c3-2.h 单链队列--队列的链式存储结构
typedef struct QNode // (见图3.12)
{
	QElemType data;
	QNode *next;
}*QueuePtr;
struct LinkQueue // (见图3.13)
{
	QueuePtr front,rear; // 队头、队尾指针
};

和栈一样,队列也是操作受限的线性表,只允许在队尾插入元素,在队头删除元素。
对于链队列结构,为了便于插入元素,设立了队尾指针。这样,插入元素的操作与队列长
度无关。图314 是具有两个元素的链队列示例。

// bo3-2.cpp 链队列(存储结构由c3-2.h定义)的基本操作(9个)
void InitQueue(LinkQueue &Q)
{ // 构造一个空队列Q(见图3.15)
	if(!(Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode))))
		exit(OVERFLOW);
	Q.front->next=NULL;
}
void DestroyQueue(LinkQueue &Q)
{ // 销毁队列Q(无论空否均可)(见图3.16)
	while(Q.front)
	{
		Q.rear=Q.front->next;
		free(Q.front);
		Q.front=Q.rear;
	}
}
void ClearQueue(LinkQueue &Q)
{ // 将Q清为空队列
	QueuePtr p,q;
	Q.rear=Q.front;
	p=Q.front->next;
	Q.front->next=NULL;
	while(p)
	{
		q=p;
		p=p->next;
		free(q);
	}
}
Status QueueEmpty(LinkQueue Q)
{ // 若Q为空队列,则返回TRUE;否则返回FALSE
	if(Q.front->next==NULL)
		return TRUE;
	else
		return FALSE;
}
int QueueLength(LinkQueue Q)
{ // 求队列的长度
	int i=0;
	QueuePtr p;
	p=Q.front;
	while(Q.rear!=p)
	{
		i++;
		p=p->next;
	}
	return i;
}
Status GetHead(LinkQueue Q,QElemType &e)
{ // 若队列不空,则用e返回Q的队头元素,并返回OK;否则返回ERROR
	QueuePtr p;
	if(Q.front==Q.rear)
		return ERROR;
	p=Q.front->next;
	e=p->data;
	return OK;
}
void EnQueue(LinkQueue &Q,QElemType e)
{ // 插入元素e为Q的新的队尾元素(见图3.17)
	QueuePtr p;
	if(!(p=(QueuePtr)malloc(sizeof(QNode))))
		// 存储分配失败
		exit(OVERFLOW);
	p->data=e;
	p->next=NULL;
	Q.rear->next=p;
	Q.rear=p;
}
Status DeQueue(LinkQueue &Q,QElemType &e)
{ // 若队列不空,删除Q的队头元素,用e返回其值,
	// 并返回OK;否则返回ERROR(见图3.18)
	QueuePtr p;
	if(Q.front==Q.rear)
		return ERROR;
	p=Q.front->next;
	e=p->data;
	Q.front->next=p->next;
	if(Q.rear==p)
		Q.rear=Q.front;
	free(p);
	return OK;
}
void QueueTraverse(LinkQueue Q,void(*vi)(QElemType))
{ // 从队头到队尾依次对队列Q中每个元素调用函数vi()
	QueuePtr p;
	p=Q.front->next;
	while(p)
	{
		vi(p->data);
		p=p->next;
	}
	printf("\n");
}



// main3-2.cpp 检验bo3-2.cpp的主程序
#include"c1.h"
typedef int QElemType;
#include"c3-2.h"
#include"bo3-2.cpp"
void print(QElemType i)
{
	printf("%d ",i);
}
void main()
{
	int i;
	QElemType d;
	LinkQueue q;
	InitQueue(q);
	printf("成功地构造了一个空队列!\n");
	printf("是否空队列?%d(1:空0:否) ",QueueEmpty(q));
	printf("队列的长度为%d\n",QueueLength(q));
	EnQueue(q,-5);
	EnQueue(q,5);
	EnQueue(q,10);
	printf("插入3个元素(-5,5,10)后,队列的长度为%d\n",QueueLength(q));
	printf("是否空队列?%d(1:空0:否) ",QueueEmpty(q));
	printf("队列的元素依次为");
	QueueTraverse(q,print);
	i=GetHead(q,d);
	if(i==OK)
		printf("队头元素是:%d\n",d);
	DeQueue(q,d);
	printf("删除了队头元素%d\n",d);
	i=GetHead(q,d);
	if(i==OK)
		printf("新的队头元素是:%d\n",d);
	ClearQueue(q);
	printf("清空队列后,q.front=%u q.rear=%u q.front->next=%u\n",q.front,q.rear,q.front->next);
	DestroyQueue(q);
	printf("销毁队列后,q.front=%u q.rear=%u\n",q.front, q.rear);
}

代码运行将结果如下:

/*
成功地构造了一个空队列!
是否空队列?1(1:空0:否) 队列的长度为0
插入3个元素(-5,5,10)后,队列的长度为3
是否空队列?0(1:空0:否) 队列的元素依次为-5 5 10
队头元素是:-5
删除了队头元素-5
新的队头元素是:5
清空队列后,q.front=4794552 q.rear=4794552 q.front->next=0
销毁队列后,q.front=0 q.rear=0
*/
由c3-2.h 和c2-2.h 对比可见,单链队列和单链表的结构有相同之处。单链队列也是
带有头结点的单链表,它的队头指针相当于单链表的头指针。因为队列操作是线性表操作
的子集,所以bo3-2.cpp 中的基本操作也可以用单链表的基本操作来代替。这样既可以充
分利用现有资源,减小编程工作量,又可以更清楚地看出队列和线性表的内在联系和共
性。bo3-6.cpp 是利用单链表的基本操作实现单链队列基本操作的程序。

// bo3-6.cpp 用单链表的基本操作实现链队列(存储结构由c3-2.h定义)的基本操作(9个)
typedef QElemType ElemType;
#define LinkList QueuePtr // 定义单链表的类型与相应的链队列的类型相同
#define LNode QNode
#include"bo2-2.cpp" // 单链表的基本操作
void InitQueue(LinkQueue &Q)
{ // 构造一个空队列Q
	InitList(Q.front); // 调用单链表的基本操作
	Q.rear=Q.front;
}
void DestroyQueue(LinkQueue &Q)
{ // 销毁队列Q(无论空否均可)
	DestroyList(Q.front);
	Q.rear=Q.front;
}
void ClearQueue(LinkQueue &Q)
{ // 将Q清为空队列
	ClearList(Q.front);
	Q.rear=Q.front;
}
Status QueueEmpty(LinkQueue Q)
{ // 若Q为空队列,则返回TRUE;否则返回FALSE
	return ListEmpty(Q.front);
}
int QueueLength(LinkQueue Q)
{ // 求队列的长度
	return ListLength(Q.front);
}
Status GetHead(LinkQueue Q,QElemType &e)
{ // 若队列不空,则用e返回Q的队头元素,并返回OK;否则返回ERROR
	return GetElem(Q.front,1,e);
}
void EnQueue(LinkQueue &Q,QElemType e)
{ // 插入元素e为Q的新的队尾元素
	QueuePtr p;
	if(!(p=(QueuePtr)malloc(sizeof(QNode)))) // 存储分配失败
		exit(OVERFLOW);
	p->data=e;
	p->next=NULL;
	Q.rear->next=p;
	Q.rear=p;
}
Status DeQueue(LinkQueue &Q,QElemType &e)
{ // 若队列不空,删除Q的队头元素,用e返回其值,并返回OK;否则返回ERROR
	if(Q.front->next==Q.rear) // 队列仅有1个元素(删除的也是队尾元素)
		Q.rear=Q.front; // 令队尾指针指向头结点
	return ListDelete(Q.front,1,e);
}
void QueueTraverse(LinkQueue Q,void(*vi)(QElemType))
{ // 从队头到队尾依次对队列Q中每个元素调用函数vi()
	ListTraverse(Q.front,vi);
}

用单链表的操作代替单链队列的操作又和代替链栈的操作情况不同。链栈和单链表的
结构完全相同,许多栈的基本操作仅是单链表基本操作改了个名。而单链队列和单链表的
结构并不完全相同,只能是在单链队列的基本操作中调用单链表的基本操作。

// main3-6.cpp 检验bo3-6.cpp的主程序
#include"c1.h"
typedef int QElemType;
#include"c3-2.h"
#include"bo3-6.cpp" // 仅此句与main3-2.cpp不同
void print(QElemType i)
{
	printf("%d ",i);
}
void main()
{
	int i;
	QElemType d;
	LinkQueue q;
	InitQueue(q);
	printf("成功地构造了一个空队列!\n");
	printf("是否空队列?%d(1:空0:否) ",QueueEmpty(q));
	printf("队列的长度为%d\n",QueueLength(q));
	EnQueue(q,-5);
	EnQueue(q,5);
	EnQueue(q,10);
	printf("插入3个元素(-5,5,10)后,队列的长度为%d\n",QueueLength(q));
	printf("是否空队列?%d(1:空0:否) ",QueueEmpty(q));
	printf("队列的元素依次为");
	QueueTraverse(q,print);
	i=GetHead(q,d);
	if(i==OK)
		printf("队头元素是:%d\n",d);
	DeQueue(q,d);
	printf("删除了队头元素%d\n",d);
	i=GetHead(q,d);
	if(i==OK)
		printf("新的队头元素是:%d\n",d);
	ClearQueue(q);
	printf("清空队列后,q.front=%u q.rear=%u q.front->next=%u\n",q.front,q.rear,q.front->next);
	DestroyQueue(q);
	printf("销毁队列后,q.front=%u q.rear=%u\n",q.front, q.rear);
}

代码运行结果:

/*
成功地构造了一个空队列!
是否空队列?1(1:空0:否) 队列的长度为0
插入3个元素(-5,5,10)后,队列的长度为3
是否空队列?0(1:空0:否) 队列的元素依次为-5 5 10
队头元素是:-5
删除了队头元素-5
新的队头元素是:5
清空队列后,q.front=5253304 q.rear=5253304 q.front->next=0
销毁队列后,q.front=0 q.rear=0
*/





posted @ 2014-08-17 21:05  meiyouor  阅读(659)  评论(0编辑  收藏  举报