数据结构 - 栈

目录

一. 栈的概念

二. 栈的结构

三. 栈的实现

1. 实现栈的两种方式

链表实现栈

顺序表实现栈

选择依据

栈的创建

栈的初始化 

栈的销毁

入栈

出栈

获取栈顶元素

判断栈是否为空

获取栈中有效数据的个数


一. 栈的概念

栈(Stack)是一种重要的抽象数据类型(ADT),也是一种特殊的顺序表,用于存储有序的元素集合。它的最大特点是后进先出(Last In First Out, LIFO)。这意味着在这个数据结构中,最后添加的元素将是第一个被移除的。

栈的原型:其中进行数据插入的和删除操作的一端称为栈顶,另一端称为栈底。

栈的原则:栈中的数据元素遵守 后进先出(LIFO)的原则   

栈的两个典型操作:
压栈栈的插入操作叫做 进栈 / 压栈  / 入栈  (入数据在栈顶)

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

二. 栈的结构

三. 栈的实现

1. 实现栈的两种方式

针对栈的实现,我们可以使用之前学习过的链表顺序表都可以实现栈,但是我们需要考虑的什到底要用哪种方式实现栈呢?

链表实现栈

优点

  1. 动态大小:链表基于指针链接,因此可以根据需要动态增长和缩小,不需要事先定义容量。
  2. 内存利用:链表不需要连续的内存空间,因此在内存分配上比较灵活,适合元素数量不确定的情况。

缺点

  1. 内存开销:每个元素都需要额外的空间来存储指针,这增加了内存消耗。
  2. 性能问题:相较于顺序表,链表在内存中可能不连续,可能会影响缓存的利用效率,从而影响性能。

顺序表实现栈

优点:

  1. 快速访问:顺序表基于数组实现,可以实现快速的随机访问。
  2. 内存效率:不像链表,顺序表不需要额外的空间来存储指针,内存使用更加高效。
  3. 缓存友好:由于数据连续存储,顺序表更好地利用了CPU缓存机制,提高了访问效率。

缺点

  1. 固定大小:传统的数组大小是固定的,需要提前分配内存,虽然可以通过动态数组(如 C++ 的 std::vector 或 Java 的 ArrayList)来解决这个问题,但这可能导致复杂的扩容操作和潜在的性能损耗。
  2. 可能的扩容成本:当数组达到容量极限时,需要进行扩容,这涉及到分配新的更大的内存块,并复制旧数据到新位置,这个过程可能相对耗时。

选择依据

  • 性能需求:如果需要最大化性能,特别是访问速度,顺序表(数组)通常是更好的选择。对于频繁的插入和删除操作,链表可能更优。
  • 内存考量:如果内存使用更为关键,或者元素大小变化不可预测,链表提供了更灵活的内存管理。
  • 实现复杂性:数组的实现通常更简单直接。链表虽然提供更大的灵活性,但需要额外的指针操作和错误处理。

总的来说,没有绝对的“更好”,只有更适合特定需求的实现。例如,如果你预期栈会频繁变化大小,且不太关心随机访问性能,链表可能是一个好的选择。相反,如果你需要高性能和最优的空间利用,且栈的大小相对稳定,使用数组实现的顺序表可能更合适。

栈的创建

需要用结构体创建一个栈,这个结构体需要包括栈的基本内容(栈,栈顶,栈的容量)。

typedef int STDataType;
typedef struct Stack
{
    STDataType* a;       // 指向动态数组的指针,用于存储栈中的元素
    int top;             // 栈顶的索引,指向栈顶元素
    int capacity;        // 栈的容量,表示栈数组可以容纳的最大元素数量
} Stack;

栈的初始化 

主要是给 栈 一个地址空间,将栈中的数据数据全部清空,与便于后续的操作方便。

void StackInit(Stack* ps)
{
    assert(ps);
	ps->a = NULL;
    ps->capacity = 0;
    // 这里需要注意的是当 top=0 时指向的是栈顶元素的下一个位置
    //                   top=-1 时指向的是栈顶元素
    // 这里也可以理解为顺序表中 size 有效数据的意思
    ps->top = 0;
}

栈的销毁

栈的销毁,需要将动态数组的头指针 free 掉,结构体其他元素置0.

void StackDestroy(Stack* ps)
{
    assert(ps);  // 确保传入的栈指针不为空,防止未定义行为
    free(ps->a);  // 释放栈使用的动态数组内存
    ps->a = NULL;  // 将指向动态数组的指针设为NULL,避免悬挂指针(dangling pointer)
    ps->top = 0;  // 将栈顶索引重置为0
    ps->capacity = 0;  // 将栈的容量设置为0

    // 注意:此处没有释放栈结构本身的内存,仅释放了其内部的动态数组
}

