【数据结构与算法(C 语言)】队列 --链队列

1. 前言

1.1 定义

队列:一种先进先出(first in first out,缩写 FIFO)的线性表。

允许插入的一端(rear)称为 队尾 ,允许删除的一端 (front)称为 队头
和其他线性表一样,分为链式存储和线性存储。
用链表标识的队列简称 链队列,本文的代码就是实现队列的链式存储。

1.2 队列示意图

在这里插入图片描述

2. 链队列存储结构和函数说明

2.1 队列结点

typedef struct QNode{
	QElemType data;
	struct QNode * next;
}QNode;  	//定义队列的结点

2.2 队列类型

typedef struct{
	QNode * front;  //队头指针 
	QNode * rear;	//队尾指针
	int length; 
}LinkQueue;   

2.3 函数原型声明

一共有9个基本的操作函数

Status InitQueue(LinkQueue * queue);   /*初始化队列,申请一个头结点的内存*/
void DestroyQueue(LinkQueue *queue);   /*销毁队列*/
Status ClearQueue(LinkQueue * queue);  //将队列queue清空
Status QueueEmpty(LinkQueue queue);    //判断队列是否为空
Status GetHead(LinkQueue queue ,QElemType * e); //获取队列第一个元素
int QueueLength(LinkQueue queue);		//返回队列长度
Status EnQueue(LinkQueue  * queue, QElemType e);	//元素e 插入队列queue
Status DeQueue(LinkQueue * queue ,QElemType * e);  //若队列queue不空,则删除Q的队头元素,用e返回其值,并返回 OK;否则返回ERROR
Status QueueTraverse(LinkQueue queue,void (*visit)())//遍历队列,对队列的每个元素调用Visit函数

2.4 初始化队列 InitQueue

原型 :Status InitQueue(LinkQueue * queue);
功能 :初始化队列
说明:申请头结点的内存地址
    头指针、尾指针、队列变量初始化

/*初始化队列,申请一个头结点的内存*/
Status InitQueue(LinkQueue * queue)
{
	queue->front = (QNode*) malloc(sizeof(QNode)); //申请一个队列结点作为头结点的内存地址给 队头指针;
	if(queue->front == NULL)
		return FALSE;
	queue->front->next = NULL;		
	queue->rear=queue->front;
	queue->length=0;
	return TRUE;
}

2.5 销毁队列 DestroyQueue

原型 :void DestroyQueue(LinkQueue *queue)
功能 :销毁队列,释放内存空间

/*销毁队列*/
void DestroyQueue(LinkQueue *queue)
{
	ClearQueue(queue);
	free(queue->front);
	queue->front = queue->rear=NULL;
	queue->length=0;
}

2.6 清空队列 ClearQueue

原型 :Status ClearQueue(LinkQueue * queue)
功能 :清空队列中的结点,
说明 : 和DestroyQueue的区别在于,清空队列是保留头结点指向的地址的,清空以后,队列还是可以照常使用的。

//将队列queue清空
Status ClearQueue(LinkQueue * queue)
{
	QNode * curNode;
	while((curNode = queue->front->next) != NULL)
	{
		queue->front->next=curNode->next;	
		free(curNode);
	}
	queue->rear = queue->front;
	queue->length = 0;
	return OK;	
}

2.7 判断队列是否为空 QueueEmpty

原型 :Status QueueEmpty(LinkQueue queue)
功能 :判断队列是否为空
说明 :判断队列是否为空,只需要判断头指针和尾指针是否相等,相等,队列即为空

//判断队列是否为空
Status QueueEmpty(LinkQueue queue)
{
	return queue.front == queue.rear? TRUE:FALSE; 
}

2.8 获取队列第一个元素 QueueEmpty

原型 :Status GetHead(LinkQueue queue ,QElemType * e)
功能 :获取队列第一个元素
说明 :获取队列第一个元素,不是删除第一个元素。获得元素存放在参数 e 中,如果获取成功,返回TRUE ;失败,返回FALSE;

//获取队列第一个元素
Status GetHead(LinkQueue queue ,QElemType * e)
{
	if(queue.length == 0)
		return FALSE;
	*e=queue.front->next->data;
	return TRUE;
}

2.9 获取队列长度 QueueLength

原型 :int QueueLength(LinkQueue queue)
功能 :获取队列长度

//返回队列长度
int QueueLength(LinkQueue queue)
{
	return queue.length;
}

2.10 插入操作 EnQueue

原型 :Status EnQueue(LinkQueue * queue, QElemType e)
功能 :元素 e 插入队列
说明 :插入操作,都是在队列尾部进行;插入成功,返回 TRUE;插入失败,返回 FALSE;

//元素 e 插入队列queue
Status EnQueue(LinkQueue  * queue, QElemType e)
{
	QNode * curNode=(QNode*) malloc(sizeof(QNode));
	if(!curNode)
		return FALSE;
	curNode->data=e;
	curNode->next=NULL;
	queue->rear->next = curNode;
	queue->rear =curNode;
	queue->length++;
	return TRUE;
}

2.11 删除操作 DeQueue

原型 :Status DeQueue(LinkQueue * queue ,QElemType * e)
功能 :删除队列第一个元素,
说明 :删除操作,只能在队头执行。 删除成功,返回 TRUE;删除失败,返回 FALSE;

//若队列queue不空,则删除Q的队头元素,用e返回其值,并返回 OK;否则返回ERROR
Status DeQueue(LinkQueue * queue ,QElemType * e)
{
	QNode * curNode;
	if(queue->length == 0)
		return FALSE;
	curNode = queue->front->next;
	*e=curNode->data;
	queue->front->next=curNode->next;
	free(curNode);
	queue->length--;
	return TRUE;
}

