栈的深度解析:顺序栈与链栈的实现

引言

栈是一种重要的线性数据结构,遵循“后进先出”(LIFO)的原则。栈的应用非常广泛,如表达式求值、括号匹配、递归实现等。在本文中,我们将深入探讨栈的概念,并通过顺序栈和链栈两种实现方式进行对比分析。

一、基本概念

1.1 定义

栈(Stack)是一种只能在一端进行插入和删除操作的集合,遵循“后进先出”(LIFO)原则。即最后加入的元素最先被移除

1.2 基本操作

  • 入栈(Push):将新元素添加到栈顶。
  • 出栈(Pop):移除并返回栈顶元素。
  • 查看栈顶元素(Peek):返回栈顶元素,但不删除它。
  • 判断是否为空(isEmpty):检查栈是否没有元素。
  • 统计栈的大小(Size):获取栈中有效元素个数。

1.3 特点

操作限制:只能在栈顶进行元素的添加(入栈)和移除(出栈)。

栈顶元素:栈顶是当前可以访问和操作的元素。

空栈:栈为空时,无法进行出栈操作。

二、栈的实现 

2.1 顺序栈

使用数组实现栈时,我们可以将数组的尾部作为栈顶。
入栈与出栈操作分别对应在数组尾部。添加元素与删除元素,时间复杂度都为 𝑂(1)

2.1.1 基本结构

typedef struct Stack
{DataType* arr;//数组实现int top;//栈顶int capacity;//记录容量
}ST;

2.1.2 功能实现 

1).初始化栈
//初始化栈
void StackInit(ST* p)
{assert(p);p->arr = NULL;p->top = p->capacity = 0;
}
2).销毁栈 
//销毁栈
void StackDestory(ST* p)
{assert(p);if (p->arr){free(p->arr);}p->arr = NULL;p->top = p->capacity = 0;
}
3).入栈 

//入栈
void StackPush(ST* p,DataType x)
{assert(p);checkcapacity(p);p->arr[p->top++] = x;
}
4).判空 
//判断栈顶是否为空
bool StackEmpty(ST* p)
{assert(p);return p->top == 0;
}
5).出栈 

//出栈
void StackPop(ST* p)
{assert(p);assert(!StackEmpty(p));//栈顶不为空才能删除--p->top;
}
6).取栈顶元素
//取栈顶元素
DataType StackTop(ST* p)
{assert(p);assert(!StackEmpty(p));return p->arr[p->top - 1];
}
7).栈长度 
//获取栈中有效元素个数
int StackSize(ST* p)
{assert(p);return p->top;
}

2.2 链式栈 

使用链表实现栈时,我们可以将链表的头节点视为栈顶,尾节点视为栈底。
对于入栈操作,我们只需将元素插入链表头部,这种节点插入方法被称为“头插法”。而对于
出栈操作,只需将头节点从链表中删除即可。

2.2.1 基本结构

//定义节点结构
typedef struct Node {DataType data;//数据域struct Node *next;//指针域
}Node;
// 定义链栈结构
typedef struct Stack{Node* top;            // 栈顶指针int size;             // 栈中有效元素个数
} ST;

2.2.2 功能实现

1).初始化栈
//初始化栈
void StackInit(ST* p)
{assert(p);p->top = NULL;p->size = 0;
}
2).销毁栈
//销毁栈
void StackDestory(ST* p) {Node* pcur = p->top; // 从栈顶开始Node* temp;while (pcur != NULL) {temp = pcur;         // 记录当前节点pcur = pcur->next; // 移动到下一个节点free(temp);             // 释放当前节点的内存}p->top = NULL;          // 将栈顶指针设置为 NULLp->size = 0;            // 重置栈的大小
}
3).入栈

