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

数据结构-栈和队列

文章目录

  • 一、栈
    • 1.概念与结构
    • 2.数组栈的实现
      • 2.1 栈的结构定义
      • 2.2 栈的初始化
      • 2.3 栈的销毁
      • 2.4 栈的判空
      • 2.5 栈的入栈
      • 2.6 栈的出栈
      • 2.7 查看栈顶元素
      • 2.8 栈的大小
    • 3.两种栈的图示结构
  • 二、队列
    • 1.概念与结构
    • 2.链式队列的实现
      • 2.1 队列的结构定义
      • 2.2 队列的初始化
      • 2.3 队列的销毁
      • 2.4 队列的判空
      • 2.5 队列的入队
      • 2.6 队列的出队
      • 2.7 查看队头元素
      • 2.8 查看队尾元素
      • 2.9 队列的大小
    • 3.链式队列的图示结构

一、栈

1.概念与结构

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

压栈: 栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈: 栈的删除操作叫做出栈。出数据也在栈顶。

在这里插入图片描述栈底层结构选型
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。

2.数组栈的实现

2.1 栈的结构定义

typedef int STDataType;
typedef struct Stack
{STDataType* arr;int top; int capacity; //空间容量
}ST;

arr就是待开辟空间的指针。top可以有两种选择:一种是指向栈顶元素,另一种就是指向栈顶元素的下一个位置。现在我们定义一个栈的变量:

ST st;

2.2 栈的初始化

void STInit(ST* pst)
{assert(pst != NULL);pst->arr = NULL;//pst->top = -1; //top指向栈顶元素pst->top = 0; //top指向栈顶元素的下一个位置pst->capacity = 0;
}

由于定义的是一个结构体变量st,要改变该结构体,就要传st的指针。所以要断言pst不能为空,开始先初始化数组的指针为空。对于top我们说过有两种定义方式:

当top初始化为-1时,说明top指向的是栈顶元素,top==-1时说明栈顶还没有存储元素。top==-1是数组第一个元素的前一个位置,是非法的:
在这里插入图片描述

当top初始化为0时,说明top指向的是栈顶元素的下一个位置,top==0时说明栈顶还没有数据:
在这里插入图片描述

capacity就是数组能存储的元素个数。

2.3 栈的销毁

void STDestroy(ST* pst)
{assert(pst != NULL);free(pst->arr);pst->arr = NULL;pst->top = pst->capacity = 0;
}

由于动态开辟的是一块连续的空间,所以释放空间很简单,直接free掉arr,再把arr置空,top和capacity赋值为0即可。pst仍然要断言不能为空。

2.4 栈的判空

bool STEmpty(ST* pst)
{assert(pst != NULL);return pst->top == 0;
}

判空就是判断栈顶是否有数据,初始化的top是为0的,说明top指向的是栈顶元素的下一个位置。所以如果表达式top==0为真,则返回true,否则返回false。

2.5 栈的入栈

void STPush(ST* pst,STDataType x)
{assert(pst != NULL);if (pst->top == pst->capacity){int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDataType* tmp = (STDataType*)realloc(pst->arr, newCapacity*sizeof(STDataType));if (tmp == NULL){perror("realloc fail!");return NULL;}pst->arr = tmp;pst->capacity = newCapacity;}pst->arr[pst->top++] = x;
}

由于top是指向栈顶元素的下一个位置,所以在压栈之前,要先判断数组是否满了,也就是当top==capacity时,要么是数组里还没有元素,要么就是数组存储满了。realloc就能实现空间的扩容。如果还没有开辟空间,那realloc的功能就相当于malloc。在压栈后,记得要把top往后挪一位,指向栈顶元素的下一个位置。

2.6 栈的出栈

void STPop(ST* pst)
{assert(pst != NULL);assert(!STEmpty(pst));pst->top--;
}

由于栈的特点是后进先出,所以栈里元素的出栈,要从栈顶出元素才行。直接让top往前挪一位即可。但在删除栈顶元素之前要先判空。因为如果栈里没有元素,则不能进行出栈操作。

2.7 查看栈顶元素

STDataType STTop(ST* pst)
{assert(pst != NULL);assert(!STEmpty(pst));return pst->arr[pst->top - 1];
}

