奶奶都看的懂的《栈》(C语言实现,超详细解析 !!!)

news2024/11/26 16:26:40

目录

一、前言

二、栈

 🍎栈的概念

🍐栈的结构​编辑

🍉栈的实现

🍊栈 各个接口的实现

⭕ 定义一个  栈  结构体

⭕栈 的初始化

 ⭕ 栈 的尾插

⭕ 栈 的尾删

⭕ 栈 内数据个数

⭕ 获取 栈 顶元素

 ⭕ 判断 栈  是否为空

 ⭕ 栈 数据的打印

 三、栈 完整代码

🍇 Stack.h

🍋 Stack.c

🥝 Test.c

🍍代码运行界面

四、共勉


一、前言

       在之前的几篇文章中已经详细讲解了线性表中的 顺序表、单链表。每一种不同的数据结构都有它独特的结构和应用之处,今天将再次给大家介绍一个新的线性表:

       在数据结构中又代表了什么呢?这里我将给大家依次解惑,让大家真正的搞懂数据结构,学起来才更有动力!

二、栈

 🍎栈的概念

1️⃣:一种特殊的线性表,其中只允许在固定的一端进行插入和删除元素的操作

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

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

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

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

🍐栈的结构

🍉栈的实现

💦 针对栈的实现,我们可以使用之前学习过的 链表 、顺序表都可以实现栈,但是我们需要考虑的是,之前学习的哪一种结构可以更高效的实现栈呢?

1️⃣ 链表:空间的利用率高,不用扩容,头插头删高效

2️⃣ 顺序表:空间利用率低,需要扩容,但是尾插尾删效率高


针对 栈的结构 我们不难看出 栈不管是插入数据,还是删除数据都是从栈顶进行操作(进行尾插,和尾删)。

🔑 尾插和尾删 在目前来看,顺序表的效率是最高的,所以我们选择使用顺序表来进行 栈的实现。

🍊栈 各个接口的实现

这里先建立三个文件夹:

1️⃣:Stack.h 文件,用于函数声明
2️⃣:Stack.c 文件,用于函数的定义

3️⃣:Test.c   文件,用于测试函数

建立三个文件的目的: 将 栈 作为以一个项目来进行书写,方便我们的学习和观察。

定义一个    结构体

🔑 栈的结构体由三个部分组成:

▶ : 第一部分 动态数组 用来存储数据

▶ : 第二部分 小标值 用来确定栈顶元素位置

▶ : 第三部分  容量值 用来确定栈的元素个数

typedef int STDataType;   // 定义数据类型
typedef struct Stack
{
	STDataType* a;   // 定义一个动态数组
	STDataType top;  // 用来确定栈顶位置(指向栈顶元素的下一个位置)
	STDataType capacity;  // 栈的容量
}ST;               // ST 为结构体的缩写名

⭕栈 的初始化

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