2.11 遍历队列 QueueTraverse

原型 :Status QueueTraverse(LinkQueue queue,void (*visit)())
功能 :遍历队列
说明 :队列的每个元素调用Visit函数,这里的visit是函数指针,实际应用可以根据需要修改Visit函数。

//遍历队列,对队列的每个元素调用Visit函数
Status QueueTraverse(LinkQueue queue,void (*visit)())
{
	QNode * curNode=queue.front->next;
	while(curNode)
	{
		visit(curNode->data);
		curNode=curNode->next;
	}
}

3. 完整代码

#include <stdio.h>
#include <stdlib.h>

#define TRUE  1
#define FALSE 0
#define OK    1
#define ERROR 0
#define MAXSIZE 30

typedef  int Status;

typedef  int QElemType; //定义元素类型为整型

typedef struct QNode{
	QElemType data;
	struct QNode * next;
}QNode;  	//定义队列的结点

typedef struct{
	QNode * front;  //队头指针 
	QNode * rear;	//队尾指针
	int length; 
}LinkQueue;     //定义一个队列类型 


Status InitQueue(LinkQueue * queue);   /*初始化队列,申请一个头结点的内存*/
void DestroyQueue(LinkQueue *queue);   /*销毁队列*/
Status ClearQueue(LinkQueue * queue);  //将队列queue清空
Status QueueEmpty(LinkQueue queue);    //判断队列是否为空
Status GetHead(LinkQueue queue ,QElemType * e); //获取队列第一个元素
int QueueLength(LinkQueue queue);		//返回队列长度
Status EnQueue(LinkQueue  * queue, QElemType e);	//元素e 插入队列queue
Status DeQueue(LinkQueue * queue ,QElemType * e);  //若队列queue不空,则删除Q的队头元素,用e返回其值,并返回 OK;否则返回ERROR
Status QueueTraverse(LinkQueue queue,void (*visit)());//遍历队列,对队列的每个元素调用Visit函数

/*初始化队列,申请一个头结点的内存*/
Status InitQueue(LinkQueue * queue)
{
	queue->front = (QNode*) malloc(sizeof(QNode)); //申请一个队列结点作为头结点的内存地址给 队头指针;
	if(queue->front == NULL)
		return FALSE;
	queue->front->next = NULL;		
	queue->rear=queue->front;
	queue->length=0;
	return TRUE;
}

/*销毁队列*/
void DestroyQueue(LinkQueue *queue)
{
	ClearQueue(queue);
	free(queue->front);
	queue->front = queue->rear=NULL;
	queue->length=0;
}

//将队列queue清空
Status ClearQueue(LinkQueue * queue)
{
	QNode * curNode;
	while((curNode = queue->front->next) != NULL)
	{
		queue->front->next=curNode->next;	
		free(curNode);
	}
	queue->rear = queue->front;
	queue->length = 0;
	return OK;	
}

//判断队列是否为空
Status QueueEmpty(LinkQueue queue)
{
	return queue.front == queue.rear? TRUE:FALSE; 
}

//获取队列第一个元素
Status GetHead(LinkQueue queue ,QElemType * e)
{
	if(queue.length == 0)
		return FALSE;
	*e=queue.front->next->data;
	return TRUE;
}


//返回队列长度
int QueueLength(LinkQueue queue)
{
	return queue.length;
}


//元素e 插入队列queue
Status EnQueue(LinkQueue  * queue, QElemType e)
{
	QNode * curNode=(QNode*) malloc(sizeof(QNode));
	if(!curNode)
		return FALSE;
	curNode->data=e;
	curNode->next=NULL;
	queue->rear->next = curNode;
	queue->rear =curNode;
	queue->length++;
	return TRUE;
}

//若队列queue不空,则删除Q的队头元素,用e返回其值,并返回 OK;否则返回ERROR
Status DeQueue(LinkQueue * queue ,QElemType * e)
{
	QNode * curNode;
	if(queue->length == 0)
		return FALSE;
	curNode = queue->front->next;
	*e=curNode->data;
	queue->front->next=curNode->next;
	free(curNode);
	queue->length--;
	return TRUE;
}
void Visit(QElemType e)
{
	printf("%3d",e);
}
//遍历队列,对队列的每个元素调用Visit函数
Status QueueTraverse(LinkQueue queue,void (*visit)())
{
	QNode * curNode=queue.front->next;
	while(curNode)
	{
		visit(curNode->data);
		curNode=curNode->next;
	}
}

int main()
{
	QElemType e;
	LinkQueue queue;
	InitQueue(&queue);
	printf("队头分别插入数字3、4、5后:");
	EnQueue(&queue,3);
	EnQueue(&queue,4);
	EnQueue(&queue,5);
	QueueTraverse(queue,Visit);
	printf("\n删除队头数字后:");
	DeQueue(&queue,&e);
	QueueTraverse(queue,Visit);	
	printf("\n清空队列");
	ClearQueue(&queue);
	printf("\n队列长度:%d\n",QueueLength(queue));
	DestroyQueue(&queue);
	getchar();
	return 0;
}

4. 运行结果

在这里插入图片描述

5. 优缺点

这里的优缺点,是相对于顺序存储队列而言

优点:

  1. 链队列可以动态分配空间,当不确定队列大小的时候,内存空间需要多少就申请多少,不浪费。
  2. 不会出现数组溢出等问题。

缺点:

    当确定队列大小的时候,占用的空间比顺序存储大,因为每个结点都有一个额外的指针指向下一个结点。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值