在返回栈顶元素之前要先判断栈是否为空,不为空再返回栈顶的元素。注意:top是指向栈顶元素的下一个位置的,所以栈顶元素的位置是top-1。

2.8 栈的大小

int STSize(ST* pst)
{assert(pst != NULL);return pst->top;
}

栈的大小即数组中的有效元素个数。由于top是指向栈顶元素的下一个位置的,所以top刚好就可以表示数组中的有效元素个数。注意:如果一开始top是初始化为-1的话,那数组的有效元素个数就要返回top+1。

3.两种栈的图示结构

在这里插入图片描述在这里插入图片描述记住:栈的特点是后进先出(Last In First Out),所以链式栈的进栈出栈要在头结点处进行。
🧳🧳栈就像箱子一样:往箱子里放东西会从箱底放起,直到放满;然后从箱子里取东西就要从箱顶开始取,否则你取不到箱底的东西。 这就是后进先出的意思。

代码仓库:Stack

二、队列

1.概念与结构

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

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

在这里插入图片描述队列底层结构选型
队列也可以使用数组或链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列要在数组头出数据,效率会比较低。

2.链式队列的实现

2.1 队列的结构定义

//1.节点结构
typedef int QDataType;
typedef struct QueueNode
{QDataType data;struct QueueNode* next;
}QNode;
//2.队列结构
typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;

队列的结构中只有三个成员,phead是用来指向链表的头的,ptail是用来指向链表的尾的。因为队列是先进先出的特点,所以链式队列是在队头出数据,在队尾进数据。有了phead和ptail指针就方便我们管理链表。size是链表的元素个数(节点个数)。

若现在创建了一个结构体变量:

Queue q;

2.2 队列的初始化

void QueueInit(Queue* pq)
{assert(pq != NULL);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}

注意:我们创建的是一个结构体变量q,所以要改变该变量,就要传该变量的地址才行。所以要对pq进行断言不能为空。

2.3 队列的销毁

void QueueDestroy(Queue* pq)
{assert(pq != NULL);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}

队列的销毁就是释放链表中的所有节点,然后要记得把phead和ptail置为空,size赋值为0。链式队列的销毁就跟单链表的销毁是一样的。

2.4 队列的判空

bool QEmpty(Queue* pq)
{assert(pq != NULL);return pq->phead == NULL&& pq->ptail == NULL;
}

理论上如果链表为空,那phead和ptail都为空,但是两个一起判断更好,以免出啥bug。当然也可以通过判断size是否等于0来判断队列是否为空。

2.5 队列的入队

