【C语言 | 数据结构】栈

news2024/10/4 14:27:13

文章目录

    • 前言
    • 1、栈
      • 1.1栈的概念和定义
        • 1.1.2栈的基本概念:
      • 1.2栈的方法(接口)
      • 1.3栈的实现方法
      • 1.4栈的性质
      • 1.5栈的应用
        • 1.6栈的结构
    • 2、栈的实现
        • 2.1 顺序栈
            • 2.1.1 顺序栈的结构体
            • 2.1.2 顺序栈的初始化
            • 2.1.3 顺序栈的销毁
            • 2.1.4 顺序栈的入栈
            • 2.1.5 顺序栈的出栈
            • 2.1.5 顺序栈的判空
            • 2.1.5 顺序栈的栈顶元素
            • 2.1.5 顺序栈的有效个数
    • 2、顺序栈的完整代码实现

前言

前面讲解了数据结构中的链表、顺序表,接下来就是栈了

1、栈

1.1栈的概念和定义

是一种限定仅在表尾进行插入或删除操作的线性表。这一端被称为栈顶(top),相对地,另一端被称为栈底(bottom)。栈顶是允许操作的,而栈底是固定的。栈的插入操作通常称为进栈/压栈/入栈(PUSH),而删除操作则称为退栈/出栈(POP)。

1.1.2栈的基本概念:

栈顶(top)和栈底(bottom):

  • 栈顶:栈顶是栈中最后一个被插入或删除的元素的位置。当新的元素被添加到栈中时,它被放置在栈顶;同样,当元素从栈中被删除时,也是从栈顶开始删除的。
  • 栈底:它表示栈的起始位置或者说是最早被插入的元素所在的位置,栈底是固定的。

1.2栈的方法(接口)

  • Push(入栈/压栈):在栈顶位置压入一个新数据。
  • Pop(出栈):从栈顶位置删除一个数据。
  • Top:获取栈顶数据
  • Size:获取栈的有效数据个数
  • Empty:判断栈是否为空

1.3栈的实现方法

栈(Stack)的实现方法主要有两种:基于数组的实现和基于链表的实现。数组实现栈比较简单,需要使用realloc来扩容,使用链表来实现就不需要扩容了,可以按需申请空间,插入和删除操作的时间复杂度都为O(1)

1.4栈的性质

  1. 后进先出(LIFO):栈遵循后进先出(Last In First Out)的原则,即最后进入栈的元素将最先被移出栈。这是栈最显著的特点。
  2. 集合性:栈是由若干个元素集合而成,当没有元素的空集合称为空栈。
  3. 线性结构:栈在逻辑上呈现一种线性结构,使用数组的话在物理逻辑上是连续的,但不同于普通的线性表,栈的插入和删除操作仅在一端(栈顶)进行。
  4. 数学性质:当多个编号元素依某种顺序压入,且可任意时刻弹出时,所获得的编号元素排列的数目,恰好满足卡塔兰数列的计算,即Cn = C(2n, n) / (n+1),其中n为编号元素的个数,Cn是可能的排列数目。
  5. 栈的大小限制:栈的大小通常是有限的,当栈满时,不能再进行进栈操作,否则会引发溢出错误;当栈空时,不能再进行出栈操作,否则会引发下溢错误。

1.5栈的应用

  • 函数调用:当一个函数调用另一个函数时,操作系统会给每个线程分配一块内存空间,这块内存被组织成栈结构。每个函数调用都需要将当前状态的信息(如函数调用前的参数、局部变量和程序计数器等)保存到栈中,等到函数调用结束后再从栈中弹出这些信息,恢复调用前的状态。这个过程被称作函数的压栈和弹栈操作。
  • 表达式求值:在计算机中,对算术表达式进行求值时,通常使用栈来实现。编译器可以通过两个栈来实现,一个栈用来保存操作数,另一个栈用来保存运算符。从左到右遍历表达式,当遇到数字时,将其压入操作数栈;当遇到运算符时,与运算符栈栈顶元素进行比较,根据运算符的优先级进行相应的压栈或出栈操作,并计算表达式的值。
    系统调用:在操作系统中,内核通常会将一个系统调用的参数、返回值和程序计数器等状态保存到进程的用户栈中,在系统调用结束后再从栈中弹出这些信息,恢复调用前的状态。
    递归实现的非递归化:某些递归算法可以通过使用栈的数据结构转换为非递归形式,通过手动管理栈来模拟递归调用的过程。
