【算法与数据结构】栈的实现详解

news2025/9/20 6:28:00

请添加图片描述

文章目录

  • 📝栈的概念及结构
    • 🌉栈的实现
  • 🌠栈的接口
      • 🌉初始化栈
      • 🌠入栈
      • 🌉出栈
      • 🌠获取栈顶元素
      • 🌉获取栈中有效元素个数
      • 🌉检测栈是否为空
      • 🌉销毁栈
      • 🌉Stack.c文件:
      • 🌉测试文件
  • 🚩总结


📝栈的概念及结构

栈的概念:

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

栈是一种限定只允许在一端进行插入和删除操作的线性数据结构。

栈的主要特点:

  1. 先进后出(LIFO, Last In First Out)。新添加的元素都放在栈顶,取出元素时也是从栈顶取出。

  2. 只允许在一端(栈顶)进行插入和删除操作。插入操作称为入栈,删除操作称为出栈。

  3. 栈内元素的访问只能是顺序访问,不能随机访问。

  4. 通常使用数组或链表来实现栈。

栈的基本操作:

- push(item): 将元素添加到栈顶。
- pop(): 弹出栈顶元素,同时删除该元素。
- peek(): 返回栈顶元素,但不删除。 
- isEmpty(): 检查栈是否为空。
- size(): 返回栈中元素的个数。

栈的结构:
使用数组实现栈时,维护一个top指针指向栈顶元素的下一个位置。入栈时将元素添加到数组top位置,并将top1;出栈时从top位置取元素,并将top1
使用链表实现栈时,链表的头结点指向栈顶元素。入栈添加新节点到头结点后面,出栈删除头结点。
所以栈具有后进先出的特性,是一种限定只允许在一端插入和删除的线性数据结构。
在这里插入图片描述

🌉栈的实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的
代价比较小。
使用数组实现栈确实具有一些优点:

  1. 内存连续性:数组在内存中是连续存储的,这使得对数组的访问速度相对较快,因为它允许缓存友好的访问模式。
  2. 尾部操作高效:数组在尾部插入或删除元素的时间复杂度为 O(1),这使得栈的 push 和 pop 操作效率很高。

但是,使用数组实现栈也有一些限制:
4. 固定大小:数组的大小一旦确定,就不能动态扩展,如果栈需要存储的元素数量超过了数组的大小,就会导致栈溢出。
5. 动态调整的开销:当栈的大小超出数组容量时,需要重新分配更大的数组并将原始数据复制到新数组中,这会引入一定的开销。

相比,链表实现栈的优点是:

  1. 动态大小:链表可以根据需要动态扩展,不受固定大小的限制。
  2. 插入和删除操作的效率:在链表中,插入和删除操作的时间复杂度为 O(1),不会像数组那样需要重新分配和复制数据。

但链表实现也有其缺点:

  1. 空间开销:链表中的每个节点都需要额外的指针来指向下一个节点,这会增加存储开销。
  2. 缓存不友好:由于节点在内存中不一定是连续存储的,可能会导致缓存未命中,从而降低访问速度。

因此,选择使用数组或链表实现栈取决于具体的需求和性能要求。如果需要高效的尾部操作和内存连续性,则数组实现可能更合适;而如果需要动态大小和高效的插入/删除操作,则链表实现可能更合适。
在这里插入图片描述

🌠栈的接口

本文将将使用动态链表实现栈:
在这里插入图片描述
StackCode.h

# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

//方便修改
typedef int STDataType;
typedef struct Stack
{
	STDataType* _a;
	int _top;//栈顶
	int _capacity;//容量
}Stack;
//初始化栈
void StackInit(Stack* ps);
//入栈
void StackPush(Stack* ps, STDataType x);
//出栈
void StackPop(Stack* ps);
//获取栈顶元素
STDataType StackTop(Stack* ps);
//获取栈中有效元素个数
int StackSize(Stack* ps);
//检测栈是否有空,如果为空返true,如果不为空,返回false;
bool StackEmpty(Stack* ps);
//销毁栈
void StackDestroy(Stack* ps);

🌉初始化栈

//初始化栈
void StackInit(Stack* ps)
{
	assert(ps);//assert(ps)检查ps指针是否合法,防止空指针问题。
	ps->_a = NULL;//栈初始化时还未分配数组空间。
	ps->_capacity = ps->_top = 0;
}

注意:
_capacity和_top成员都设置为0
_capacity表示栈的总容量,初始化时为0表示还未分配空间。
_top表示栈顶元素的下一个位置,作为栈的有效元素计数器。初始化时为0表示栈为空。

🌠入栈

