数据结构学习分享之栈和队列详解

news2024/11/22 18:14:00

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:数据结构学习分享⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你了解更多数据结构的知识
  🔝🔝

在这里插入图片描述


数据结构第五课

  • 1. 前言🥇
  • 2. 什么是栈?🥇
  • 3. 栈的实现🥇
    • 3.1 初始化结构🥈
    • 3.2 初始化函数🥈
    • 3.3 插入数据🥈
    • 3.4 删除数据🥈
    • 3.5 取栈顶数据🥈
    • 3.6 判断是否为空🥈
    • 3.7 打印函数🥈
    • 3.8 栈的数据个数🥈
    • 3.9 销毁栈🥈
  • 4. 什么是队列🥇
  • 5. 队列的实现🥇
    • 5.1 初始化结构🥈
    • 5.2 插入数据🥈
    • 5.3 删除数据🥈
    • 5.4 取队头和队尾数据🥈
    • 5.5 队列中数据个数🥈
    • 5.6 判断队列是否为空🥈
    • 5.7 打印函数🥈
  • 6. 栈和队列题目分享🥇
  • 7. 总结🥇


1. 前言🥇

这一节要分享的是一个全新的结构–栈和队列,栈和队列总是会一起出现,因为它们的存储方式刚好相反,一个先进先出一个先进后出,接下来我就来分享一下什么是栈和队列以及栈和队列的具体实现


2. 什么是栈?🥇

栈:一种特殊的线性表, 其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则.

  • 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶

  • 出栈:栈的删除操作叫做出栈。出数据也在栈顶

我们画一个图理解一下:
在这里插入图片描述

3. 栈的实现🥇

之前我们学了数组结构和链式结构,那么这个地方实现栈是用数组结构还是用链式结构呢?答案是数组结构更优,因为数组在尾上插入数据的代价比较小。

在这里插入图片描述

并且这里我们还是不采用定长数组的方式来表示栈,我们采用动态长度的数组来表示


3.1 初始化结构🥈

有了之前实现顺序表的基础,这里我们直接上代码再解释

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>//返回布尔值要包含的头文件

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;//结构体中定义一个数组
	int top;//栈顶,出数据和入数据都要从栈顶开始
	int capacity;//数组的容量(容量不足需要扩容)
}ST;

和顺序表不同的是,定义栈的结构体我们用的是top而不是size,因为事实上这里top是栈顶也是有效数据个数


3.2 初始化函数🥈

上代码!

void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = 0;//top定义为0指向栈顶数据的下一位,top定义为-1指向栈顶数据
	ps->capacity = 0;
}

top你可以任意定义为0或者1,具体为什么指向栈顶为什么指向栈顶下一个可以参考下图 :

在这里插入图片描述

写好初始化函数之后,可以在test.c文件中定义一个结构体并且初始化一下,方便我们后期检查

    ST st;//定义结构体
	StackInit(&st);//初始化

3.3 插入数据🥈

这里的插入数据与之前的顺序表和链表不同,因为栈这个结构有规定只允许一遍插入数据,所以这个地方不存在什么头插尾插,只有一个插入方式

void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->top == ps->capacity)//当top与capacity相同代表空间已满或者没有空间
	{
		int newcapacity = ps->capacity == 0 ? 4 : 2 * (ps->capacity);//这里的方法和顺序表一样
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType)*newcapacity);
		ps->capacity = newcapacity;
		ps->a = tmp;
	}
	ps->a[ps->top] = x;
	ps->top++;//将top指向下一份空间
}

这里的插入和顺序表的尾插基本上是一样的,这里就不再做过多的说明,如果你不太明白这里的内容,请点击后面蓝字跳转到顺序表看看详解顺序表详解


3.4 删除数据🥈

void StackPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);//保证栈中存在数据
	ps->top--;
}

这里的删除数据和顺序表的删除不能说很相似,只能说完全一样🕶,但是这个地方关于栈的删除也是有要求的,那就是要从栈顶删除,满足我们先进先出的关系.


3.5 取栈顶数据🥈

