数据结构【队列】

队列的的概念

队列是一种特殊的线性表,特殊之处在于它只允许在表的头部进行删除操作,而在表的尾部进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。

队列的特点

  1. 先进先出 :这是队列最大的特点,队列中所有的元素都遵循先进先出的原则进行管理数据,最先入队列的一定会最先出队列。
  2. 受限访问:队列操作数据时,只能对队头或者队尾进行操作。入队(插入数据)只会在队尾进行,出队(删除数据)只会在对头进行。
  3. 高效:进行删除和插入数据,最坏情况下的时间复杂度是O(1)。

队列的接口实现

队列可以使用数组和链表来实现,但是链表实现起来更清晰。

队列的结构

c 复制代码
typedef int QUEDATATYPE;

typedef struct QueueNode
{
	QUEDATATYPE data;
	struct QueueNode* next;
}QUENODE;

但是这样有个问题,我每次插入都要找尾节点,这样就太慢了,所以我们就用两个指针来解决这个问题,一个指针指向队列的头节点,一个用来指向队列的尾节点。

c 复制代码
typedef int QUEDATATYPE;

typedef struct QueueNode
{
	QUEDATATYPE data;
	struct QueueNode* next;
}QUENODE;

typedef struct Queue
{
	QUENODE* phead;
	QUENODE* ptail;
	int size;
}Queue;

队列的初始化

c 复制代码
//初始化队列
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

入队

入队操作在尾部进行

这里有有两个情况,队列为空与非空。

  • 为空的话,就直接将新节点赋给phead和ptail。
  • 非空,将ptail的next指针指向新节点,再更新ptail。
c 复制代码
//入队
void QueuePush(Queue* pq, QUEDATATYPE x)
{
	assert(pq);
	if (pq->phead == NULL)
	{
		QUENODE* Node = (QUENODE*)malloc(sizeof(QUENODE));
		if (Node == NULL)
		{
			perror("malloc fail");
			exit(1);
		}
		Node->data = x;
		Node->next = NULL;

		pq->phead = pq->ptail = Node;
	}
	else
	{
		QUENODE* Node = (QUENODE*)malloc(sizeof(QUENODE));
		if (Node == NULL)
		{
			perror("malloc fail");
			exit(1);
		}
		Node->data = x;
		Node->next = NULL;

		pq->ptail->next = Node;
		pq->ptail = Node;
	}
	pq->size++;
}

出队

出队操作在队头进行

出队同样也有两种情况,只剩下一个节点和多个节点。

  • 只有一个节点:也就是只有头节点了,直接将头节点释放掉就好了。
  • 多个节点:将头节点释放,更新头节点
c 复制代码
//出队
void QueuePop(Queue* pq)
{
	assert(pq && pq->size > 0);
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		QUENODE* tmp = pq->phead;
		pq->phead = pq->phead->next;
		free(tmp);
		tmp = NULL;
	}
	pq->size--;
}

获取队头元素

c 复制代码
// 获取队头元素 
QUEDATATYPE QueueHead(Queue* pq)
{
	assert(pq);
	return pq->phead->data;
}

判空

c 复制代码
//判空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

获取栈中有效元素个数

c 复制代码
// 获取栈中有效元素个数 
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

销毁队列

c 复制代码
//销毁队列
void QueueDestroy(Queue* pq)
{
	QUENODE* tmp = pq->phead;
	while (tmp)
	{
		pq->phead = pq->phead->next;
		free(tmp);
		tmp = pq->phead;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

完整代码

Queue.h

c 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int QUEDATATYPE;

typedef struct QueueNode
{
	QUEDATATYPE data;
	struct QueueNode* next;
}QUENODE;

typedef struct Queue
{
	QUENODE* phead;
	QUENODE* ptail;
	int size;
}Queue;

//初始化队列
void QueueInit(Queue* pq);
//入队
void QueuePush(Queue* pq, QUEDATATYPE x);
//出队
void QueuePop(Queue* pq);
// 获取队头元素 
QUEDATATYPE QueueHead(Queue* pq);
//判空
bool QueueEmpty(Queue* pq);
// 获取栈中有效元素个数 
int QueueSize(Queue* pq);
//销毁队列
void QueueDestroy(Queue* pq);

Queue.c

c 复制代码
#include"Queue.h"

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

//入队
void QueuePush(Queue* pq, QUEDATATYPE x)
{
	assert(pq);
	if (pq->phead == NULL)
	{
		QUENODE* Node = (QUENODE*)malloc(sizeof(QUENODE));
		if (Node == NULL)
		{
			perror("malloc fail");
			exit(1);
		}
		Node->data = x;
		Node->next = NULL;

		pq->phead = pq->ptail = Node;
	}
	else
	{
		QUENODE* Node = (QUENODE*)malloc(sizeof(QUENODE));
		if (Node == NULL)
		{
			perror("malloc fail");
			exit(1);
		}
		Node->data = x;
		Node->next = NULL;

		pq->ptail->next = Node;
		pq->ptail = Node;
	}
	pq->size++;
}

//出队
void QueuePop(Queue* pq)
{
	assert(pq && pq->size > 0);
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		QUENODE* tmp = pq->phead;
		pq->phead = pq->phead->next;
		free(tmp);
		tmp = NULL;
	}
	pq->size--;
}

// 获取队头元素 
QUEDATATYPE QueueHead(Queue* pq)
{
	assert(pq);
	return pq->phead->data;
}

//判空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

// 获取栈中有效元素个数 
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

//销毁队列
void QueueDestroy(Queue* pq)
{
	QUENODE* tmp = pq->phead;
	while (tmp)
	{
		pq->phead = pq->phead->next;
		free(tmp);
		tmp = pq->phead;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}
相关推荐
启观川5 小时前
数据结构与算法 -第 3 章 常用算法-动态规划
数据结构·笔记·python·算法
码爸5 小时前
排序算法介绍
python·算法·排序算法
动词ing6 小时前
【题目练习】算法 组合总和||
算法
wuminyu6 小时前
ForkJoinPool窃取线程在扫描其他WorkQueue时的随机采样算法与Phase线程挂起唤醒机制解析
java·linux·c语言·jvm·c++
longlongzihan7 小时前
链表找环:Floyd 判圈算法(LeetCode 141 & 142 )
c++·算法·leetcode·链表
专业程序开发源7 小时前
flask家电故障预测系统92491-计算机课程设计/毕业设计
vscode·python·sql·算法·flask·课程设计
Logic1017 小时前
C语言/数据结构欧几里得算法题解:长方形切割最大正方形——贪心划分计数
c语言·数据结构·算法·贪心算法·时间复杂度·空间复杂度·欧几里得算法
yi0117 小时前
LeetCode 643. 子数组最大平均数 I|从暴力枚举到滑动窗口
人工智能·笔记·python·算法·leetcode·滑动窗口
极光通讯8 小时前
服务器内存来料检验(IQC)实操:批次追溯、外观判定与上机验证
java·服务器·算法
淡海水8 小时前
02-04-原理篇-GC Roots与对象图遍历
算法·unity·c#·图·gc·遍历·roots