【数据结构】栈(Stack)和队列(Queue)

news/2024/5/20 18:35:49

文章目录

    • 一、栈的概念及结构
    • 二、栈的特点
    • 三、栈的实现
      • 1.初始化栈
      • 2.判断栈空
      • 3.入栈
      • 4.出栈
      • 5.取栈顶元素
      • 6.栈的元素个数
      • 7.销毁
  • 队列
    • 一、队列的概念及结构
    • 二、队列的特点
    • 三、队列的实现
      • 1.初始化
      • 2.入队
      • 3.出队
      • 4.判断队空
      • 5.取队头元素
      • 6.取队尾元素
  • 总结

一、栈的概念及结构

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

在这里插入图片描述

栈顶:允许进行插入、删除操作的一端称为栈的栈顶(top),也称为表尾。
栈底:固定不动的一端,称为栈底(bottom),也称为表头。
进栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈/弹栈,出数据也在栈顶。

也分为顺序栈链栈(类比顺序表和链表)采用顺序存储的栈称为顺序栈,用一段物理地址连续的存储单元依次存储数据元素,通常以数组的形式实现;采用链式存储的栈称为链栈。

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些,因为数组尾插尾删的效率更高。

二、栈的特点

1.只能在栈顶进行插入和删除元素。
2.遵循后进先出原则,后入栈的元素先出栈,即最后插入的元素最先删除。
3.只能访问栈顶元素,不能从栈底或者中间访问元素。

三、栈的实现

栈的基本操作有:入栈(Push)、出栈(Pop)、取栈顶元素(Top)和判断栈是否为空(IsEmpty)等。

和顺序表一样,顺序栈采用动态存储的方式,根据需要来动态地申请空间。

队列的定义

#define INIT_SZ 10  //初始空间大小
#define INC_SZ 4	//每次扩容的空间大小
typedef int STDataType;//方便改存储的数据类型,下面以int示例
typedef struct Stack
{int* a;int top;//栈顶索引int capacity;//分配的空间容量
}ST;

1.初始化栈

//初始化
void STInit(ST* ps)
{assert(ps);//提高代码健壮性ps->a = (STDataType*)malloc(sizeof(STDataType) * INIT_SZ);if (NULL == ps->a){perror("malloc");return;}ps->capacity = INIT_SZ;//ps->top = -1;//top是栈顶元素的位置ps->top = 0;//top是栈顶元素的下一个位置
}

注意:栈顶下标top在初始化时,可以选择初始化为-1,表示栈顶元素的位置;也可以选择初始化为0,表示栈顶元素的下一个位置。top初始化的值会导致后面的基本操作写法有一点不同,随机选择一种即可。

2.判断栈空

判空条件与初始化时top的值有关。

//判断栈空
bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;//初始化的值
}

3.入栈

//入栈
void STPush(ST* ps, STDataType x)
{assert(ps);if (ps->top == ps->capacity)//栈内元素个数等于空间容量,需要进行扩容{STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * (INC_SZ + ps->capacity));if (NULL == tmp){perror("malloc");return;}ps->a = tmp;ps->capacity += INC_SZ;}//ps->a[++ps->top] = x;//ps->top初始化为-1时的写法ps->a[ps->top++] = x;
}

注意:栈顶下标top初始化为-1,表示栈顶元素的位置,每次入栈先++top,到下一个元素的位置,再插入;top如果初始化为0,表示栈顶元素的下一个位置,每次先插入,再++top。

4.出栈

//出栈
void STPop(ST* ps)
{assert(ps);assert(!STEmpty(ps));//栈非空才能出栈ps->top--;
}

注意:删除的空间不能free掉,因为动态开辟的空间不能局部释放。

5.取栈顶元素

//返回栈顶元素
STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));//要保证栈非空才能取栈顶元素//return ps->a[ps->top];//top初始化为-1时的写法return ps->a[ps->top - 1];
}

这里也会受到前面top初始化值的影响。

6.栈的元素个数

//栈的元素个数
int STSize(ST* ps)
{assert(ps);//return ps->top+1;//top初始化为-1时的写法return ps->top;
}

7.销毁

//销毁
void STDestroy(ST* ps)
{assert(ps);ps->a = NULL;free(ps->a);ps->top = 0 = ps->capacity = 0;
}

队列

一、队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)的特点。
在这里插入图片描述就像人们排队一样,讲究先来后到,先排队的人享受完服务,先离开。

队头:进行删除操作的一端。
队尾:进行插入操作的一端。
入队列:队列的插入操作,入数据在队尾。
出队列:队列的删除操作,出数据在队头。

队列也可以用数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列是数组头删,效率会比较低。

队列也分为非循环队列循环队列,可以用数组或链表实现。下面主要介绍用链表实现的普通的非循环队列。

二、队列的特点

1.只能在队头删除数据,只能在队尾插入数据。
2.遵循先进先出原则,先入队的元素先出队,即先插入的元素先删除。
3.只能访问队头和队尾元素,不能从中间访问元素。

