队列的介绍和实现(C语言实现)

人书就像骑自行车,想要保持平衡就得往前走。
在这里插入图片描述

队列的概念

队列是限制元素插入操作固定在一端进行,而结点的删除操作固定在另一端进行的线性表.队列犹如一个两端开口的管道。允许插入的一端称为队头,允许删除的一端称为队尾。队列的特点是结点在队列中的排队次序和出队次序按进队时间先后确定,即先进队者先出队。因此,队列又称先进先出表.简称FIFO(first in first out)表.

队列的结构

在这里插入图片描述

队列的实现

在之前我们实现的栈中,我们是用顺序表实现的。而今天的队列我们用链表来实现,为什么不用顺序表来实现队列呢?这是因为我们的队列要进行队头出元素队尾进元素,如果是顺序表你频繁的去删除第一个元素,那么我们要将后面的元素频繁的往前挪动数据,导致效率变低。在下面我们就来实现队列。

队列的初始化

在初始化之前我们需要创建一个结点类型,类型包含了该队列每个结点的数据和指向下一结点的指针。

typedef int QueueDataType;
typedef struct QueueNode
{
	//数据域
	QueueDataType _data;
	//指针域,指向下一个结点
	struct QueueNode* _next;
}QueueNode;

我们知道队列与普通链表又有所不同,队列的基本信息要包括了队头和队尾,因为我们要进行头部出元素,尾部入元素。所以我们需要再创建一个结构体用于存放队列的队头队尾

typedef struct Queue
{
	//队头指针
	QueueNode* _head;

	//队尾指针
	QueueNode* _tail;
}Queue;

最后当我们创建一个队列的对象时,我们需要将这个Queue的队头与队尾进行初始化。

//初始化
void QueueInit(Queue* pQ)
{
	assert(pQ != NULL);
	pQ->_head = NULL;
	pQ->_tail = NULL;
}

队列的销毁

有初始化那么必定就会有销毁,因为我们的队列的结点都是动态开辟出来的,我们需要将每一个结点去删除。

//销毁
void QueueDestory(Queue* pQ)
{
	assert(NULL != pQ);
	
	while (NULL != pQ->_head)
	{
		QueueNode* next = pQ->_head->_next;
		free(pQ->_head);
		pQ->_head = next;
	}
	pQ->_head = NULL;
	pQ->_tail = NULL;
}

入队

在上面的概念中我们说到过,队列是一个先进先出的。这就好比我们去吃饭排队取号一样,取得号是前面的号数+1,并将你排队的信息插入到尾部。我们这里的入队同样是从尾部插入的。

//入队
void QueuePush(Queue* pQ, const QueueDataType x)
{
	assert(NULL != pQ);
	//创建一个新的结点,并赋予值
	QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newNode == NULL)
	{
		printf("分配空间失败\n");
		exit(-1);
	}
	else
	{
		newNode->_data = x;
		newNode->_next = NULL;
	}


	if (pQ->_head == NULL)
	{
		pQ->_head = pQ->_tail = newNode;
	}
	else
	{
		pQ->_tail->_next = newNode;
		pQ->_tail = newNode;
	}
}

出队

出队操作这里就好比你现在去吃饭,并且取到的号是1号,那么下一个就是你进去了,进去后的同时删除掉你排队的信息。同样出队,就是从头发删除掉一个元素。

//出队
void QueuePop(Queue* pQ)
{
	assert(pQ!=NULL);
	assert(pQ->_head != NULL);
	QueueNode* next = pQ->_head->_next;
	free(pQ->_head);
	pQ->_head= next;
	if (pQ->_head == NULL)
	{
		 pQ->_tail = NULL;
	}
}

获取队头元素

获取队列头部元素,即返回队头指针指向的数据即可。

//取队头元素
QueueDataType QueueFront(Queue* pQ)
{
	assert(pQ != NULL);
	assert(pQ->_head != NULL);
	return pQ->_head->_data;
}

获取队尾元素

获取队列尾部元素,即返回队尾指针指向的数据即可。

//取队尾元素
QueueDataType QueueBack(Queue* pQ)
{
	assert(pQ != NULL);
	assert(pQ->_tail != NULL);
	return pQ->_tail->_data;
}

判断队列是否为空

检测队列是否为空,即判断队头指针指向的内容是否为空。

//判断队是否为空,true表示队为空,false表示队不空
bool QueueEmpty(Queue* pQ)
{
	assert(pQ != NULL);
	if (pQ->_head == NULL)
	{
		return true;
	}
	return false;
}

查看队列中的元素个数

该函数不建议经常使用,因为我们每次使用时,都是从头部去依次遍历到尾部。时间复杂度为O(n)。如果频繁的需要知道队列的元素个数时,不妨在队列的结构体中增加一个元素个数的变量来记录当前元素的个数。

//队中元素得个数
int QueueSize(Queue* pQ)
{
	assert(pQ != NULL);
	QueueNode* cur = pQ->_head;
	int size = 0;
	while (cur!=NULL)
	{
		size++;
		cur = cur->_next;
	}
	return size;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值