// 初始化栈
void STInit(ST* ps)
{
	assert(ps); // 这里一定要断言,如果是空指针的话,就无法找到整个数组 

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

 ⭕ 栈 的尾插

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


 

// 栈的尾插
void STPush(ST* 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 STPop(ST* ps)
{
	assert(ps);
	// 只需要删除栈顶的数据即可

	// 需要判断栈内是否还有数据
	assert(ps->top > 0);
	ps->top--;

}

⭕ 栈 内数据个数

🔑 统计 栈 内个数即可

// 栈内数据的个数
int STSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

⭕ 获取 栈 顶元素

🔑 返回栈顶元素即可

// 获取栈顶元素
STDataType STTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	return ps->a[ps->top - 1];
}

 ⭕ 判断 栈  是否为空

🔑 栈为空(栈顶的top是否等于0)

// 判断栈是否为空
bool STEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

 ⭕ 栈 的销毁

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

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

 ⭕ 栈 数据的打印

// 打印栈
void STPrint(ST* ps)
{
	assert(ps);

	while (!STEmpty(ps))
	{
		// 打印栈顶
		printf("%d ", STTop(ps));
		// 一边出数据一边删数据(满足后进先出)
		STPop(ps);
	}
	printf("\n");
}

 三、栈 完整代码

🍇 Stack.h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <math.h>

// 静态的栈
//#define N 10
//struct Stack
//{
//	int a[N];    定义了一个指定好大小的数组
//	int size;
//};


// 动态栈
// 栈可以选择链表也可以选择数组,为什么要选择动态数组呢
// 因为数组的尾插和尾删效率比较高,而栈刚刚好,是先进后出,并且只能从一端进,一端出(栈顶)

typedef int STDataType;   // 定义数据类型
typedef struct Stack
{
	STDataType* a;   // 定义一个动态数组
	STDataType top;  // 用来确定栈顶位置(指向栈顶元素的下一个位置)
	STDataType capacity;  // 栈的容量
}ST;               // ST 为结构体的缩写名

// 初始化栈
void STInit(ST* ps);
// 栈的销毁
void STDestory(ST* ps);

// 栈只能从栈顶入栈,只能从栈顶出栈


// 栈的尾插
void STPush(ST* ps, STDataType x);
// 栈的删除
void STPop(ST* ps);
// 栈的个数
int STSize(ST* ps);
// 判断栈是否为空
bool STEmpty(ST* ps);
// 打印栈
void STPrint(ST* ps);
// 获取栈顶元素
STDataType STTop(ST* ps);

🍋 Stack.c

#include "Stack.h"
#include <stdio.h>

// 初始化栈
void STInit(ST* ps)
{
	assert(ps); // 这里一定要断言,如果是空指针的话,就无法找到整个数组 

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

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

// 栈的尾插
void STPush(ST* 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 STPop(ST* ps)
{
	assert(ps);
	// 只需要删除栈顶的数据即可

	// 需要判断栈内是否还有数据
	assert(ps->top > 0);
	ps->top--;

}

// 栈内数据的个数
int STSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

// 判断栈是否为空
bool STEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

// 打印栈
void STPrint(ST* ps)
{
	assert(ps);

	while (!STEmpty(ps))
	{
		// 打印栈顶
		printf("%d ", STTop(ps));
		// 一边出数据一边删数据(满足后进先出)
		STPop(ps);
	}
	printf("\n");
}

// 获取栈顶元素
STDataType STTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	return ps->a[ps->top - 1];
}

🥝 Test.c

// 栈 :
// 有数组栈(尾插尾删效率高) 和 链式栈
// 用数组实现栈更优一点


#include "Stack.h"
#include <stdio.h>


// 尾插测试
void Test1()
{
	// 定义一个结构体变量
	// 要改变这个结构体变量,就要在形参上 传递 结构体变量的地址
	ST ps;
	// 进行初始化
	STInit(&ps);
	// 将结构体变量的地址给给尾插函数
	printf("********************测试队列*****************\n");
	printf("\n");
	printf("********************进行尾插*****************\n");
	printf("\n");
	printf("********************尾插1 2 3 4 5\n");
	printf("\n");
	STPush(&ps, 1);
	STPush(&ps, 2);
	STPush(&ps, 3);
	STPush(&ps, 4);
	STPush(&ps, 5);
	printf("****输出(满足后进先出原则)\n");
	printf("\n");
	STPrint(&ps);
	

	// 销毁(防止内存泄露)
	STDestory(&ps);
}


// 尾删测试
void Test2()
{
	// 定义一个结构体变量
	ST ps;
	// 进行初始化
	STInit(&ps);
	// 将结构体变量的地址给给尾插函数
	STPush(&ps, 1);
	STPush(&ps, 1);
	STPush(&ps, 1);

	STPop(&ps);
	STPrint(&ps);

	// 销毁(防止内存泄露)
	STDestory(&ps);
}



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

🍍代码运行界面

四、共勉

 以下就是我对数据结构-----的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对数据结构-----队列的理解,请持续关注我哦!!!

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

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

相关文章

Linux-网卡和网络配置

链接一篇大佬的博客&#xff1a;Linux之手把手教会修改网卡名称 文章目录 修改网卡名称步骤1&#xff1a;修改“/etc/default/grub”步骤2&#xff1a;修改“/etc/sysconfig/network-scripts”下的文件步骤3&#xff1a;修改“ifcfg-eth0”配置步骤4&#xff1a;判断操作系统的…

AIGC入门 - LLM 信息概览

本文将介绍以下 LLM OPTLLaMaAlpacaVicunaMosschatGLMBaichuanOpenbuddy 一、OPT 1、背景 OPT全称Open Pre-trained Transformer Language Models&#xff0c;即“开放的预训练Transformer语言模型”&#xff0c;是 Meta AI 团队在2022年5月发布了开源大模型OPT-175B&#…

Ninja: Towards Transparent Tracing and Debugging on ARM【TEE的应用】

目录 摘要引言贡献 背景TrustZone和受信任的固件PMU和ETM 相关工作x86上的透明恶意软件分析ARM上的动态分析工具基于仿真的系统硬件虚拟化裸机系统 Trustzone相关的系统 系统架构具体实现和评估可以看论文&#xff0c;这里不赘述了讨论总结 作者&#xff1a;Zhenyu Ning and Fe…

ffmpeg编译 Error: operand type mismatch for `shr‘

错误如下&#xff1a; D:\msys2\tmp\ccUxvBjQ.s: Assembler messages: D:\msys2\tmp\ccUxvBjQ.s:345: Error: operand type mismatch for shr D:\msys2\tmp\ccUxvBjQ.s:410: Error: operand type mismatch for shr D:\msys2\tmp\ccUxvBjQ.s:470: Error: operand type mismatch…

BCrypt 密码数据加解密运用

前言&#xff1a; 当涉及到存储用户密码时&#xff0c;确保密码的安全非常重要。以往&#xff0c;我们通常都是采用 MD5 这种不可逆算法来进行密码数据的加密后存储&#xff0c;虽然MD5算法是一种常见的哈希函数&#xff0c;但是它已经不再被认为是安全的选项。 常规MD5加密&a…

趣解设计模式之《小王的学习秘籍》

〇、小故事 小王是学校的学霸&#xff0c;凭借着自己的天赋以及对于学习的刻苦&#xff0c;每次考试都能排到年级第一名。但是&#xff0c;他所在的班级总成绩却不高&#xff0c;在所有班级中&#xff0c;属于中游水平。老师希望通过小王的贡献&#xff0c;能否帮助整个班级同…

证券账户可以绑定几张银行卡,可以更换绑定吗

个人账户实现股票量化程序化自动交易&#xff0c;券商有接口&#xff0c;门槛已降低_股票程序交易接口的博客-CSDN博客像上面的例子&#xff0c;如果按照市面上常见的可转债万3或万2不免5&#xff0c;人工操作费率限制&#xff0c;这种情况就不要想&#xff0c;根本没机会&…

返回最大元素的索引 忽略数组中所有的NaN值 numpy.nanargmax()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 返回最大元素的索引 忽略数组中所有的NaN值 numpy.nanargmax() [太阳]选择题 请问代码中第一次执行语句的输出正确的是&#xff1f; import numpy as np a np.array([0,np.nan,2]) print(&…

H264视频压缩格式

H264简介 H.264从1999年开始&#xff0c;到2003年形成草案&#xff0c;最后在2007年定稿有待核实。在ITU的标准里称为H.264, 在MPEG的标准里是MPEG-4的一个组成部分-MPEG-4 Part 10&#xff0c;又叫Advanced Video Codec&#xff0c;因此常常称为MPEG-4AVC或直接叫AVC。 压缩算…

服务器搭建(TCP套接字)-fork版(服务端)

基础版的服务端虽然基本实现了服务器的基本功能&#xff0c;但是如果客户端的并发量比较大的话&#xff0c;服务端的压力和性能就会大打折扣,为了提升服务端的并发性能&#xff0c;可以通过fork子进程的方式&#xff0c;为每一个连接成功的客户端fork一个子进程&#xff0c;这样…

Ansible自动化:简化你的运维任务

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

OpenStack创建云主机并连接CRT

文章目录 OpenStackT版创建云主机并连接CRT命令行操作&#xff08;1&#xff09;创建镜像&#xff08;2&#xff09;创建实例&#xff08;3&#xff09;创建网络创建内网创建外网 &#xff08;4&#xff09;创建安全组&#xff08;5&#xff09;创建路由&#xff08;6&#xff…

如何利用CSS实现三角形、扇形、聊天气泡框

思路 三角形 实现三角形的关键思路是使用 CSS 的 border 属性来创建一个透明的矩形块&#xff0c;并利用边框的透明部分来形成三角形。下面是创建三角形的一般思路&#xff1a; 创建一个 HTML 元素&#xff0c;通常是一个 <div> 元素&#xff0c;用于容纳三角形。 为该…

超低功耗段码LCD液晶显示驱动IC-VKL144A/BQFN48超小体积液晶驱动

产品品牌&#xff1a;永嘉微电/VINKA 封装形式&#xff1a;TSSOP48/QFN48L 产品年份&#xff1a;新年份 沈先生 135 、547/44,703 原厂&#xff0c;工程服务&#xff0c;技术支持&#xff01; VKL144A/B 概述: VKL144A/B 是一个点阵式存储映射的LCD 驱动器&#xff0c;可…

数据库操作-DML/DQL

数据库操作-DML DML英文全称是Data Manipulation Language(数据操作语言)&#xff0c;用来对数据库中表的数据记录进行增、删、改操作。 添加数据&#xff08;INSERT&#xff09; 修改数据&#xff08;UPDATE&#xff09; 删除数据&#xff08;DELETE&#xff09; 增加(ins…

面试题四:请解释一下watch,computed和filter之间的区别

watch与computed、filter&#xff1a; watch:监控已有属性&#xff0c;一旦属性发生了改变就去自动调用对应的方法 computed:监控已有的属性,一旦属性的依赖发生了改变&#xff0c;就去自动调用对应的方法.computed有详细的介绍&#xff0c;移步computed的使用 filter:js中为…

2023 Google 开发者大会 – 惊喜来袭

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; 2023 Google 开发者大会 – 惊喜来袭 2023 Google 开发者大会面向开发者和科技爱好者展示最新产品和平台的年度盛会。今年Google大会为大家提供了丰富的学习资源&…

transforms数据预处理【图像增强】 ->(个人学习记录笔记)

文章目录 1. 安装2. transforms——Crop 裁剪2.1 transforms.CenterCrop2.2 transforms.RandomCrop2.3 transforms.RandomResizedCrop2.4 transforms.FiveCrop2.5 transforms.TenCrop 3. transforms——Flip 翻转3.1 transforms.RandomHorizontalFlip3.2 transforms.RandomVert…

Bash脚本学习:AWK, SED

1. AWK AWK 是一种编程语言&#xff0c;设计用于处理文件或数据流中基于文本的数据&#xff0c;或者使用 shell 管道。 可以将 awk 与 shell 脚本结合使用或直接在 shell 提示符下使用。 以上展示使用AWK分别打印第一个位置变量和第二个位置变量。 建立一个文档 csvtest.cs…

【前端知识】Three 学习日志(二)—— 加强三维空间认识

Three 学习日志&#xff08;二&#xff09;—— 加强三维空间认识 一、设置辅助观察坐标系 // 创建3D场景对象Scene const scene new THREE.Scene(); // AxesHelper&#xff1a;辅助观察的坐标系 const axesHelper new THREE.AxesHelper(150); scene.add(axesHelper);二、设…