1.6栈的结构

在这里插入图片描述

2、栈的实现

栈的实现可以使用数组来完成,也可以使用链表来完成,使用数组来完成相对简单,

2.1 顺序栈

顺序栈是使用顺序存储结构数组)实现的栈,即利用一段连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设一个指针(通常称为栈顶指针)指示当前栈顶元素的位置。顺序栈具有结构简单、操作方便、易于实现等优点,因此在实际应用中非常广泛。

2.1.1 顺序栈的结构体
typedef int SDataType;

typedef struct Stack
{
	SDataType* _a;
	int _top;
	int _capacity;
}Stack;

栈结构里面有三个成员,一个栈顶,一个栈的数组,一个栈的总容量

2.1.2 顺序栈的初始化
void StackInit(Stack* ps)
{
	ps->_a = NULL;

	ps->_capacity = ps->_top = 0;
}

这里有两种方法初始化,一个是top始终指向栈顶的下一个元素的索引,一个是top始终是栈顶元素的索引。

2.1.3 顺序栈的销毁
// 销毁栈
void StackDestroy(Stack* ps)
{
	assert(ps);
	free(ps->_a);
	ps->_a = NULL;

	ps->_capacity = ps->_top = 0;
}
2.1.4 顺序栈的入栈
// 入栈
void StackPush(Stack* ps, SDataType data)
{
	assert(ps);
	 
	if (ps->_top == ps->_capacity)
	{
		int _newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;
		SDataType* _new_a = (SDataType*)realloc(ps, _newcapacity * sizeof(SDataType));
		if (_new_a == NULL)
		{
			perror("StackPush()::realloc()");
			exit(-1);
		}
		ps->_a = _new_a;
		ps->_capacity = _newcapacity;
	}
	ps->_a[ps->_top++] = data;
}
2.1.5 顺序栈的出栈
// 出栈
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->_top > 0);

	ps->_top--;
}

2.1.5 顺序栈的判空
// 判空
void StackEmpty(Stack* ps)
{
	assert(ps);

	return ps->_top == 0;
}
2.1.5 顺序栈的栈顶元素
// 获取栈顶元素
void StackTop(Stack* ps)
{
	assert(ps);
	assert(ps->_top > 0);

	return ps->_a[ps->_top - 1];
}
2.1.5 顺序栈的有效个数
// 计算栈内有效个数
void StackSize(Stack* ps)
{
	assert(ps);

	return ps->_top;
}

2、顺序栈的完整代码实现

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

typedef int SDataType;

typedef struct Stack
{
	SDataType* _a;
	int _top;
	int _capacity;
}Stack;

// 初始化
void StackInit(Stack* ps)
{
	ps->_a = NULL;

	ps->_capacity = ps->_top = 0;
}

// 销毁栈
void StackDestroy(Stack* ps)
{
	assert(ps);
	free(ps->_a);
	ps->_a = NULL;

	ps->_capacity = ps->_top = 0;
}

// 入栈
void StackPush(Stack* ps, SDataType data)
{
	assert(ps);
	 
	if (ps->_top == ps->_capacity)
	{
		int _newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;
		SDataType* _new_a = (SDataType*)realloc(ps, _newcapacity * sizeof(SDataType));
		if (_new_a == NULL)
		{
			perror("StackPush()::realloc()");
			exit(-1);
		}
		ps->_a = _new_a;
		ps->_capacity = _newcapacity;
	}
	ps->_a[ps->_top++] = data;
}

// 出栈
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->_top > 0);

	ps->_top--;
}

// 计算栈内有效个数
void StackSize(Stack* ps)
{
	assert(ps);

	return ps->_top;
}

// 获取栈顶元素
void StackTop(Stack* ps)
{
	assert(ps);
	assert(ps->_top > 0);

	return ps->_a[ps->_top - 1];
}