//创建节点
//Node* CreateNode(DataType x)
//{
//	Node* newnode = (Node*)malloc(sizeof(Node));
//	if (newnode == NULL) {
//		perror("malloc fail");
//		exit(1);
//	}
//	newnode->data = x;
//	newnode->next = NULL;
//	return newnode;
//}//入栈
void StackPush(ST* p,DataType x)
{assert(p);Node* newnode = CreateNode(x);newnode->next = p->top->next;p->top->next = newnode;++p->size;
}
4).判空
//判断栈顶是否为空
bool StackEmpty(ST* p)
{assert(p);return p->top->next==NULL;//p->top->next是栈顶元素
}
5).出栈

//出栈
void StackPop(ST* p)
{assert(p);assert(!StackEmpty(p));//栈顶不为空才能删除Node* temp = p->top->next;p->top->next = p->top->next->next;free(temp);temp = NULL;--p->size;
}
6).取栈顶元素
//取栈顶元素
DataType StackTop(ST* p)
{assert(p);return p->top->next->data;
}
7).栈长度
//获取栈中有效元素个数
int StackSize(ST* p)
{assert(p);return p->size;
}

2.3 对比 

顺序栈vs链栈
特点顺序栈链式栈
存储结构基于数组基于链表
内存管理静态分配(也可动态扩容)动态分配
空间效率容量固定(也可动态扩容)动态扩展
访问速度O(1)时间复杂度O(1)时间复杂度
栈溢出容易发生不易发生

三、完整代码

3.1  顺序栈

Stack.h 

该部分主要包括函数的声明、以及头文件的引用

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int DataType;
typedef struct Stack
{DataType* arr;//数组实现int top;//栈顶int capacity;//记录容量
}ST;
//初始化栈
void StackInit(ST* p);
//销毁栈
void StackDestory(ST* p);
//入栈
void StackPush(ST* p, DataType x);
//出栈
void StackPop(ST* p);
//取栈顶元素
DataType StackTop(ST* p);
//获取栈中有效元素个数
int StackSize(ST* p);
Stack.c

该部分主要包括函数的定义 

#define _CRT_SECURE_NO_WARNINGS
#include"Stack.h"
//初始化栈
void StackInit(ST* p)
{assert(p);p->arr = NULL;p->top = p->capacity = 0;
}
//销毁栈
void StackDestory(ST* p)
{assert(p);if (p->arr){free(p->arr);}p->arr = NULL;p->top = p->capacity = 0;
}
//判断扩容
void checkcapacity(ST* p)
{assert(p);if (p->capacity == p->top){int NewCap = p->capacity == 0 ? 4 : 2 * p->capacity;DataType* tmp = (DataType*)realloc(p->arr, NewCap * sizeof(DataType));if (tmp == NULL){perror("realloc fail!");exit(1);}p->arr = tmp;p->capacity = NewCap;}
}
//入栈
void StackPush(ST* p,DataType x)
{assert(p);checkcapacity(p);p->arr[p->top++] = x;
}
//判断栈顶是否为空
bool StackEmpty(ST* p)
{assert(p);return p->top == 0;
}
//出栈
void StackPop(ST* p)
{assert(p);assert(!StackEmpty(p));//栈顶不为空才能删除--p->top;
}
//取栈顶元素
DataType StackTop(ST* p)
{assert(p);assert(!StackEmpty(p));return p->arr[p->top - 1];
}
//获取栈中有效元素个数
int StackSize(ST* p)
{assert(p);return p->top;
}
main.c 

该部分用来测试,即函数的使用

#define _CRT_SECURE_NO_WARNINGS
#include"Stack.h"
void test01()
{ST st;StackInit (&st);StackPush (&st,1);StackPush (&st,3);StackPush (&st,5);StackPush (&st,7);while (!StackEmpty(&st))//栈顶元素依次出栈{DataType  data = StackTop(&st);printf("%d ", data);StackPop(&st);//出栈}
}
int main()
{test01();return 0;
}

3.2 链式栈

 Stack.h 

