队列的链式存储结构及实现

队列的链式存储结构,其实就是线性表的单链表,只不过它只是尾进头出而已,我们把它简称为链队列为了操作上的方便,我们将队头指针指向链队列的头结点,而队尾指针指向终端节点。如果



空队列时,front和rear都指向头结点。



入队操作:

在队尾添加元素,先将队尾元素的next指向添加的元素,然后将队尾指针重新指向新的队尾即可。


出队操作:

头结结点指向的结点即为队头结点,出队操作,就是把队头结点干掉,先把头结点指向新的队头结点(也就是旧的队头结点的后继结点),然后释放旧的队头结点。 如果链表除头结点外只剩一个元素时,则需将rear指向头结点即可


下面是队列链式存储结构实现的具体代码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define QUEUESIZE 10
#define ERROR 0 
#define OK 1 
#define TRUE 1 
#define FALSE 0
#define EleType int 
#define Status int
//链队列结点
typedef struct QueueNode
{
	EleType e;//数据域
	struct QueueNode* next;//指针域
}QueueNode,*LinkQueuePoi;
typedef struct LinkQueue
{
	LinkQueuePoi front;//指向头结点
	LinkQueuePoi rear;//指向队尾
}LinkQueue;
/*
初始化链队列
链队列为空时,链队列队头指针队尾指针均指向头结点
*/
Status InitLinkQueue(LinkQueue* queue)
{
	//空指针
	if (!queue)
	{
		return ERROR;
	}
	QueueNode* node = (QueueNode*)malloc(sizeof(QueueNode));//头结点
	node->next = NULL;
	queue->front = queue->rear = node;
	return OK;
}
/*
清空链队列
将所有元素释放
*/
Status CleaerLinkQueue(LinkQueue* queue)
{
	//空指针
	if (!queue)
	{
		return ERROR;
	}
	//空链队列
	if (queue->front == queue->rear)
	{
		return ERROR;
	}
	QueueNode* node = queue->front->next;//队头元素
	while (node)
	{

		queue->front->next = node->next;//指向新的队头结点
		if (queue->rear == node)//当删除的是队尾元素时,将队尾指针指向头结点
		{
			queue->rear = queue->front;
		}
		free(node);//释放旧的队头结点
		node = queue->front->next;
	}
	return OK;
}
/*
判断链队列是否为空队列
*/
Status EmptyLinkQueue(LinkQueue* queue)
{
	//空指针
	if (!queue)
	{
		return ERROR;
	}
	//空链队列
	if (queue->front == queue->rear)
	{
		return TRUE;
	}
	return FALSE;
}
/*
获取链队列长度
*/
int LengthLinkQueue(LinkQueue* queue)
{
	//空指针
	if (!queue)
	{
		return ERROR;
	}
	//空链队列
	if (queue->front == queue->rear)
	{
		return 0;
	}
	QueueNode* node = queue->front->next;
	int num = 0;
	while (node)
	{
		node = node->next;
		num++;
	}
	return num;
}
/*
在链队列队尾添加元素
先将新元素添加到链表尾部,然后将队列尾指针指向这个新元素
*/
Status AddQueue(LinkQueue* queue,EleType e)
{
	//空指针
	if (!queue)
	{
		return ERROR;
	}
	QueueNode* node = (QueueNode*)malloc(sizeof(QueueNode));
	if (!node)
	{
		return ERROR;
	}
	node->next = NULL;
	node->e = e;
	queue->rear->next = node;//将新结点添加到链表表中
	queue->rear = node;//队尾指针指向新的队尾结点
	return OK;
}
/*
从链队列中删除队头元素
先将头结结点指向新的队头结点,然后释放原来的队头结点
*/
Status DelQueue(LinkQueue* queue, EleType *e)
{
	//空指针
	if (!queue)
	{
		return ERROR;
	}
	//注意queue->front是头结点,头结点指向的结点才是队头结点
	QueueNode* node = queue->front->next;//旧队头结点
	*e = node->e;
	queue->front->next = node->next;//队头指针指向新的队头结点
	//当删除的是队尾元素时,将队尾指针指向头结点
	if (node = queue->rear)
	{
		queue->rear = queue->front;
	}
	return OK;
}
/*
打印链队列元素
*/
void PrintfLinkQueue(LinkQueue* queue)
{
	if (!queue)
	{
		return;
	}
	QueueNode* node = queue->front->next;
	while (node)
	{
		printf("%d,", node->e);
		node = node->next;
	}
	printf("\n");
	return;
}
int main(int argc, char *argv[])
{
	LinkQueue queue;
	InitLinkQueue(&queue);
	AddQueue(&queue, 1);
	AddQueue(&queue, 2);
	AddQueue(&queue, 3);
	AddQueue(&queue, 4);
	AddQueue(&queue, 5);
	AddQueue(&queue, 6);
	AddQueue(&queue, 7);
	AddQueue(&queue, 8);
	AddQueue(&queue, 9);
	printf("链队列元素个数:%d\n",LengthLinkQueue(&queue));
	printf("展示元素:\n");
	PrintfLinkQueue(&queue);
	int e1, e2;
	DelQueue(&queue, &e1);
	DelQueue(&queue, &e2);
	printf("删除元素:%d,%d\n", e1, e2);
	printf("展示元素:\n");
	PrintfLinkQueue(&queue);
	printf("链队列元素个数:%d\n", LengthLinkQueue(&queue));
	CleaerLinkQueue(&queue);
	printf("清空元素后,长度为%d,rear = %p,front=%p",LengthLinkQueue(&queue), queue.rear,queue.front);
	printf("\n");
	return 0;
}
验证结果截图:


对于循环队列与链队列的比较,可以从时间和空间2方面来考虑,从时间上,他们的基本操作都是常数时间,即都为O(1),不过循环队列是事先申请好空间,使用期间不释放,而对于链队列,每次申请和释放结点也会存在一些时间开销,如果入队出队频繁,则2者还是有些细微的差异。对于空间方面来说,循环队列必须有一个固定的长度,所以就有了存储元素个数和空间浪费的问题。而链队列就不存在这个问题,尽管它需要一些指针域,会产生一些空间上的开销,但也可以接受。所以在空间上,链队列更加灵活。





评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值