入栈

需要判断 栈的容量是否已满,满了就取扩容,没满,则向栈顶插入数据即可

void STPush(Stack* ps, STDataType x)
{
	// 此时需要保证传入的栈,不是空
	assert(ps);

	// 扩容
	// 判断是否需要扩容
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* temp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
		// 防止返回的是空指针
		if (temp == NULL)
		{
			perror("realloc fail!");
			exit(-1);
		}
		ps->a = temp;
		ps->capacity = newcapacity;
	}
	// 进行尾插数据
	ps->a[ps->top] = x;
	ps->top++;
}

出栈

只需要将栈顶的数据移除即可。

注意:一定要保证栈顶有数据

void StackPop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));//检测栈是否为空

	ps->top--;//栈顶下移
}

获取栈顶元素

获取栈顶元素,即获取栈的最上方的元素。若栈为空,则不能获取。

STDataType StackTop(Stack* ps)
{
    assert(ps);                     // 确保传入的栈指针非空
    assert(!StackEmpty(ps));        // 确保栈不为空,防止访问空栈

    return ps->a[ps->top - 1];     // 返回栈顶元素
    //ps->a[ps->top - 1]:这部分代码访问栈中的数组 a,并获取栈顶元素。
    //这里使用 ps->top - 1 是因为 top 通常表示下一个可插入元素的位置,
    //所以栈顶的实际元素位于 top - 1 的位置。
}

判断栈是否为空

判断栈是否为空的函数通常检查栈顶指针top的值。如果top为0,则表示栈中没有元素,即栈为空

bool StackEmpty(Stack* ps)
{
    assert(ps);      // 断言检查,确保传入的栈指针非空
    return ps->top == 0; // 返回栈是否为空的判断结果
}

获取栈中有效数据的个数

因为top记录的是栈顶,使用top的值便代表栈中有效元素的个数。