该部分主要包括函数的声明、以及头文件的引用

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int DataType;
//定义节点结构
typedef struct Node {DataType data;//数据域struct Node *next;//指针域
}Node;
// 定义链栈结构
typedef struct Stack{Node* top;            // 栈顶指针int size;             // 栈中有效元素个数
} ST;
//初始化栈
void StackInit(ST* p);
// 创建链表头节点
Node* CreateHead();
//销毁栈
void StackDestory(ST* p);
//入栈
void StackPush(ST* p, DataType x);
//出栈
void StackPop(ST* p);
//取栈顶元素
DataType StackTop(ST* p);
//获取栈中有效元素个数
int StackSize(ST* p);
的引用
Stack.c

该部分主要包括函数的定义 

#pragma once
#include"Stack.h"
//初始化栈
void StackInit(ST* p)
{assert(p);p->top = NULL;p->size = 0;
}
//创建节点
Node* CreateNode(DataType x)
{Node* newnode = (Node*)malloc(sizeof(Node));if (newnode == NULL) {perror("malloc fail");exit(1);}newnode->data = x;newnode->next = NULL;return newnode;
}
// 创建链表头节点
Node* CreateHead()
{Node* headnode = CreateNode(0); // 头节点值为0(或任何不使用的值)return headnode;
}
//入栈
void StackPush(ST* p,DataType x)
{assert(p);Node* newnode = CreateNode(x);newnode->next = p->top->next;p->top->next = newnode;++p->size;
}
//判断栈顶是否为空
bool StackEmpty(ST* p)
{assert(p);return p->top->next==NULL;//p->top->next是栈顶元素
}
//出栈
void StackPop(ST* p)
{assert(p);assert(!StackEmpty(p));//栈顶不为空才能删除Node* temp = p->top->next;p->top->next = p->top->next->next;free(temp);temp = NULL;--p->size;
}
//取栈顶元素
DataType StackTop(ST* p)
{assert(p);return p->top->next->data;
}
//获取栈中有效元素个数
int StackSize(ST* p)
{assert(p);return p->size;
}
//销毁栈
void StackDestory(ST* p) {Node* pcur = p->top; // 从栈顶开始Node* temp;while (pcur != NULL) {temp = pcur;         // 记录当前节点pcur = pcur->next; // 移动到下一个节点free(temp);             // 释放当前节点的内存}p->top = NULL;          // 将栈顶指针设置为 NULLp->size = 0;            // 重置栈的大小
}
main.c 

该部分用来测试,即函数的使用

#define _CRT_SECURE_NO_WARNINGS
#include"Stack.h"
void test01()
{ST st;StackInit(&st);st.top = CreateHead();//栈顶指针指向头节点,故头节点的next为栈顶元素StackPush(&st,1);StackPush(&st,2);StackPush(&st,3);//StackPop(&st);//int data = StackTop(&st);//int size=StackSize(&st);//printf("%d\n", data);//printf("%d", size);//while (!StackEmpty(&st))//{//	DataType  data = StackTop(&st);//	printf("%d ", data);//	StackPop(&st);//出栈//}StackDestory(&st);//st.top = NULL;
}
int main()
{test01();return 0;
}

四、总结

栈是一种重要的基础数据结构,适用于多种计算场景。通过顺序栈和链式栈的实现,我们可以更好地理解栈的工作原理及其应用。选择哪种实现方式取决于具体需求,顺序栈在内存使用上更高效,而链式栈则提供了更大的灵活性。希望这篇博客能帮助你更好地理解栈的概念和实现!

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

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

相关文章

路径报错问题

项目场景&#xff1a; 假设这是我的项目结构&#xff0c;我现在需要在aa.js文件中引入并使用aa.geojson文件&#xff0c; 问题&#xff1a; 当我引入路径是const filePath ../geo/aa.geojson&#xff1b;的时候&#xff0c;系统报错 "aa.geojson is not Found",找不…