void StackPush(Stack* ps, STDataType x)
{
	assert(ps);
	//满了,需要扩容
	if (ps->_top == ps->_capacity)//判断栈是否满了(ps->_top == ps->_capacity),如果满了需要扩容:
	{//如果_capacity为0,新容量为4,否则新容量为原容量的2倍
		int newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;
		STDataType* temp = (STDataType*)realloc(ps->_a, newcapacity * sizeof(STDataType));//使用realloc重新分配数组空间
		if (NULL == temp)
		{
			perror("realloc temp");//实际分配失败会打印错误并返回
			return;
		}

		ps->_a = temp;//扩容成功后,更新_a指针和_capacity
		ps->_capacity = newcapacity;

	}
	//将元素x赋值到栈顶位置ps->_a[ps->_top]
	ps->_a[ps->_top] = x;
	ps->_top++;
}

🌉出栈

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

修改_top指针,就可以模拟出栈操作了。元素本身不做删除,只是修改指针来"移除"顶部元素。

🌠获取栈顶元素

//获取栈顶元素
STDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

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

由于栈使用数组实现,元素位置从0开始编号,栈顶指针_top指向当前栈顶元素的下一个位置,所以实际栈顶元素的位置是_top - 1

🌉获取栈中有效元素个数

//获取栈中有效元素个数
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->_top;
}

栈使用数组实现,元素从0开始插入,_top指针指向当前最后一个元素的下一个位置,所以_top值就代表当前栈中元素的个数

🌉检测栈是否为空

//检测栈是否为空,如果为空返回true,结果不为空false
bool StackEmpty(Stack* ps)
{
	assert(ps);
	if (ps->_top == 0)
		return true;
	else
		return false;
	
}

🌉销毁栈

//销毁栈
void StackDestroy(Stack* ps)
{
	assert(ps);
	ps->_a = NULL;
	ps->_capacity = ps->_top   = 0;
}

🌉Stack.c文件:

# define _CRT_SECURE_NO_WARNINGS 1
#include "StackCode.h"

//初始化栈
void StackInit(Stack* ps)
{
	assert(ps);
	ps->_a = NULL;
	ps->_capacity = ps->_top = 0;
}
//入栈
void StackPush(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, newcapacity * sizeof(STDataType));
		if (NULL == temp)
		{
			perror("realloc temp");
			return;
		}

		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];
}
//获取栈中有效元素个数
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->_top;
}
//检测栈是否为空,如果为空返回true,结果不为空false
bool StackEmpty(Stack* ps)
{
	assert(ps);
	if (ps->_top == 0)
		return true;
	else
		return false;
	
}
//销毁栈
void StackDestroy(Stack* ps)
{
	assert(ps);
	ps->_a = NULL;
	ps->_capacity = ps->_top   = 0;
}

🌉测试文件

Test.c

#include "STackCode.h"

int main()
{
	Stack s;
	StackInit(&s);
	StackPush(&s,1);
	StackPush(&s,2);
	StackPush(&s,3);
	StackPush(&s,4);

	int top = StackTop(&s);
	printf("%d", top);
	StackPop(&s);

	StackPush(&s, 5);
	StackPush(&s, 6);

	while (!StackEmpty(&s))
	{
		int top = StackTop(&s);
		printf("%d", top);
		StackPop(&s);
	}

	StackDestroy(&s);

	return 0;
}

测试结果:
在这里插入图片描述


🚩总结

请添加图片描述

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

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

相关文章

链表|142.环形链表