这个函数是我们顺序表和链表没有的,是因为这个函数对于栈来说比较常用,假如我们想打印栈中所有的数据,这个时候取栈顶数据函数就可以排上用场了,我们后面写完打印函数后在test.c文件中实际操作一下

STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);//保证栈中数据不为空
	return ps->a[ps->top-1];//top是栈顶下一个位置,top-1才是栈顶
}

注意这里函数的返回类型是STDataType,我们栈中存储什么类型的数据就返回什么类型


3.6 判断是否为空🥈

bool StackEmpty(ST* ps)
{
	assert(ps);
	if (ps->top <= 0)
	{
		return true;
	}
	else
	{
		return false;
	}
}

这里可能是我们第一次接触到bool(布尔类型),它的意思就是返回真(true)或假(false),它需要包含的头文件是stdbool.h, 这里栈为空就返回true,栈不为空就返回false


3.7 打印函数🥈

void StackPrint(ST* ps)
{
	assert(ps);
	while (ps->top >0)//不能等于0,等于0后面再减一就是负数了
	{
		printf("%d ", ps->a[ps->top - 1]);
		ps->top--;
	}
	printf("\n");

我们写完打印函数后就可以根据前面实现的插入删除,取栈顶等操作来玩一玩:(解释在代码中)

    ST st;
	StackInit(&st);
	StackPush(&st, 2);//插入2 3 4 5
	StackPush(&st, 3);//实际上出数据要从5开始出
	StackPush(&st, 4);
	StackPush(&st, 5);
	while (!StackEmpty(&st))//当栈不为空时进入while循环
	{
		printf("%d ", StackTop(&st));//打印栈顶的数据
		StackPop(&st);//再删除栈顶的数据,打印一个删除一个
	}

3.8 栈的数据个数🥈

int StackSize(ST* ps)
{
	assert(ps);
	return ps->top;//top等于2有a[0]和a[1]两个数据
}

注意这里返回的是数据个数而不是数据本身,所以我们用 int 类型.


3.9 销毁栈🥈

void StackDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

每次用完栈后要记得销毁,下次再次使用时又重新定义结构体.



4. 什么是队列🥇

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

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

在这里插入图片描述
满足先进先出


5. 队列的实现🥇

和栈一样,实现队列的时候也有两种结构选择:数组结构和链式结构. 这里使用链式结构更优一些 因为如果使用数组的结构,出队列在数组头上出数据,要将后面所有数据向前挪动,效率会比较低。

在这里插入图片描述


5.1 初始化结构🥈

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

typedef int QDataType;

typedef struct QueueNode//定义链式结构
{
	struct QueueNode* next;
	QDataType data;
}QN;

typedef struct Queue//定义一个结构体,结构体中有两个指针.一个指向队头一个指向队尾
{
	QN* head;//其中,head是链式结构的指针,head中有data和next(如head->data)
	QN* tail;//tail也是定义的链式结构指针.
}Queue;

这里和我们之前定义的链表有所不同,我们的链表只定义了一个指针指向,而我们的队列定义了两个指针指向并且把这两个指针放在了一个结构体当中,这是因为链表中定义两个指针的用处不大,也就是如果它定义两个指针有一个指针不常用,然而队列这个地方删除是队头,插入是队尾,所以这里定义两个指针很有必要.

它其实就是一种套娃结构:
在这里插入图片描述



5.2 插入数据🥈

void QueuePush(Queue* pq,QDataType x)
{
	assert(pq);
    QN* newnode = (QN*)malloc(sizeof(QN));
	newnode->data = x;
	newnode->next = NULL;
	if (pq->head == NULL)//head为空的情况
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;//队尾插入新的数据
		pq->tail = newnode;//再把新节点给上队尾
	}
}

之前说过,链式结构只要是插入数据就要重新向内存申请一块空间,并且当我们的队列为空时要特殊处理(实际上就是尾插)


5.3 删除数据🥈