[000-002-01].第29节:MySQL执行流程

1、MySQL的查询流程&#xff1a; 客户端请求进入到数据库服务器后&#xff0c;先进行查询缓存&#xff0c;如果命中&#xff0c;那么就返回结果&#xff1b;如果没命中&#xff0c;进入到解析器&#xff0c;进行词法解析和语法解析&#xff0c;生成解析树&#xff1b;然后进入到…

企业图纸文档管理系统推荐 三大企业图纸文档管理软件详细介绍

在现代企业的设计和生产过程中&#xff0c;图纸文档的管理是至关重要的一环。 无论是建筑、制造业&#xff0c;还是技术研发领域&#xff0c;图纸文档的正确存储、分享与管理能够极大提升工作效率&#xff0c;避免误操作或信息丢失。 接下来&#xff0c;小编将为大家推荐三款优…

采购管理系统SRM助力电子元器件制造企业构建高效的供应商管理体系

在当今快速迭代的电子元器件制造行业中&#xff0c;构建一套高效、透明的供应商管理体系对于提升企业竞争力、降低运营成本、确保供应链稳定性至关重要。采购管理系统(SRM&#xff0c;Supplier Relationship Management)作为这一领域的得力助手&#xff0c;正引领着电子元器件制…

远程连接服务器时出现“这可能是由于CredSSP加密数据库修正”的错误提示的解决办法

现象&#xff1a; 当远程连接服务器时&#xff0c;有时候会出现以下提示&#xff0c;从而导致无法成功连接服务&#xff0c;如下所述&#xff1a; 原因&#xff1a; 远程桌面使用的是“凭据安全支持提供程序协议 (CredSSP) ”&#xff0c;这个协议在未修补的版本中是存在漏…

scrapy 爬取微博(四)【最新超详细解析】: 设计篇

一、功能设计 开始开发之前我们先对本文的scrapy微博爬虫工程进行一个功能的设计&#xff0c;包含的功能模块如下&#xff1a; 功能模块具体描述微博文章爬取根据关键词、时间范围等参数爬取微博文章&#xff0c;获取用户名、ID、微博mid、微博内容、点赞、转发、评论等数据微…

《深度学习》卷积神经网络 使用最优模型、调整学习率 用法解析及案例实现

目录 一、使用最优模型 1、什么是最优模型 2、如实使用最优模型 1&#xff09;读取参数方法 2&#xff09;调用完整模型方法 3&#xff09;实例 完整代码&#xff1a; 打印结果&#xff1a; 二、调整学习率 1、什么是调整学习率 2、目的 3、调整学习率的方法 1&am…

C++ 语言课程笔记

C 语言课程笔记 C语言程序设计第四版——谭浩强著&#xff0c;此书中的代码题大部分已经在本文中展示&#xff0c;以及南开大学 C 语言上机题库 100 题的作答&#xff0c;如果有作答不正确的地方或者可优化的地方&#xff0c;欢迎指正&#xff0c;谢谢&#xff01; 001 屏幕输出…

DAMODEL丹摩智算平台实践CogVideoX

文章目录 前言 一、平台账号注册并登录 二、部署CogVideoX &#xff08;一&#xff09;简介 &#xff08;二&#xff09;部署 1. 创建实例 2. 配置环境和依赖 3.预制模型与配置文件 三、开始运行 总结 前言 该文章主要记录DAMODEL丹摩智算平台实践过程与心得体会&…

【YashanDB知识库】客户端字符集与数据库字符集兼容问题

本文转自YashanDB官网&#xff0c;具体内容请见https://www.yashandb.com/newsinfo/7352675.html?templateId1718516 问题现象 客户端yasql配置字符集为GBK&#xff0c;服务端yasdb配置字符集为UTF8&#xff0c;之后执行语句&#xff1a; 会发现&#xff1a; 期望是两个都…

FAT32取证分析

