【C/数据结构】队列

队列的概念

        队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)入队列。


进行插入操作的一端称为队尾出队列,进行删除操作的一端称为队头


由于队列需要进行队列头部删除数据,队列尾部插入数据,所以使用链表较为合适【数组虽然队尾插入数据方便,但是队头删除数据非常麻烦】

队列的实现

队列的结构体

队列的核心操作是队列的尾部出队列,队列的头部入队列。而普通的单向链表传递头结点时,只能方便队头删除结点,而对位插入结点需要保存链表的最后一个结点。

// 单链表结构——》表示队列
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueuNode* next;
	QDataType data;
}QNode;

// 队列的结构——》一个指向头,一个指向尾部
typedef struct Queue
{
	QNode* head;
	QNode* tail;
}Queue;
  • 队列有两个指针,一个指针指向链表头结点,一个指针指向链表最后一个结点;
  • 每一个队列指针都保存着一个链表结点

队列初始化

// 队列初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

初始化队列时,不需要开辟内存空间

队列销毁

// 队列销毁
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}


队尾插入数据

// 队尾插入数据
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newNode = (Queue*)malloc(sizeof(Queue));
	if (newNode == NULL)
	{
		perror("newNode malloc fail!\n");
		return;
	}
	// 赋值数据
	newNode->data = x;
	newNode->next = NULL;
	// 判断队列是否为空
	if (pq->head == NULL)
	{
		assert(pq->tail == NULL);

		pq->head = pq->tail = newNode;
	}
	else
	{
		// tail后面链接
		pq->tail->next = newNode;
		// tail指向新的最后一个结点
		pq->tail = newNode;
	}
    pq->size++;
}

插入数据需要注意队列中没有元素的情况,需要将队列的头指针和尾指针均指向新结点


队头删除数据

// 队头删除数据
void QueuePop(Queue* pq)
{
	assert(pq);
	// 如果head不为空,说明没有结点
	assert(pq->head != NULL);

	// 保存第一个结点
	QNode* cur = pq->head;

	// 链接第二个结点/或者链接NULL
	pq->head = cur->next;
	// 删除第一个结点
	free(cur);
	cur->data = 0;
	cur->next = NULL;
	if (pq->head == NULL)
	{
		// 说明释放的时候只有一个结点
		pq->tail = NULL;
	}
	pq->size--;
}

这里重点需要考虑只有一个结点的情况,需要另外拿出来判断


 队列的元素个数

// 队列的元素个数
size_t QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

这里体现队列除了保存双指针,还添加保存了size数据的好处


队列是否为空

// 队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL;
}


访问队头元素数据

// 访问队头元素数据
QDataType QueueFront(Queue* pq)
{
	// 防止pq没有指向链表
	assert(pq);
	// 防止队列中没有元素
	assert(!QueueEmpty(pq));

	return pq->head->data;
}


访问队尾元素数据

// 访问队尾元素数据
QDataType QueueBack(Queue* pq)
{
	// 防止pq没有指向链表
	assert(pq);
	// 防止队列中没有元素
	assert(!QueueEmpty(pq));

	return pq->tail->data;
}

队列的优点和缺点

优点

  1. 插入/删除数据操作效率高,时间复杂度为O(1)
  2. 符合“先进先出”,适用于特殊场景

缺点

  1. 随机访问中间元素效率低,需要将数据一个一个出队列,时间复杂度O(N)
  2. 功能单一

队列的代码实现

Queue.h头文件

#ifndef QUEUE_H_
#define QUEUE_H_
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>


// 单链表结构——》表示队列
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueuNode* next;
	QDataType data;
}QNode;

// 队列的结构——》一个指向头,一个指向尾部
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	size_t size;
}Queue;


// 队列初始化
void QueueInit(Queue* pq);
// 队列销毁
void QueueDestroy(Queue* pq);
// 队尾插入数据
void QueuePush(Queue* pq, QDataType x);
// 队头删除数据
void QueuePop(Queue* pq);
// 队列的元素个数
size_t QueueSize(Queue* pq);
// 队列是否为空
bool QueueEmpty(Queue* pq);
// 访问队头元素数据
QDataType QueueFront(Queue* pq);
// 访问队尾元素数据
QDataType QueueBack(Queue* pq);

#endif

Queue.c源文件

#include"Queue.h"


// 队列初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

// 队列销毁
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

// 队尾插入数据
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newNode = (Queue*)malloc(sizeof(Queue));
	if (newNode == NULL)
	{
		perror("newNode malloc fail!\n");
		return;
	}
	// 赋值数据
	newNode->data = x;
	newNode->next = NULL;
	// 判断队列是否为空
	if (pq->head == NULL)
	{
		assert(pq->tail == NULL);

		pq->head = pq->tail = newNode;
	}
	else
	{
		// tail后面链接
		pq->tail->next = newNode;
		// tail指向新的最后一个结点
		pq->tail = newNode;
	}
	pq->size++;
}

// 队头删除数据
void QueuePop(Queue* pq)
{
	assert(pq);
	// 如果head不为空,说明没有结点
	assert(pq->head != NULL);

	// 保存第一个结点
	QNode* cur = pq->head;

	// 链接第二个结点/或者链接NULL
	pq->head = cur->next;
	// 删除第一个结点
	free(cur);
	cur->data = 0;
	cur->next = NULL;
	if (pq->head == NULL)
	{
		// 说明释放的时候只有一个结点
		pq->tail = NULL;
	}
	pq->size--;
}

// 队列的元素个数
size_t QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

// 队列是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL;
}

// 访问队头元素数据
QDataType QueueFront(Queue* pq)
{
	// 防止pq没有指向链表
	assert(pq);
	// 防止队列中没有元素
	assert(!QueueEmpty(pq));

	return pq->head->data;
}

// 访问队尾元素数据
QDataType QueueBack(Queue* pq)
{
	// 防止pq没有指向链表
	assert(pq);
	// 防止队列中没有元素
	assert(!QueueEmpty(pq));

	return pq->tail->data;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值