三、队列的实现

队列的基本操作有:入队(Push)、出队(Pop)、判断队列空(IsEmpty)取队头元素(Front)、取队尾元素(Back)等。

队列的定义
队列的链式存储结构是一个带有队头指针和队尾指针的单链表。

typedef int QDataType;//数据类型
//结点
typedef struct QueueNode
{QDataType data;struct QueueNode* next;
}QNode;
//队列
typedef struct Queue
{QNode* head;//队头指针QNode* tail;//队尾指针
}Queue;

1.初始化

不带头结点的链式队列的初始化。

void QueueInit(Queue* pq)
{assert(pq);pq->head = pq->tail = NULL;
}

2.入队

在这里插入图片描述入队相当于链表的尾插,只不过链表没有尾指针,需要从头结点开始遍历到尾结点,而队列可以通过队尾指针直接访问尾结点,效率更高。

void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newNode = (QNode*)malloc(sizeof(QNode));//申请结点if (NULL == newNode){perror("malloc");return;}newNode->data = x;newNode->next = NULL;if (NULL == pq->head)//空队列,第一次入队{pq->head = pq->tail = newNode;}else{pq->tail->next = newNode;//队尾的下个结点指向新结点pq->tail = newNode;//更新队尾指针}
}

3.出队

在这里插入图片描述出队相当于链表的头删。

void QueuePop(Queue* pq)
{assert(pq);assert(pq->head);QNode* head = pq->head;//保存头结点,释放空间pq->head = head->next;//更新队头指针free(head);//释放头结点的空间head = NULL;//防止野指针
}

注意:删除时要释放结点空间,必须先保存头结点,否则更新队头指针后无法找到该结点从而导致无法释放这块空间。

4.判断队空

队列为空的条件与初始化有关。

bool QueueEmpty(Queue* pq)
{assert(pq);return pq->head == NULL;//或者return pq->tail == NULL;
}

5.取队头元素

QDataType QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));//队列非空是前提return pq->head->data;
}

6.取队尾元素

QDataType QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));//队列非空是前提return pq->tail->data;
}

总结

栈和队列都是一种特殊的线性表。

  • 栈的特点:后进先出,只能在表尾进行插入和删除。
  • 队列的特点:先进先出,只能在表头删除,在表尾插入。

  • 它们都可以用顺序存储和链式存储的方式。

    栈常用顺序存储结构即数组的方式,因为数组的尾插尾删效率高,但可能会存在频繁开辟内存空间和内存空间浪费的问题。而栈的链式存储结构,解决了空间浪费的问题,但每个节点都存放一个指针域,也会存在一定的内存开销,并且在每次申请和释放节点的过程中也存在一定的时间开销。

    队列常用链式存储结构即链表的方式,比链表多定义一个尾指针,解决尾插效率低的问题,并且不存在空间浪费。 而队列的顺序存储结构,由于插入需要挪动数据,效率低下,但循环队列可以解决这个问题,时间复杂度从O(N)变成了O(1),但仍存在内存空间浪费的问题。


http://www.mrgr.cn/p/26681701

相关文章

组件化开发根组件

目录 一、组件化开发介绍 二、根组件 一、组件化开发介绍 组件化:一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为。 好处:便于维护,利于复用,提升开发效率。 二、根组件 组件分类&#xff…

韩顺平0基础学Java——第4天

p45—p71 老天鹅,居然能中断这么久,唉...学不完了要 API API:application programing interface应用程序编程接口 www.matools.com 可以理解成Python的调包...c的头文件对吧 字符型 char用单引号 String用双引号 char本质上是个整数&#xff0c…

nginx--反向代理

反向代理 指的是代理外网用户的请求到内部的指定web服务器器,并将数据返回给用户的一种方式,这是用的比较多的一种方式 模块和功能 ngx_http_proxy_module: 将客户端的请求以http协议转发至指定服务器进行处理。ngx_stream_proxy_module&…

【大数据】学习笔记

文章目录 [toc]NAT配置IP配置SecureCRT配置PropertiesTerminal Java安装环境变量配置 Hadoop安装修改配置文件hadoop-env.shyarn-env.shslavescore-site.xmlhdfs-site.xmlmapred-site.xmlyarn-site.xml 环境变量配置 IP与主机名映射关系配置hostname配置映射关系配置 关闭防火墙…

interp2函数最临近nearest测试

code clear all; close all;clc; % 假设这是我们的原始数据,一个30x60的网格,表示经度和纬度 % 这里使用随机数创建一个示例矩阵,实际应用中应当使用真实的海拔高度数据 longitude linspace(0, 180, 30); latitude linspace(-90, 90, 60);…

【隧道篇 / WAN优化】(7.4) ❀ 03. WAN优化的原理 ❀ FortiGate 防火墙

