zoukankan      html  css  js  c++  java
  • 链队列-队列的链式表示和实现

    // 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("
    ");
    }



    // 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("成功地构造了一个空队列!
    ");
    	printf("是否空队列?%d(1:空0:否) ",QueueEmpty(q));
    	printf("队列的长度为%d
    ",QueueLength(q));
    	EnQueue(q,-5);
    	EnQueue(q,5);
    	EnQueue(q,10);
    	printf("插入3个元素(-5,5,10)后,队列的长度为%d
    ",QueueLength(q));
    	printf("是否空队列?%d(1:空0:否) ",QueueEmpty(q));
    	printf("队列的元素依次为");
    	QueueTraverse(q,print);
    	i=GetHead(q,d);
    	if(i==OK)
    		printf("队头元素是:%d
    ",d);
    	DeQueue(q,d);
    	printf("删除了队头元素%d
    ",d);
    	i=GetHead(q,d);
    	if(i==OK)
    		printf("新的队头元素是:%d
    ",d);
    	ClearQueue(q);
    	printf("清空队列后,q.front=%u q.rear=%u q.front->next=%u
    ",q.front,q.rear,q.front->next);
    	DestroyQueue(q);
    	printf("销毁队列后,q.front=%u q.rear=%u
    ",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("成功地构造了一个空队列!
    ");
    	printf("是否空队列?%d(1:空0:否) ",QueueEmpty(q));
    	printf("队列的长度为%d
    ",QueueLength(q));
    	EnQueue(q,-5);
    	EnQueue(q,5);
    	EnQueue(q,10);
    	printf("插入3个元素(-5,5,10)后,队列的长度为%d
    ",QueueLength(q));
    	printf("是否空队列?%d(1:空0:否) ",QueueEmpty(q));
    	printf("队列的元素依次为");
    	QueueTraverse(q,print);
    	i=GetHead(q,d);
    	if(i==OK)
    		printf("队头元素是:%d
    ",d);
    	DeQueue(q,d);
    	printf("删除了队头元素%d
    ",d);
    	i=GetHead(q,d);
    	if(i==OK)
    		printf("新的队头元素是:%d
    ",d);
    	ClearQueue(q);
    	printf("清空队列后,q.front=%u q.rear=%u q.front->next=%u
    ",q.front,q.rear,q.front->next);
    	DestroyQueue(q);
    	printf("销毁队列后,q.front=%u q.rear=%u
    ",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
    */





  • 相关阅读:
    《算法竞赛入门经典》(刘汝佳)——排序与检索(基础)
    Python中的GIL
    MongoDB 安装
    python3 报错集合
    socket 实例化方法
    socket入门
    Day_6作业_模拟人生
    高阶函数举例
    面向对象_python
    xml
  • 原文地址:https://www.cnblogs.com/KongkOngL/p/3945962.html
Copyright © 2011-2022 走看看