int StackSize(Stack* ps)
{
	assert(ps);

	return ps->top;//top的值便是栈中有效元素的个数
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VScode Failed to parse remote port from server output

在使用VScode 在连接AutoDL 过程中一直连接不上,显示 Failed to parse remote port from server output 在网上查了很多资料,貌似的没啥用。和我有相同 error 的可以尝试修改setting.json 文件。 添加这条命令(我的json文件里面没有&#…

共享购:融合社交分享与消费返利的创新电商模式

共享购电商模式是一种独特的商业模式,巧妙地将社交分享与消费返利结合,让消费者在购物的同时,也能通过平台资产奖励实现价值的双重增长。该平台资产体系主要由共享值和共享积分两大要素构成,共同构建了一个充满活力的电商生态系统…

区块链技术与应用学习笔记(8-9节)——北大肖臻课程

目录 8.挖矿 对于全节点和轻节点思考问题? ①全节点在比特币的主要作用? ②挖矿时当监听到别人已经挖出区块并且延申了最长合法链此时应该立刻放弃当前区块在 本地重新组装一个指向最后这个新合法区块的候选区块,重新开始挖矿。节点这么做…

vivado 使用“链路 (Links)”窗口查看和更改链路设置

使用“链路 (Links) ”窗口查看和更改链路设置 创建链路后 , 就会将其添加到“ Links ”视图 ( 请参阅下图 ) 中 , 该视图是更改链路设置和查看状态的主要方法 , 也是最佳方法。 “ Links ”窗口中的每一行都对应 1 …

pymilvus创建多向量

pymilvus创建多向量 从 Milvus 2.4 开始,引入了多向量支持和混合搜索框架,单个collection可以支持10个向量字段。不同的向量字段可以表示不同的方面、不同的embedding模型甚至表征同一实体的不同数据模态。该功能在综合搜索场景中特别有用,例…

python学习笔记----python基础语法(二)

一、字面量 在 Python 中,字面量 是一种直接在代码中表示其自身值的数据。字面量用于创建值,并且可以直接被 Python 的解释器识别和处理。不同类型的数据有不同的字面量形式。下面是一些常见的字面量类型: 二、注释 注释:在程序…

[Android14] SystemUI的启动

1. 什么是System UI SystemUI是Android系统级应用,负责反馈系统及应用状态并与用户保持大量的交互。业务主要涉及的组成部分包括状态栏(Status Bar),通知栏(Notification Panel),锁屏(Keyguard),控制中心(Quick Setting)&#xff…

Babylon.js和Three.js的区别

Babylon.js和Three.js都是基于WebGL的3D图形库,它们使得开发者能够在网页上创建和展示3D内容。尽管它们的目标相似,但在设计理念、功能集、性能和社区支持等方面存在一些差异。北京木奇移动技术有限公司,专业的软件外包开发公司,欢…

SpringCloud引入SpringBoot Admin

Spring Boot Admin可以监控和管理Spring Boot&#xff0c;能够将 Actuator 中的信息进行界面化的展示&#xff0c;也可以监控所有 Spring Boot 应用的健康状况&#xff0c;提供警报功能。 1. 创建SpringBoot工程 2. 引入相关依赖 <dependency><groupId>com.alib…

MinIO分布式文件系统介绍

1、不同存储方式的对比&#xff1a; 2、 分布式文件系统对比 3、MinIO的特点 MinIO特点 数据保护&#xff1a;Minio使用Minio Erasure Code&#xff08;纠删码&#xff09;来防止硬件故障。即便损坏一半以上的driver&#xff0c;但是仍然可以从中恢复。 高性能&#xff1a;作…

PID算法学习

PID算法介绍 在过程控制中&#xff0c;按偏差的比例&#xff08;P&#xff09;、积分&#xff08;I&#xff09;和微分&#xff08;D&#xff09;进行控制的PID控制器&#xff08;亦称PID调节器&#xff09;是应用最为广泛的一种自动控制器。它具有原理简单&#xff0c;易于实…

冯唐成事心法笔记 —— 知世

系列文章目录 冯唐成事心法笔记 —— 知己 冯唐成事心法笔记 —— 知人 冯唐成事心法笔记 —— 知世 冯唐成事心法笔记 —— 知智慧 文章目录 系列文章目录PART 3 知世 成事者的自我修养怎样做一个讨人喜欢的人第一&#xff0c;诚心第二&#xff0c;虚心 如何正确看待别人的评…

MQTTX工具获取及使用

工具获取地址&#xff1a;百度网盘 请输入提取码 新建连接 订阅主题

Redis分布式锁手动实现

Redis分布式锁手动实现 java中锁机制 在 Java 中&#xff0c;锁是用来同步并发访问共享资源的机制。它确保了在一个时间点&#xff0c;只有一个线程可以执行某个代码块或方法&#xff0c;从而防止了数据的不一致和竞态条件。Java 提供了多种锁机制&#xff0c;包括内置锁&…

全国各地级市财政收入支出明细统计数据2003-2022年

01、数据简介 全国各地级市财政统计主要是按地级市财政支出和财政收入两项统计&#xff0c;反映地区财政资金形成、分配以及使用情况的统计&#xff0c;​是由地区各地级市统计局统计公布&#xff0c;是加强财政资金管理使用的依据&#xff0c;研究国民收入分配和再分配的重要…

山东省2024年首版次测试报告具体的要求是什么?

山东省首版次测试报告的具体要求可能会根据每年的政策调整、行业变化以及申报的具体产品而有所不同。但一般而言&#xff0c;山东省首版次测试报告需要满足以下一些基本要求和标准&#xff1a; 1.完整性&#xff1a;测试报告应涵盖所有关键的测试环节&#xff0c;包括但不限于测…

张小泉签约实在智能,用实在Agent打造自动化高

在不少老杭州人的童年记忆里&#xff0c;妈妈裁剪衣服、料理食材、修剪各种物品&#xff0c;用的都是张小泉刀剪。 近日&#xff0c;实在智能与“刀剪第一股”张小泉&#xff08;股票代码&#xff1a;301055.SZ&#xff09;正式达成合作&#xff0c;实在Agent数字员工助力张小…

AM解调 FPGA(寻找复刻电赛电赛D题的)

设计平台 Quartus II10.3mif产生工具modelsimSE &#xff08;仿真用&#xff09; DDS&#xff08;直接数字式频率合成器&#xff09; 从前面的内容可知&#xff0c;我们需要产生一个载波&#xff0c;并且在仿真时&#xff0c;我们还需要一个较低频率的正弦波信号来充当我们的…

划重点:用这个技巧,抖音粉丝涨不停!

在这个信息爆炸的时代&#xff0c;如何在抖音上脱颖而出&#xff0c;吸引大量粉丝&#xff0c;成为了每一个创作者心中的痛。你是否曾经在发布作品后焦急等待评论&#xff0c;期待着每一次互动&#xff1f;如果你有这样的困扰&#xff0c;那么这篇文章将为你打开一扇新的大门&a…

【Claude 3 Opus】Claude 3 Opus 模型正式上线抢先体验

文章目录 1. Claude 3 Opus介绍2. Claude 3 Opus 支持的应用场景3. 申请Claude 3 Opus访问4. Claude 3 Opus初体验5. 『云上探索实验室』Bedrock 体验又更新啦6. 参考链接 1. Claude 3 Opus介绍 近期&#xff0c;亚马逊云宣布 Anthropic 的 Claude 3 Opus 模型已在 Amazon Bed…
最新文章