前言&#xff1a; 在正常工作中经常会有数据恢复或者取证分析的场景&#xff0c;数据是否能被恢复&#xff0c;主要还是看数据是否被覆盖&#xff0c;正常情况下文件虽然被删除&#xff0c;只是修对应的标志位&#xff0c;文件本身数据并不会被破坏&#xff0c;所以我们就可以…

【Java】1.初识Java

文章目录 1. 使用记事本创建.Java程序2. 使用IDEA创建第一个Java程序3. 标识符4. 关键字 1. 使用记事本创建.Java程序 先创建了HelloWorld.java这个文件。然后用Sublime Text记事本打开&#xff0c;输入以下代码。 winr&#xff0c;cmd输入D:切换到D盘&#xff0c;然后输入cd …

投资气膜场馆:开启未来体育发展的新纪元—轻空间

随着对体育设施建设的重视&#xff0c;气膜场馆作为一种创新的体育设施&#xff0c;正日益成为投资的热门选择。气膜场馆凭借其独特的优势和多重好处&#xff0c;不仅能提升体育场馆的功能性和经济性&#xff0c;更为地方经济发展注入了新的活力。 成本效益显著 气膜场馆具有快…

419. 棋盘上的战舰(C++)

题目 给你一个大小为 m x n 的矩阵 board 表示棋盘&#xff0c;其中&#xff0c;每个单元格可以是一艘战舰 X 或者是一个空位 . &#xff0c;返回在棋盘 board 上放置的 舰队 的数量。 舰队 只能水平或者垂直放置在 board 上。换句话说&#xff0c;舰队只能按 1 x k&#xff…

SimpleAIAgent:使用免费的glm-4-flash即可开始构建简单的AI Agent应用

SimpleAIAgent是基于C# Semantic Kernel 与 WPF构建的一款AI Agent探索应用。主要用于使用国产大语言模型或开源大语言模型构建AI Agent应用的探索学习&#xff0c;希望能够帮助到感兴趣的朋友。 接下来我想分享一下我的AI Agent应用实践。 翻译文本并将文本存入文件 第一个…

Transformer入门指南!14天速成

想系统而又透彻地入门和学习Transformer&#xff0c;可以按照以下思路(步骤): 1、首先&#xff0c;了解一些NLP领域的基本知识&#xff0c;比如文本是如何被表征的&#xff0c;序列文本信息的处理&#xff0c;基于(深度神经网络)的语言模型是如何处理自然语言的; 2、Transfor…

计算机前沿技术-人工智能算法-大语言模型-最新论文阅读-2024-09-21

计算机前沿技术-人工智能算法-大语言模型-最新论文阅读-2024-09-21 1. AIvril: AI-Driven RTL Generation With Verification In-The-Loop Authors: Mubashir ul Islam, Humza Sami, Pierre-Emmanuel Gaillardon, and Valerio Tenace AIVRIL: 人工智能驱动的RTL生成与验证内…

表观项目文章速递,平均IF=9.7

表观组学是研究基因组层面的表观遗传变化及其调控机制的一门学科&#xff0c;它在现代生物学研究中具有重要意义。传统的遗传学研究主要关注DNA序列的变化&#xff0c;而表观组学则着眼于在不改变DNA序列的情况下&#xff0c;如何通过化学修饰和染色质结构的改变进而影响基因表…

【开源免费】基于SpringBoot+Vue.JS墙绘产品展示交易平台(JAVA毕业设计)

本文项目编号 T 049 &#xff0c;文末自助获取源码 \color{red}{T049&#xff0c;文末自助获取源码} T049&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

Windows 10 on ARM, version 22H2 (updated Sep 2024) ARM64 AArch64 中文版、英文版下载

Windows 10 on ARM, version 22H2 (updated Sep 2024) ARM64 AArch64 中文版、英文版下载 基于 ARM 的 Windows 10 请访问原文链接&#xff1a;https://sysin.org/blog/windows-10-arm/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;s…