// 判空
void StackEmpty(Stack* ps)
{
	assert(ps);

	return ps->_top == 0;
}

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

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

相关文章

万兆POE网络变压器90W的性能和作用

万兆POE网络变压器GX82405SP-90W是一种应用于网络设备的电力供应器件&#xff0c;它结合了数据传输和电力供应功能&#xff0c;可以为PoE&#xff08;Power over Ethernet&#xff09;设备提供高功率供电。它的性能和作用主要包括&#xff1a; 1. 高功率供电&#xff1a;万兆P…

MyBatis——在WEB中使用MyBatis(MVC架构模式)

一、在 Web 应用中使用 MyBatis 项目目录结构 pojo package org.qiu.bank.pojo;/*** 账户类&#xff0c;封装账户数据* author 秋玄* version 1.0* package org.qiu.bank.pojo* date 2022-09-27-20:31* since 1.0*/ public class Account {private Long id;private String …

邮件代发邮箱API发送邮件时如何正确使用?

邮件代发API发送邮件如何使用&#xff1f;邮件代发的注意事项&#xff1f; 邮件代发邮箱API作为邮件发送的自动化工具&#xff0c;其正确使用对于提高工作效率、保障信息安全具有重要意义。下面&#xff0c;AokSend就来探讨一下在使用邮件代发邮箱API发送邮件时&#xff0c;应…

[数据集][图像分类]抽烟打电话分类数据集6150张3类别

数据集类型&#xff1a;图像分类用&#xff0c;不可用于目标检测无标注文件 数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;6150 分类类别数&#xff1a;3 类别名称:["normal","phone&…

【JVM基础篇】双亲委派机制介绍

文章目录 双亲委派机制简介案例&#xff1a;自底向上查找案例&#xff1a;自顶向下加载案例&#xff1a;C类在当前程序的classpath中 双亲委派机制的作用如何指定加载类的类加载器&#xff1f;面试题如果一个类重复出现在三个类加载器的加载位置&#xff0c;应该由谁来加载&…

css backdrop-filter 实现背景滤镜

官方给出的定义是&#xff1a;backdrop-filter属性允许您将图形效果&#xff08;如模糊或颜色偏移&#xff09;应用于元素后面的区域。因为它适用于元素后面的所有内容&#xff0c;所以要查看元素或其背景的效果&#xff0c;需要透明或部分透明。 大致分为以下10种&#xff1a…

【基于 PyTorch 的 Python 深度学习】5 机器学习基础(2)

前言 文章性质&#xff1a;学习笔记 &#x1f4d6; 学习资料&#xff1a;吴茂贵《 Python 深度学习基于 PyTorch ( 第 2 版 ) 》【ISBN】978-7-111-71880-2 主要内容&#xff1a;根据学习资料撰写的学习笔记&#xff0c;该篇主要介绍了如何选择合适的激活函数、损失函数和优化器…

【系统架构师】-案例篇(三)NoSQL与分布式对象调用

1、NoSQL 一个基于Web 2.0的大型社交网络系统。就该系统的数据架构而言&#xff0c;李工决定采用公司熟悉的数据架构&#xff0c;使用通用的商用关系型数据库&#xff0c;系统内部数据采用中央集中方式存储。该系统投入使用后&#xff0c;初期用户数量少&#xff0c;系统运行平…

第二证券|北交所股票散户可以买吗?门槛多少?

北交所股票散户能够买&#xff0c;不过一般来说&#xff0c;北交所股票出资风险比较大&#xff0c;不适合资金实力不雄厚的散户。 北交所买卖权限注册条件&#xff1a;请求注册权限前20个买卖日的证券账户和资金账户内的财物日均不低于50万元&#xff0c;其间不包括经过融资融…

【资源分享】完胜谷歌翻译的Deepl翻译

::: block-1 “时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验&#xff0c;帮助大家尽早适应研究生生活&#xff0c;尽快了解科研的本质。祝一切顺利&#xff01;—…

【算法】动态规划之背包DP与树形DP

前言&#xff1a; 本系列是学习了董晓老师所讲的知识点做的笔记 董晓算法的个人空间-董晓算法个人主页-哔哩哔哩视频 (bilibili.com) 动态规划系列 【算法】动态规划之线性DP问题-CSDN博客 【算法】动态规划之背包DP问题&#xff08;2024.5.11&#xff09;-CSDN博客 背包…

银河麒麟服务器操作系统ssh服务无法启动报exit-code

尝试重装ssh服务后依然无法解决&#xff0c;查看日志journalctl -xe&#xff0c;发现可能是ssh配置文件权限问题导致的。 journalctl -xe AWARNING: UNPROTECTED PRIVATE KEY FILE! AA Permissions 0755 for /etc/ssh/ssh_host_rsa_key are too open. A It is required that …

EPAI手绘建模APP工程图工具栏

(2) 工程图工具栏 ① 模板 1) 打开模板选择页面。 图 306 工程图模板列表 2) 模板选择页面列出了可以使用的工程图模板类型&#xff0c;每个模板规定了工程的大小、方向、规格、标准、常用字段等。也包括一些空白模板&#xff0c;此时可以通过添加表格等注释自定义工程图样式…