void QueuePush(Queue* pq, QDataType x)
{assert(pq != NULL);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail!");return;}newnode->data = x;newnode->next = NULL;if (pq->ptail == NULL){assert(pq->phead == NULL);pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}

先创建一个新节点,然后需要判断此时队列是否为空,为空是一种情况,不为空也是一种情况。为空就让phead和ptail都指向newnode;不为空就要在尾结点ptail处进行尾插。数据入队后,记得要让size+1。

2.6 队列的出队

void QueuePop(Queue* pq)
{assert(pq != NULL);assert(!QEmpty(pq));if (pq->phead->next == NULL){free(pq->phead);pq->phead = pq->ptail = NULL;}else{QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}pq->size--;
}

元素出队也是需要分类讨论的,如果队列为空就不能进行出队操作,所以要先判空。如果是队列中只有一个节点,那phead和ptail此时都指向这个节点,所以直接释放掉phead即可,但是要记得把两个指针都置空,否则会出现野指针。如果队列中不止一个节点,那直接在头结点phead处进行头删。出队一个元素,记得要让size-1。

2.7 查看队头元素

QDataType QueueFront(Queue* pq)
{assert(pq != NULL);assert(!QEmpty(pq));return pq->phead->data;
}

如果队列为空,则链表为空,没有队头数据。所以要判先空。

2.8 查看队尾元素

QDataType QueueBack(Queue* pq)
{assert(pq != NULL);assert(!QEmpty(pq));return pq->ptail->data;
}

查看队尾元素也是要先判断队列是否为空,队列为空就没有队尾元素。

2.9 队列的大小

int QueueSize(Queue* pq)
{assert(pq != NULL);return pq->size;
}

队列的大小就是队列中的元素个数(节点个数)size,返回size即可。

3.链式队列的图示结构

在这里插入图片描述在这里插入图片描述
在这里插入图片描述记住:队列的特点是先进先出(First In Fitst Out),所以链式队列的入队要在链表的尾结点处尾插,而出队要在链表的头节点处头删。
⬅️🚶🚶‍♂️🚶‍♀️⬅️队列就像排队打饭一样:先来的同学会排在队伍的前面,而后来的同学会排在队伍的后面。排在最前面的同学会先打到饭离开队伍,而排在队伍后面的同学需要等待前面的同学离开了才能打到饭。这就是先进先出的意思。

代码仓库:Queue
在这里插入图片描述

相关文章:

数据结构-栈和队列

文章目录 一、栈1.概念与结构2.数组栈的实现2.1 栈的结构定义2.2 栈的初始化2.3 栈的销毁2.4 栈的判空2.5 栈的入栈2.6 栈的出栈2.7 查看栈顶元素2.8 栈的大小 3.两种栈的图示结构 二、队列1.概念与结构2.链式队列的实现2.1 队列的结构定义2.2 队列的初始化2.3 队列的销毁2.4 队…...

RabbitMQ---TTL与死信

(一)TTL 1.TTL概念 TTL又叫过期时间 RabbitMQ可以对队列和消息设置TTL,当消息到达过期时间还没有被消费时就会自动删除 注:这里我们说的对队列设置TTL,是对队列上的消息设置TTL并不是对队列本身,不是说队列过期时间…...

第4章 Kafka核心API——Kafka客户端操作

Kafka客户端操作 一. 客户端操作1. AdminClient API 一. 客户端操作 1. AdminClient API...

Python爬虫学习前传 —— Python从安装到学会一站式服务

早上好啊,大佬们。我们的python基础内容的这一篇终于写好了,啪唧啪唧啪唧…… 说实话,这一篇确实写了很久,一方面是在忙其他几个专栏的内容,再加上生活学业上的事儿,确实精力有限,另一方面&…...

Lora理解QLoRA

Parameter-Efficient Fine-Tuning (PEFT) :节约开销的做法,fine-tune少量参数,而不是整个模型; Low-Rank Adaptation (LoRA) :是PEFT的一种;冻结原参数矩阵,只更新2个小参数矩阵。 原文经过对比…...

Linux测试处理fps为30、1920*1080、一分钟的视频性能

前置条件 模拟fps为30、1920*1080、一分钟的视频 项目CMakeLists.txt cmake_minimum_required(VERSION 3.30) project(testOpenGl)set(CMAKE_CXX_STANDARD 11)add_executable(testOpenGl main.cpptestOpenCl.cpptestOpenCl.hTestCpp.cppTestCpp.hTestCppThread.cppTestCppTh…...

Flink (六):DataStream API (三) 窗口

1. 窗口 窗口(Window)是处理无界流的关键所在。窗口可以将数据流装入大小有限的“桶”中,再对每个“桶”加以处理。 下面展示了 Flink 窗口在 keyed streams 和 non-keyed streams 上使用的基本结构。 我们可以看到,这两者唯一的…...

MYSQL学习笔记(二):基本的SELECT语句使用(基本、条件、聚合函数查询)

前言: 学习和使用数据库可以说是程序员必须具备能力,这里将更新关于MYSQL的使用讲解,大概应该会更新30篇,涵盖入门、进阶、高级(一些原理分析);这一篇是讲解SELECT语句使用,包括基本、条件、聚合函数查询,…...

PCL 点到面的ICP算法实现点云配准(C++详细过程版)

ICP算法 一、算法原理1、算法概述2、实现流程3、参考文献二、代码实现三、结果展示四、相关链接一、算法原理 1、算法概述 实现的算法与 PCL 点到面的ICP精配准(线性最小二乘优化)一文相同,使用C++代码复现线性优化的求解过程,求解过程如下所示,由于原版英文文献的计算过…...

MarsCode青训营打卡Day1(2025年1月14日)|稀土掘金-16.最大矩形面积问题

资源引用: 最大矩形面积问题 - MarsCode 打卡小记录: 今天是开营第一天,和小伙伴们组成了8人的团队,在接下来的数十天里相互监督,打卡刷题! 稀土掘金-16.最大矩形面积问题(16.最大矩形面积问题…...

我的世界-与门、或门、非门等基本门电路实现

一、红石比较器 (1) 红石比较器结构 红石比较器有前端单火把、后端双火把以及两个侧端 其中后端和侧端是输入信号,前端是输出信号 (2) 红石比较器的两种模式 比较模式 前端火把未点亮时处于比较模式 侧端>后端 → 0 当任一侧端强度大于后端强度时,输出…...

【FISCO BCOS】二十三、部署WeBASE-Node-Manager

WeBASE-Node-Manager是WeBASE的子组件之一,可以处理前端页面所有web请求,管理各个节点的状态,管理链上所有智能合约,对区块链的数据进行统计、分析,对异常交易的审计,私钥管理等,今天我们来部署WeBASE-Node-Manager。 环境:ubuntu 22 、已搭建单机四节点(节点已启动)…...

app版本控制java后端接口版本管理

java api version 版本控制 java接口版本管理 1 自定义 AppVersionHandleMapping 自定义AppVersionHandleMapping实现RequestMappingHandlerMapping里面的方法 public class AppVersionHandleMapping extends RequestMappingHandlerMapping {Overrideprotected RequestCondit…...

Go语言strings包与字符串操作:从基础到高级的全面解析

Go语言strings包与字符串操作:从基础到高级的全面解析 引言 Go语言以其简洁、高效和强大的标准库而闻名,其中strings包是处理字符串操作的核心工具。本文将深入探讨Go语言中strings包的功能及其在实际开发中的应用,帮助开发者更好地理解和使用这一工具。 1. strings包概述…...

使用redis-cli命令实现redis crud操作

项目场景: 线上环境上redis中的key影响数据展示,需要删除。但环境特殊没办法通过 redis客户端工具直连。只能使用redis-cli命令来实现。 操作步骤: 1、确定redis安装的服务器; 2、找到redis的安装目录下 ##找到redis安装目…...

Ubuntu升级Linux内核教程

本文作者CVE-柠檬i: CVE-柠檬i-CSDN博客 本文使用的方法是dpkg安装,目前版本为5.4.0-204,要升级成5.8.5版本 下载 下载网站:https://kernel.ubuntu.com/mainline/ 在该网站下载deb包,选择自己想要升级的版本,这里是5…...

5、docker-compose和docker-harbor

安装部署docker-compose 自动编排工具,可以根据dockerfile自动化的部署docker容器。是yaml文件格式,注意缩进。 1、安装docker-compose 2、配置compose配置文件docker-compose.yml 3、运行docker-compose.yml -f:指定文件,up&…...

Leetcode3097:或值至少为 K 的最短子数组 II

题目描述: 给你一个 非负 整数数组 nums 和一个整数 k 。 如果一个数组中所有元素的按位或运算 OR 的值 至少 为 k ,那么我们称这个数组是 特别的 。 请你返回 nums 中 最短特别非空 子数组的长度,如果特别子数组不存在,那么返…...

HTML应用指南:利用GET请求获取全国特斯拉充电桩位置

随着电动汽车的普及,充电基础设施的建设变得至关重要。作为电动汽车领域的先驱,特斯拉不仅在车辆技术创新上持续领先,还积极构建广泛的充电网络,以支持其不断增长的用户群体。为了提升用户体验和服务质量,开发人员和数…...

阿里云通义实验室自然语言处理方向负责人黄非:通义灵码2.0,迈入 Agentic AI

通义灵码是基于阿里巴巴通义大模型研发的AI 智能编码助手,在通义灵码 1.0 时代,我们针对代码的生成、补全和问答,通过高效果、低时延,研发出了国内最受欢迎的编码助手。 在通义灵码 2.0 发布会上,阿里云通义实验室自然…...

idea大量爆红问题解决

问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

7.4.分块查找

一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...

Python如何给视频添加音频和字幕

在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...

Kafka入门-生产者

生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...