void QueuePop(Queue* pq)//实际上是头删
{
	assert(pq);
	assert(pq->head != NULL);//保证队列中还存在数据
	QN* cur = pq->head;
	QN* next = cur->next;//定义一个next指针,不然free掉cur后就找不到下一个节点了
	free(cur);
	cur = NULL;
	pq->head = next;//再把next给上新头
	if (pq->head == NULL)//当删除到最后一个数据时,要把tail一起置空,否则下次再插入数据会出问题
	{
		pq->tail = NULL;
	}
}

这个地方要注意的有两点:

  • 删除数据前要判断队列中还有没有数据.

  • 当删除到最后一个数据时,要把尾指针给置空,否则我们的尾指针还是指向原先的位置,下一次插入数据的时候,tail的指向会出现问题


5.4 取队头和队尾数据🥈

队列与栈不同的是队列有两个口子可以操作,一个进一个出,而栈只有一个,所以这里取数据比栈要多一个

QDataType QueueFront(Queue* pq)//取队头数据,也就是即将出队列的数据
{
	assert(pq);
	assert(pq->head);//保证队列中有数据
	QN* cur = pq->head;
	return cur->data;
}

🫵🫵🫵

QDataType QueueBack(Queue* pq)取队尾数据,也就是最后一个出队列的数据
{
	assert(pq);
	assert(pq->head);//保证队列中有数据
	QN* cur = pq->tail;
	return cur->data;
}

5.5 队列中数据个数🥈

size_t QueueSize(Queue* pq)
{
	assert(pq);
		int count = 0;
        QN* cur = pq->head;
		while (cur)
		{
			count++;
			cur = cur->next;
		}
		return count;
}

我们之前说过 size_t 就是无符号整型的意思,这里是返回数据个数而不是数据本身,所以是整型类型


5.6 判断队列是否为空🥈

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	if (pq->head == NULL)
	{
		return true;
	}
	else
	{
		return false;
	}
}

这里返回的是布尔值,我们之前已经提到过一次.队列为空就返回true,为假就返回false


5.7 打印函数🥈

