当前位置: 首页 > news >正文

队列(C/C++)

前言

本文介绍队列的基本知识,包括概念、初始化、销毁、入队、出队、求队首队尾值以及计算有效元素个数

队列

    • 前言
    • 正文
      • 1概念与结构
    • 2.常见操作基本实现
      • Queue.h
      • Queue.c
        • 初始化与销毁
        • 入队
        • 判断队列是否为空
        • 出队
        • 取队头或队尾数据
        • 队列中的有效元素
      • test.c
    • 结语

正文

1概念与结构

概念:只允许在一端进行插入的数据操作,在另一端进行删除数据操作的特殊线性表
队列具有先入先出
入队列:进行插入的一段称为队尾
出队列:进行删除操作的一段称为队头
队列
那么队列的底层结构如何选选择?数组or链表

数组
入队,可以直接找到,时间复杂度为O(1)
出队,需要遍历,时间复杂度为O(N)
链表
出队,对头出队,O(1)
入队,需要找到尾指针,O(N)

这样看来似乎哪个都行没有区别,但是,对于链表而言,如果我们直接定义一个队尾的指针,时间复杂度岂不是O(1).
代码如下:

//队列结点的结构
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QueueNode;
//队列的结构
typedef struct Queue
{
	QueueNode* phead;
	QueueNode* ptail;
}Queue;

2.常见操作基本实现

本文依旧是多文件形式

Queue.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int QDataType;
//队列结点的结构
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QueueNode;
//队列的结构
typedef struct Queue
{
	QueueNode* phead;
	QueueNode* ptail;
	//int size; //队列中有效数据个数
}Queue;

//初始化
void QueueInit(Queue* pq);
//销毁队列
void QueueDestroy(Queue* pq);

//入队——队尾
void QueuePush(Queue* pq, QDataType x);

//出队——队头
void QueuePop(Queue* pq);

//队列判空
bool QueueEmpty(Queue* pq);

//队列有效元素个数
int QueueSize(Queue* pq);

//取队头数据
QDataType QueueFront(Queue* pq);

//取队尾数据
QDataType QueueBack(Queue* pq);

Queue.c

初始化与销毁

初始化:令phead和ptail为NULL
销毁:定义pcur指针,保存pcur->next,然后逐个销毁pcur。

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

//销毁队列
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QueueNode* pcur = pq->phead;
	while (pcur)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	pq->phead = pq->ptail = NULL;
	//pq->size = 0;
}
入队

在这里插入图片描述
定义一个新结点,插入队尾入队

//入队——队尾
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next =NULL;

	//若队列为空
	if (pq->phead == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	//队列非空
	else {
		pq->ptail->next = newnode;
		pq->ptail = pq->ptail->next;
	}
	//pq->size++
}

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

只有一个结点phead和ptail置为空,
有多个结点,因为对头出队,所有先要保存头结点的下一个指针phead->next,释放头指针phead,让phead->next成为新的头指针

//出队——对头
void QueuePop(Queue* pq)
{
	assert(!QueueEmpty(pq));
	//只有一个结点,phead和ptail都置为空
	if (pq->phead == pq->ptail)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;

	}
	else
	{
		QueueNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	//pq->size--;
}

取队头或队尾数据

注意:这里是拿出来用并不是销毁,该数据还在队列中
直接返回对应位置的data值即可

//取队头数据
QDataType QueueFront(Queue* pq)
{
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}

//取队尾数据
QDataType QueueBack(Queue* pq)
{
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}
队列中的有效元素

见代码

//队列有效元素个数
int QueueSize(Queue* pq)
{
	assert(pq);
	//方法一:遍历列表——适用于不频繁调用队列有效数据个数的场景(空间复杂度较高O(N))
	QueueNode* pcur = pq->phead;
	int size = 0;
	while (pcur)
	{
		size++;
		pcur = pcur->next;
	}
	return size;

	//方法二:遍历链表——适用于频繁调用队列有效数据个数的场景
	//return pq->size;
}

test.c

用于测试

#include"Queue.h"

void test()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePop(&q);
	int front = QueueFront(&q);
	int rear = QueueBack(&q);
	printf("front:%d\n", front);
	printf("rear:%d\n", rear);
	printf("size:%d", QueueSize(&q));
	QueueDestroy(&q);
}

int main()
{
	test();
	return 0;
}

结语

这篇介绍链表的基本实现,但如需要进一步来学习栈与队列,请关注下一篇栈与队列OJ,希望三连支持一下谢谢。

相关文章:

  • 25/4/6 算法笔记<仿真O2DES>基础知识学习
  • CasaOS小主机本地安装1Panel运维面板结合内网穿透移动端远程运维
  • 【网络安全】大学信息安全技术 期末考试复习题
  • 力扣热题100——动态规划(上)
  • B站视频教材: Yocto项目实战教程 第一章 PPT讲解
  • 【dify应用】将新榜排行数据免费保存到飞书表格
  • Android Transition转场动效使用全解析
  • 精心整理的 22道 Kafka 高频面试题(含答案),你都会了吗?
  • [leetcode] 面试经典 150 题——篇9:二叉树(番外:二叉树的遍历方式)
  • AI Agent开发大全第二十一课-如何开发一个MCP(从0开发一个MCP Client)
  • Kafka 的发展历程
  • React学习-css
  • 【IDEA】✈️自定义模板,自动生成类和方法注释
  • 差分音频转单端音频单电源方案
  • 小菜Go:Ubuntu下Go语言开发环境搭建
  • 工控机和笔记本互传(①笔记本充当工控机的显示器、②笔记本控制工控机)
  • TypeScript 中interface和type的区别?
  • SDL视频显示函数
  • 数据倾斜:分布式系统中的性能杀手与应对之道
  • React Context API 用于在组件树中共享全局状态
  • 专家称第二波疫情风暴会很低/北京seo包年
  • 网站设计师加油站/优秀品牌策划方案
  • 美妆销售网站开发的目的/网络营销课程心得体会
  • 常州 做网站/企业网站首页
  • 网站销售的优势/湘潭高新区最新新闻
  • seo网站策划/引流软件下载站