苹果15适合用哪些充电宝充电?苹果15可以用充电宝推荐

在如今移动设备如此普遍的时代&#xff0c;充电宝已成为我们日常生活中不可或缺的一部分。对于拥有苹果15的用户来说&#xff0c;选择一款适合的充电宝尤为重要。因为接口以及苹果手机配置上的一个升级&#xff0c;市面上很多普通充电宝已经不能兼容苹果15充电了。苹果15作为一…

5.10.8 Transformer in Transformer

Transformer iN Transformer (TNT)。具体来说&#xff0c;我们将局部补丁&#xff08;例如&#xff0c;1616&#xff09;视为“视觉句子”&#xff0c;并将它们进一步划分为更小的补丁&#xff08;例如&#xff0c;44&#xff09;作为“视觉单词”。每个单词的注意力将与给定视…

ChatGLM 本地部署指南(问题解决)

硬件要求&#xff08;模型推理&#xff09;&#xff1a; INT4 &#xff1a; RTX3090*1&#xff0c;显存24GB&#xff0c;内存32GB&#xff0c;系统盘200GB 如果你没有 GPU 硬件的话&#xff0c;也可以在 CPU 上进行推理&#xff0c;但是推理速度会更慢。 模型微调硬件要求更高。…

高效测评系统方案助力沃尔玛、亚马逊卖家提升产品销量

无论在哪个电商平台&#xff0c;测评确实是最有效的推广方式。测之前一定要选好产品&#xff0c;因为对于大部分卖家而言&#xff0c;不可能你店铺里所有的都是爆款&#xff0c;所以选择的是需要有潜力成为爆款的产品。测评是指通过搭建安全的环境模拟真实的买家购物行为&#…

AH1515-12v转3V20A电源芯片

AH1515-12v转3V20A电源芯片&#xff1a;一款强大的电源解决方案 在当今的电子设备领域&#xff0c;电源管理的重要性不言而喻。一款优秀的电源芯片能够为各种设备提供稳定、高效的电能转换。今天&#xff0c;我们将为大家介绍一款极具特色的电源芯片——AH1515。这款芯片将为您…

FMEA存在的五个主要不足及改进措施——FMEA软件

免费试用FMEA软件-免费版-SunFMEA 在制造业和产品设计领域&#xff0c;失效模式与影响分析&#xff08;Failure Modes and Effects Analysis&#xff0c;简称FMEA&#xff09;被广泛运用&#xff0c;用于预防潜在的设计或制造缺陷。然而&#xff0c;尽管FMEA在风险管理方面发挥…

【51】Camunda8-Zeebe核心引擎-Zeebe Gateway

概述 Zeebe网关是Zeebe集群的一个组件,它可以被视为Zeebe集群的联系点,它允许Zeebe客户端与Zeebe集群内的Zeebe代理进行通信。有关Zeebe broker的更多信息,请访问我们的附加文档。 总而言之,Zeebe broker是Zeebe集群的主要部分,它完成所有繁重的工作,如处理、复制、导出…