void QueeuPrint(Queue* pq)
{
	assert(pq);
	QN* cur = pq->head;
	while (cur != NULL)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

因为队列是队头先出数据,所以打印数据时要从队头开始往后走

这里我们写完打印函数就可以在test.c文件中测试运行一下了:

#include"Queue.h"

    Queue q;//定义一个结构体,结构体中有head和tail两个指针指向
	QueueInit(&q);//初始化
	QueuePush(&q, 1);
	QueuePush(&q, 3);//依次插入1 3 5 7
	QueuePush(&q, 5);
	QueuePush(&q, 7);
	while (!QueueEmpty(&q))//当队列不为空就进入while循环
	{
		QDataType front = QueueFront(&q);//取队头数据
		printf("%d ", front);//打印队头数据
		QueuePop(&q);//打印队列,一边打印一边删除
	}

6. 栈和队列题目分享🥇

现学现用 ! 我现在给出几道题,非常的经典 ! 大家可以取尝试一下,我会在下周以内出肝出一篇这几个OJ题的详解,敬请期待:

🫵🫵🫵

  • 括号匹配问题 : OJ题链接🏆

  • 用队列实现栈 :OJ题链接🏆

  • 用栈实现队列 : OJ题链接🏆

7. 总结🥇

这一章介绍了两个全新的数据结构:栈和队列,它们总是容易搞混,栈是先进先出,队列是先进后出,栈是用数组实现其结构,队列是用链表实现其结构.这个地方讲完小编会停止更新数据结构一段时间去深度学习一下后面的内容:二叉树和堆,以便给大家做更详细的讲解.(C语言学习分享和刷题思路分享不停更💞💞)

💕 我的码云:gitee-杭电码农-NEO💕

🔎 下期预告:二叉树和堆 🔍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/489291.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

文心一言 VS chatgpt (14)-- 算法导论3.2 2~3题

二、证明等式&#xff08;3.16&#xff09;&#xff1a;a ^ {\log_b c} c ^ {\log_b a}。 文心一言&#xff1a; chatgpt&#xff1a; 我们需要证明的等式为&#xff1a; a log ⁡ b c c log ⁡ b a a^{\log_b c} c^{\log_b a} alogb​cclogb​a。 首先&#xff0c;将 l…

时序预测 | MATLAB实现ARIMA-BP组合模型时间序列预测

时序预测 | MATLAB实现ARIMA-BP组合模型时间序列预测 目录 时序预测 | MATLAB实现ARIMA-BP组合模型时间序列预测预测效果基本介绍模型原理程序设计参考资料 预测效果 基本介绍 时序预测 | MATLAB实现ARIMA-BP组合模型时间序列预测。 模型原理 ARIMA-BP组合模型是一种常用的时间…

2023年第二届材料科学与工程国际会议(CoMSE 2023) | IOP-JPCS出版

会议简介 Brief Introduction 2023年第二届材料科学与工程国际会议(CoMSE 2023) 会议时间&#xff1a;2023年7月21日-23日 召开地点&#xff1a;中国泰州 大会官网&#xff1a;www.icomse.org CoMSE 2023由四川大学、华南理工大学亚热带建筑科学国家重点实验室、国际电气电子和…

PCL学习四:RANSAC-随机采样一致性

参考引用 Point Cloud Library黑马机器人 | PCL-3D点云 1. RANSAC 概念及作用 RANSAC&#xff08;Random Sample Consensus&#xff0c;随机采样一致性&#xff09;是一种迭代方法&#xff0c;作用&#xff1a;从包含异常值的一组数据中估计数学模型的参数&#xff0c;RANSAC 算…

AIGC:【LLM(一)】——LoRA微调加速技术

文章目录 一.微调方法1.1 Instruct微调1.2 LoRA微调 二.LoRA原理三.LoRA使用 一.微调方法 Instruct微调和LoRA微调是两种不同的技术。 1.1 Instruct微调 Instruct微调是指在深度神经网络训练过程中调整模型参数的过程&#xff0c;以优化模型的性能。在微调过程中&#xff0c…

Flutter——最详细(TextField)使用教程

TextField简介 文本输入框&#xff0c;拥有复杂的属性。可指定控制器、文字样式、装饰线、行数限制、游标样式等。监听输入框变动事件。 使用场景&#xff1a; 搜索框&#xff0c;输入账号密码等 属性作用controller输入框监听器decoration输入框装饰属性textAlign内容对齐方式…

UE5.1.1 C++ 从0开始 (1.人物移动)

开个天坑&#xff0c;UE5.1.1的移动代码做了一个大更新&#xff0c;对于我这种万年蓝图然后正在转C的人来说可以说是个挑战也可以说是个更方便我去工作的一个点。同时斯坦福大学的那个教程的开头几个章节就不适用了&#xff0c;对于学习UE5.1.1的同学来说。所以我这里会尽量每天…

[230506] 2021年托福阅读真题第6篇|Water and Life on Mars|15:30~16:30|16:30~19:19

正确率&#xff1a;6/10 ​​​​​​​ Water and Life on Mars Paragraph 1: The question of life on Mars depends heavily on the characteristics of its air and water. Mars has a relatively thin and dry atmosphere, with a high percentage of carbon dioxide com…

想转行大数据,需要学习什么?

Python近段时间一直涨势迅猛&#xff0c;在各大编程排行榜中崭露头角&#xff0c;得益于它多功能性和简单易上手的特性&#xff0c;让它可以在很多不同的工作中发挥重大作用。 正因如此&#xff0c;目前几乎所有大中型互联网企业都在使用 Python 完成各种各样的工作&#xff0…

Spark大数据处理讲课笔记3.7 Spark任务调度

文章目录 零、本节学习目标一、有向无环图&#xff08;一&#xff09;DAG概念&#xff08;二&#xff09;实例讲解 二、Stage划分依据&#xff08;一&#xff09;两阶段案例&#xff08;二&#xff09;三阶段案例 三、RDD在Spark中的运行流程&#xff08;一&#xff09;RDD Obj…

buuctf7

目录 Crypto MD5 Url编码 看我回旋踢 web [极客大挑战 2019]BuyFlag​ [BJDCTF2020]Easy MD5 Crypto MD5 1.下载文件 2.md5在线解密 3.外包flag Url编码 使用url在线解码 看我回旋踢 下载&#xff0c;得到这串字符&#xff0c;搜一下synt编码 看到使用凯撒密码&#x…

2023-05-04:用go语言重写ffmpeg的scaling_video.c示例,用于实现视频缩放(Scaling)功能。

2023-05-04&#xff1a;用go语言重写ffmpeg的scaling_video.c示例&#xff0c;用于实现视频缩放&#xff08;Scaling&#xff09;功能。 答案2023-05-04&#xff1a; 这段代码实现了使用 libswscale 库进行视频缩放的功能。下面是程序的主要流程&#xff1a; 1.获取命令行参…

唐书计组第三章总线部分课后习题和解答

我自己的一些总结 总线周期分为哪四个阶段 申请分配阶段寻址阶段存数阶段结束阶段 总线分为哪四种通信方式 同步通信异步通信半同步通信分离式通信 总线有哪几种判优方式 链式查询 计数器定时查询 独立请求方式 计算数据传输率 3.14设总线的时钟频率为8MHz,一个总线周期…

(3)信号槽

目录 1.信号槽的概念 2.信号槽的连接 2.1自带信号 → 自带槽 2.2 自带信号 → 自定义槽 2.3 自定义信号 1.信号槽的概念 信号槽指的是信号函数与槽函数的连接&#xff0c;可以使用不同的对象通过信号槽连接在一起&#xff0c;从而实现对象之间的通信。 可以把信号槽的连接…

数字化经营3.0阶段,云徙科技如何定义“为增长而生”?

作者&#xff1a;Lucky 新时代风云变幻中&#xff0c;通过数字化转型&#xff0c;驱动业务增长、提升运营效率是企业升级的必由之路。如今&#xff0c;数字化经营也已经进入3.0阶段&#xff0c;企业对“人、货、场”三位一体的前端数字化的要求更高&#xff0c;行业也需要更有效…

Java设计模式-建造者模式

简介 建造者模式是一种创建型设计模式&#xff0c;用于将复杂对象的构建过程与其表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。建造者模式通过将复杂对象的构建过程分解为多个简单的步骤来实现。 与其他创建型模式不同&#xff0c;建造者模式强调的是将构建过…

QML路径视图(The PathView)

路径视图&#xff08;PathView&#xff09;非常强大&#xff0c;但也非常复杂&#xff0c;这个视图由QtQuick提供。它创建了一个可以让子项沿着任意路径移动的视图。沿着相同的路径&#xff0c;使用缩放&#xff08;scale&#xff09;&#xff0c;透明&#xff08;opacity&…

nssctf (1)

[NISACTF 2022]popchains Happy New Year~ MAKE A WISH <?phpecho Happy New Year~ MAKE A WISH<br>;if(isset($_GET[wish])){ #通过get获取wish的值 并判断是不是空@unserialize($_GET[wish]); #反序列化wish } else{$a=new Road_is_Long; #实例化Road_is…

YOLOv5:添加SE、CBAM、CoordAtt、ECA注意力机制

YOLOv5&#xff1a;添加SE、CBAM、CoordAtt、ECA注意力机制 前言前提条件相关介绍注意力机制SE添加SE注意力机制到YOLOv5 CBAM添加CBAM注意力机制到YOLOv5 CoordAtt添加CoordAtt注意力机制到YOLOv5 ECA添加ECA注意力机制到YOLOv5 参考 前言 记录在YOLOv5添加注意力机制&#xf…

原神3.2真端完整版架设教程

想必在座的各位都玩过这款游戏吧、开放世界的玩法、折磨人的剧情、做不完的任务、话多且烦人的派蒙、没眼看的伤害、贵到爆的抽卡、打不动的深渊、树脂刷空也刷不到想要的圣遗物、打不动的BOSS、这怎么受得了呀!反正我是受不了。废话不多说、教程开始。 准备工具: 一台16H 3…