【简介】相信对WAN优化感兴趣的人都会有疑问,WAN优化真的有作用吗?如果真的有作用,那是根据什么原理呢?让我们来更深入的了解一下。 客户端和服务器端 其实很多人在一开始看到WAN优化这个词,就自然的以为上网速度太慢&…

照片生成ai漫改头像生成漫画全套教程免费(自取)

今天给大家分享一一个AI漫改头像,轻松日增1000,简单操作好上手的一个互联网新项目,哈那其实AI漫改头像也火了差不多有半年左右了, 那其实利用AI软件将真人的照片生成漫画的形象,这个看起来很简单的方法却在小红书上大…

压缩归档库-Snappy介绍

1.简介 Snappy 是一个 C 编写的压缩和解压缩库,由 Google 开发。它专为速度而设计,而不是最大压缩率或与其他压缩库的兼容性。 Snappy 通常用于需要快速压缩和解压缩的场景。 Snappy具有以下属性: 快速:压缩速度达到250 MB/秒及…

安装oh-my-zsh(命令行工具)

目录一、安装zsh、git、wget二、安装运行脚本1、curl/wget下载2、手动下载三、切换主题1、编辑配置文件2、切换主题四、安装插件1、zsh-syntax-highlighting(高亮语法错误)2、zsh-autosuggestions(自动补全)五、更多优化配置 一、安装zsh、git、wget安装oh-my-zsh的前提需要…

CH592 蓝牙透传模块

设备架构串口透传协议说明 模块通过串口和用户MCU相连,建立用户MCU 和 BLE 设备之间的双向通讯。 用户可以通过串口,使用指定的AT指令对串口波特率、BLE连接间隔,以及不同的发包间隔,模块将会有不同的数据吞吐能力。 串口默认配置为 115200bps。 模块的串口Rx一次最大可输入…

TSINGSEE青犀视频边缘计算AI智能分析网关V4告警消息语音推送的配置流程

TSINGSEE青犀视频边缘计算硬件智能分析网关V4内置了近40种AI算法模型,支持对接入的视频图像进行人、车、物、行为等实时检测分析,上报识别结果,并能进行语音告警播放。今天我们来分享一下如何配置和使用AI智能分析网关V4的语音推送。 提前准备…

【UE5学习笔记】编辑及运行界面:关闭眼部识别(自动曝光)

自动曝光,也就是走进一个黑暗的环境,画面会逐渐变量,以模拟人眼进入黑暗空间时瞳孔放大,进光量增加的一种真实视觉感受: 制作过程中是否关闭自动曝光,取决于游戏的性质,但是个人认为&#xff0c…

项目冲刺——第三篇Scrum冲刺博客

作业所属课程 所属课程作业要求 作业要求作业目标 总结第二天的敏捷开发,安排好第三天敏捷开发冲刺一、站立式会议 1、会议图片2、昨天已完成的内容成员 任务肖杨、梁丽贤 完成注册登陆页面设计黄诃华、欧文杰 完成用户注册登陆功能姚佳如、李慧娣 完成发布帖子模块的设计廖莹…

93、动态规划-最长回文子串

思路 首先从暴力递归开始,回文首尾指针相向运动肯定想等。就是回文,代码如下: public String longestPalindrome(String s) {if (s null || s.length() 0) {return "";}return longestPalindromeHelper(s, 0, s.length() - 1);…

大模型微调实战之强化学习 贝尔曼方程及价值函数(五)

大模型微调实战之强化学习 贝尔曼方程及价值函数(五) 现在, 看一下状态-动作值函数的示意图: 这个图表示假设首先采取一些行动(a)。因此,由于动作(a),代理可能会被环境转换到这些状…

团队作业4——项目冲刺 第3篇 Scrum 冲刺博客

这个作业属于哪个课程 软件工程这个作业要求在哪里 团队作业4——项目冲刺这个作业的目标 团队完成任务的分配,明确团队每个人在接下来七天敏捷冲刺的目标其他参考文献这个作业所属团队 SuperNewCode团队成员 张楠 曾琳备 黄铭涛 张小宇 周广1.每日举行站立时会议2.燃尽图3.每…

牛客NC97 字符串出现次数的TopK问题【中等 哈希+优先级队列 Java/Go】

题目 题目链接: https://www.nowcoder.com/practice/fd711bdfa0e840b381d7e1b82183b3ee 核心 哈希,优先级队列Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返…

计算机组成原理网课笔记

无符号整数的表示与运算 带符号整数的表示与运算 原反补码的特性对比 移码 定点小数

linux增加环境变量示例

首先,通过 vim ~/.bashrc 命令进入我这个用户的.bashrc文件内 然后在这个文件末尾添加环境变量,比如下面红框中的内容表示添加了路径/home/nfs_new/wangpeng/VSCode-linux-x64/bin为环境变量,实际上这里是把vscode启动命令添加作为环境变量了。其中, $PATH 表示之前所有的…