详解队列的接口函数

队列的定义

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。

进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。

队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。

因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO---first in first out)线性表。

简而言之:
队列是必须满足先进先出的线性表


准备工作

普通的队列一般用单链表实现

但也可以使用顺序表实现

-本篇文件采用单链表实现-

创建头文件Stack.h

将头文件和函数定义等放在Stack.h中,方便管理

创建源文件Stack.c

将接口函数的实现放在里面,方便管理

头文件的包含

c 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
  • stdio.h:用于标准输入输出等
  • assret.h:用于使用assret函数,实现报错
  • stdbool.h:用于使用布尔(bool)类型
  • stdlib.h:用于使用动态内存管理函数

定义保存队列数据的结构体

为什么要将队列里的数据的数据类型重命名?

这是为了以后如果改变了SL结构体中数据存储的类型时,
不用到处改函数参数等地方的数据类型,只要改typedef后的int 为对应要改成的数据类型就可以。

至于给结构体重命名则仅是为了方便使用


定义维护队列的队头和队尾指针的结构体


定义该结构体后,使用该结构体再定义一个结构变量,将其初始化后便可用其操作队列


初始化函数


从队尾插入数据

c 复制代码
void QueuePush(Queue* p, QuDataType x)
{
	assert(p);   如果传入的p是NULL,则属于操作错误,assert就会进行报错

	QN* tmp = (QN*)malloc(sizeof(QN));

	if (tmp == NULL)  如果tmp为NULL则动态内存申请失败,结束程序
	{
		printf("malloc失败!");
		exit(-1);  结束程序
	}
	tmp->data = x;
	tmp->next = NULL;  只能在  队尾  插入数据,所以插入的数据的下一个必定时NULL

	if (p->head == NULL)  如果队头为空,则队尾也一定为空
	{
		p->head = tmp;  让队头指向唯一的一个数据节点

		p->tail = tmp;  让队尾指向唯一的一个数据节点
	}
	else
	{
		p->tail->next = tmp;  让队尾指针指向的节点的next指向新节点tmp

		p->tail = tmp;  因为新节点tmp成为了最后一个节点,
		                所以将队尾指针指向更新成tmp
	}
}

图解

删除队头数据

图解

取队头数据(只取不删)


取队尾数据(只取不删)


统计队列的数据个数


判断队列是否为空


销毁队列


全部代码

Queue.h

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

typedef int QuDataType;

typedef struct QueueNode
{
	QuDataType data;
	struct QueueNode* next;
}QN;

typedef struct Queue
{
	QN* head;
	QN* tail;
}Queue;

//初始化
void QueueInit(Queue* p);

//队尾入
void QueuePush(Queue* p, QuDataType x);

//队头出(删一个队头)
void QueuePop(Queue* p);

//取队头数据(只取不删)
QuDataType QueueFront(Queue* p);

//取队尾数据(只取不删)
QuDataType QueueBack(Queue* p);

//队列的数据个数
int QueueSize(Queue* p);

//判断队列是否为空
bool QueueEmpty(Queue* p);

//销毁队列
void QueueDestory(Queue* p);

Queue.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS


#include"Queue.h"

void QueueInit(Queue* p)
{
	assert(p);//如果传入的p是NULL,则属于操作错误,assert就会进行报错

	p->head= NULL;//队列为空时队头指针为空

	p->tail= NULL;//队列为空时队尾也指针为空
}


//队尾入
void QueuePush(Queue* p, QuDataType x)
{
	assert(p);//如果传入的p是NULL,则属于操作错误,assert就会进行报错

	QN* tmp = (QN*)malloc(sizeof(QN));

	if (tmp == NULL)//如果tmp为NULL则动态内存申请失败,结束程序
	{
		printf("malloc失败!");
		exit(-1);//结束程序
	}
	tmp->data = x;
	tmp->next = NULL;//只能在  队尾  插入数据,所以插入的数据的下一个必定时NULL

	if (p->head == NULL)//如果队头为空,则队尾也一定为空
	{
		p->head = tmp;//让队头指向唯一的一个数据节点

		p->tail = tmp;//让队尾指向唯一的一个数据节点
	}
	else
	{
		p->tail->next = tmp;//让队尾指针指向的节点的next指向新节点tmp

		p->tail = tmp;//因为新节点tmp成为了最后一个节点,
		              //所以将队尾指针指向更新成tmp
	}
}