ListNode *detectCycle(ListNode *head) {ListNode *fast head, *slow head;while (fast && fast->next) {// 这里判断两个指针是否相等&#xff0c;所以移位操作放在前面slow slow->next;fast fast->next->next;if (slow fast) { // 相交&#xff0c…

windows11编译FFmpeg源码完整步骤

1.安装MSYS2 下载并安装MSYS2 安装GCC GCC安装成功 克隆FFmpeg源码 打开MSYS2终端并进入ffmpeg文件夹,然后输入./configure回车开始生成makefile

基于Vue的预约停车位APP设计与实现

目 录 摘 要 I Abstract II 引 言 1 1 相关技术 3 1.1 Vue简介 3 1.2 Node.js简介 3 1.3 JavaScript基本介绍 4 1.4 Ajax基本介绍 4 1.5 本章小结 4 2 软件需求分析与体系结构设计 5 2.1 系统定义用户 5 2.2 系统功能需求描述 5 2.3 系统用例分析 6 2. 3. 1 用户用例分析 6 2.…

ssm+springboot音乐播放器网站mybatis+jsp

测试流程 &#xff08;1&#xff09; 登录系统、填写用户名、密码选择角色&#xff0c;主要内容&#xff1a;进行权限控制。 &#xff08;2&#xff09; 用户查看音乐信息、音乐资讯功能&#xff0c;主要是测试系统实用性、方便性。 &#xff08;3&#xff09; 信息修…

CPU流水线设计

前言 大家好我是jiantaoyab&#xff0c;这是我所总结作为学习的笔记第九篇,在这里分享给大家,还有一些书籍《深入理解计算机系统》《计算机组成&#xff1a;结构化方法》《编码&#xff1a;隐匿在计算机软硬件背后的语言》&#xff0c;这篇文章讲CPU流水线设计&#xff0c;可以…

【Linux系统】线程

目录 一.线程的概念 (1)地址空间是进程的资源窗口 (2)轻量级进程 二.线程的理解 1.Linux中线程的实现方案 2. 线程VS进程 3.线程比进程更加轻量化 4.线程的优点 5.线程的缺点 6.线程共享的资源 7.线程私有的资源 三.地址空间虚拟到物理的转化 1.页框 2.重新理解文…

xss.haozi.me:0X12

</script> <script>alert(1)\</script>

同步与异步

同步 通常情况代码都是自上向下一行一行执行的 前边的代码不执行后边的代码也不会执行 同步的代码执行会出现阻塞的情况 一行代码执行慢会影响到整个程序的执行1 解决同步问题 java python通过多线程来解决 node.js通过异步方式来解决 异步 一段代码的执行不会影响到其他的…

c语言,大宗撮合交易中心系统核心模块代码

撮合交易系统&#xff08;Matching System&#xff09;常用于大宗交易&#xff0c;如股票、期货等市场&#xff0c;它负责根据买卖双方的报价和数量&#xff0c;自动撮合成交。撮合系统的核心模块通常包括订单管理、价格计算和撮合逻辑等部分。 由于撮合系统的实现复杂且依赖于…

【保姆级爬虫】微博关键词搜索并获取博文和评论内容(python+selenium+chorme)

微博爬虫记录 写这个主要是为了防止自己忘记以及之后的组内工作交接&#xff0c;至于代码美不美观&#xff0c;写的好不好&#xff0c;统统不考虑&#xff0c;我只能说&#xff0c;能跑就不错了&#xff0c;上学压根没学过python好吧&#xff0c;基本上是crtlc&ctrlv丝滑小…

nginx配置支持ipv6访问,ipv4改造ipv6

一、前言 本地测试nginx部署的web系统支持ipv6地址访问。 二、本机ipv6地址 cmd ipconfig 找到IPv6地址 其中带有%号其实是临时分配得到地址 我们可以ping一下看看 另一种ping的方式 加上中括号 还有就是去掉%号 三、nginx增加配置 server块里增加 listen [::]:80; 四、测…

php采集类snoopy2.0使用说明

我们经常采集一些网站数据时会被识别为机器人被网页被拒绝访问&#xff0c;类似这种&#xff1a; failed to open stream: HTTP request failed! HTTP/1.1 403 Forbidden网宿云安全平台检测到您当前的访问行为存在异常&#xff0c;请稍后重试... 云安全平台检测到您当前的访问…

攻防世界——elrond32

运行得到Access deny 我第一次尝试是 修改判断条件&#xff0c;jz改为jnz&#xff0c;jle改为jg&#xff0c; 这个思路运行后&#xff0c;代码因为缺少一个输入&#xff0c;而导致程序运行错误&#xff0c;所以我们只能静态分析 我们想进入Access grant 有两个函数&#xf…

一篇搞懂什么是LRU缓存|一篇搞懂LRU缓存的实现|LRUCache详解和实现

LRUCache 文章目录 LRUCache前言项目代码仓库什么时候会用到缓存(Cache)缓存满了&#xff0c;怎么办&#xff1f;什么是LRUCacheLRUCache的实现LRUCache对应的OJ题实现LRUCache对应的STL风格实现 前言 这里分享我的一些博客专栏&#xff0c;都是干货满满的。 手撕数据结构专栏…

代码理解 pseudo_labeled = outputs.max(1)[1]

import torchls torch.Tensor([[0.2,0.4],[0.3,0.2]]) print(ls.max(1))

银河麒麟服务器ky10 server wvp镜像制作

在线安装docker yum install docker -y cat >/etc/docker/daemon.json<<EOF{"registry-mirrors": ["https://registry.docker-cn.com","https://dockerhub.azk8s.cn","https://hub-mirror.c.163.com"]} EOF systemctl start …

Kubernetes 安全秘籍:5 个你必须知道的知识点

Kubernetes 安全和身份验证是确保集群和应用安全的关键。今天将深入探讨 Service Account、身份验证和RBAC的关键概念和实践&#xff0c;帮助您构建安全可靠的应用。今天本文将着重于安全相关的内容&#xff0c;并提供更详细的示例和配置说明&#xff0c;帮助兄弟们更深入地理解…

北京智源表示大模型推断少用几层也可以,节省15%算力资源

在人工智能领域&#xff0c;大语言模型&#xff08;LLMs&#xff09;已经在各种下游任务中展现出了绝佳的性能。通常采用零次学习、少次学习和微调等多种评估协议。然而&#xff0c;LLMs的推理阶段非常昂贵&#xff0c;需要大量的计算资源。理想情况下&#xff0c;LLMs的推理阶…

java-ssm-jsp-基于ssm的宝文理学生社团管理系统

java-ssm-jsp-基于ssm的宝文理学生社团管理系统 获取源码——》公主号&#xff1a;计算机专业毕设大全