//队头出(删一个队头)
void QueuePop(Queue* p)
{
	assert(p);//如果传入的p是NULL,则属于操作错误,assert就会进行报错

	assert(p->head);//队头为空 即队列为空,队列为空时不能再删除

	//队列只有一个数据
	if (p->head == p->tail)//队头指针和队尾指针指向同一节点时
	{                      //队列只有一个节点
		
		p->tail = NULL;//删除最后一个节点后,队尾指针应该置空
	}
	//一般情况和特殊情况(队列只有一个数据)都可处理
	QN* tmp = p->head->next;//让tmp指向队的下一个节点

	free(p->head);//释放队头

	p->head = tmp;//让原队头的下一个节点成为新的队头
}

//取队头数据(只取不删)
QuDataType QueueFront(Queue* p)
{
	assert(p);//如果传入的p是NULL,则属于操作错误,assert就会进行报错

	assert(p->head);//队头为空 即队列为空,队列为空时取不出数据

	return p->head->data;//将  队头  指针指向节点的  数据返回出去
}


//取队尾数据(只取不删)
QuDataType QueueBack(Queue* p)
{
	assert(p);//如果传入的p是NULL,则属于操作错误,assert就会进行报错

	assert(p->tail);//队头为空 即队列为空,队列为空时取不出数据

	return p->tail->data;//将  队尾  指针指向节点的  数据返回出去
}


//统计队列的数据个数
int QueueSize(Queue* p)
{
	assert(p);//如果传入的p是NULL,则属于操作错误,assert就会进行报错

	QN* cur = p->head;//定义cur接收队头指针,用来遍历链表

	int count=0;//定义count用来统计数据个数
	while (cur)//cur不为空,就继续循环
	{
	    count++;
		cur = cur->next;//让cur指向下一个节点
	}
	return count;
}

//判断队列是否为空
bool QueueEmpty(Queue* p)
{
	assert(p);//如果传入的p是NULL,则属于操作错误,assert就会进行报错

	return p->head == NULL;//如果队头指针为空,队列就为空
	                       //队头为空时就return ture
	                       //队头不为空就  return false
}

//销毁队列
void QueueDestory(Queue* p)
{
	assert(p);//如果传入的p是NULL,则属于操作错误,assert就会进行报错

	if (p->head == NULL)//如果队头为空,队列就已经为空了,不用再销毁
		return;
	QN* cur = p->head;//定义cur接收队头指针,用来遍历链表

	QN* next = p->head->next;//定义next接收cur的下一个节点,用来存储下一个节点的地址
	p->head = NULL;//销毁队列后 队头指针要置空
	p->tail = NULL;//销毁队列后 队尾指针要置空

	while (next)//next不为空就继续循环
	{
		free(cur);//释放cur指向的节点
		cur = next;//让cur接收next中存储的下一个节点的地址

		next = next->next;//让next指向next的节点的下一个节点
	}
	free(cur);
}

以上就是全部内容了,如果对你有帮助的话,可以点个赞支持一下!!!

相关推荐
C++忠实粉丝1 小时前
前缀和(8)_矩阵区域和
数据结构·c++·线性代数·算法·矩阵
ZZZ_O^O1 小时前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树
代码雕刻家2 小时前
数据结构-3.9.栈在递归中的应用
c语言·数据结构·算法
Kalika0-04 小时前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
代码雕刻家4 小时前
课设实验-数据结构-单链表-文教文化用品品牌
c语言·开发语言·数据结构
龙图:会赢的4 小时前
[C语言]--编译和链接
c语言·开发语言
小字节,大梦想5 小时前
【C++】二叉搜索树
数据结构·c++
Cons.W6 小时前
Codeforces Round 975 (Div. 1) C. Tree Pruning
c语言·开发语言·剪枝
我是哈哈hh6 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
挥剑决浮云 -6 小时前
Linux 之 安装软件、GCC编译器、Linux 操作系统基础
linux·服务器·c语言·c++·经验分享·笔记