顺序栈与链式栈

目录

1.  栈

1.1 栈的概念

2.  栈的实现

3. 顺序栈的实现

3.1 顺序栈的声明

3.2 顺序栈的初始化

3.3 顺序栈的入栈

 3.4 顺序栈的出栈

3.5 顺序栈获取栈顶元素

3.6 顺序栈获取栈内有效数据个数

3.7 顺序栈判断栈是否为空

3.8 顺序栈打印栈内元素

3.9 顺序栈销毁栈

3.10 完整代码

4. 链式栈的实现

4.1 链式栈的声明

4.2 链式栈的初始化

4.3 链式栈的入栈

4.4 链式栈的出栈

4.5 链式栈获取栈顶元素

4.6 链式栈获取栈内有效数据个数

4.7 链式栈判断栈是否为空

4.8 链式栈打印栈内元素

4.9 链式栈销毁栈

5. 疑问


1.  栈

1.1 栈的概念

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

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。

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

2.  栈的实现

我们了解了栈的概念,我们就可以发现,栈其实可以用顺序表和链表来实现,我们根据它的实现方式,可以把它分为顺序栈与链式栈。

3. 顺序栈的实现

Stack.h

//需要用到的库函数的头文件
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int STDataType;typedef struct Stack
{STDataType* arr;//指向动态开辟的一块空间int top;//指向栈顶元素的下一个位置int capacity;//栈的容量
}st;//初始化栈
void STInit(st* pst);
//入栈
void STPush(st* pst,STDataType x);
//出栈
void STPop(st* pst);
//获取栈顶元素
STDataType STTop(st* pst);
//获取栈内有效数据个数
int STSize(st* pst);
//判断栈是否为空
bool STEmpty(st* pst);
//打印栈内元素
void STPrint(st* pst);
//销毁栈
void STDestroy(st* pst);

3.1 顺序栈的声明

Stack.h

typedef int STDataType;typedef struct Stack
{STDataType* arr;//指向动态开辟的一块空间int top;//指向栈顶元素的下一个位置int capacity;//栈的容量
}st;

这里我们在声明顺序栈的结构的时候,这个top可以是指向栈顶元素的,那我们在进行栈的初始化就需要将他初始化为-1,如果top是指向栈顶元素的下一个,那我们就需要将他的初始化设置为0。两种方法均可行,这里可以根据自己的习惯进行设置。

3.2 顺序栈的初始化

Stack.c

void STInit(st* pst)
{//判断pst是否为空指针assert(pst);pst->arr = NULL;pst->capacity = pst->top = 0;
}

3.3 顺序栈的入栈

Stack.c

void STPush(st* pst, STDataType x)
{//判断pst是否为空指针assert(pst);//检查空间大小,是否需要增容if (pst->capacity == pst->top){int newcapacity = pst->capacity == 0 ? 4 :2 * pst->capacity;STDataType* tmp = (STDataType*)realloc(pst->arr,newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc");exit(1);}pst->arr = tmp;pst->capacity = newcapacity;}//入数据pst->arr[pst->top++] = x;
}

 3.4 顺序栈的出栈

Stack.c

void STPop(st* pst)
{//判断pst是否为空指针assert(pst);//判断栈是否为空assert(pst->top > 0);pst->top--;
}

3.5 顺序栈获取栈顶元素

Stack.c

STDataType STTop(st* pst)
{//判断pst是否为空指针assert(pst);//判断栈是否为空assert(pst->top > 0);//这里top指向栈顶元素的下一个位置,-1刚好指向栈顶元素return pst->arr[pst->top - 1];
}

3.6 顺序栈获取栈内有效数据个数

Stack.c

int STSize(st* pst)
{assert(pst);return pst->top;
}

3.7 顺序栈判断栈是否为空

Stack.c

bool STEmpty(st* pst)
{assert(pst);return pst->top == 0;
}

3.8 顺序栈打印栈内元素

Stack.c

void STPrint(st* pst)
{assert(pst);while(!STEmpty(pst)){printf("%d\n", STTop(pst));STPop(pst);}
}

3.9 顺序栈销毁栈

Stack.c

void STDestroy(st* pst)
{assert(pst);free(pst->arr);pst->arr = NULL;pst->top = pst->capacity = 0;
}

3.10 完整代码

Stack.h

//需要用到的库函数的头文件
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int STDataType;typedef struct Stack
{STDataType* arr;//指向动态开辟的一块空间int top;//指向栈顶元素的下一个位置int capacity;//栈的容量
}st;//初始化栈
void STInit(st* pst);
//入栈
void STPush(st* pst,STDataType x);
//出栈
void STPop(st* pst);
//获取栈顶元素
STDataType STTop(st* pst);
//获取栈内有效数据个数
int STSize(st* pst);
//判断栈是否为空
bool STEmpty(st* pst);
//打印栈内元素
void STPrint(st* pst);
//销毁栈
void STDestroy(st* pst);

Stack.c

#include"Stack.h"void STInit(st* pst)
{//判断pst是否为空指针assert(pst);pst->arr = NULL;pst->capacity = pst->top = 0;
}void STPush(st* pst, STDataType x)
{//判断pst是否为空指针assert(pst);//检查空间大小,是否需要增容if (pst->capacity == pst->top){int newcapacity = pst->capacity == 0 ? 4 :2 * pst->capacity;STDataType* tmp = (STDataType*)realloc(pst->arr,newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc");exit(1);}pst->arr = tmp;pst->capacity = newcapacity;}//入数据pst->arr[pst->top++] = x;
}void STPop(st* pst)
{//判断pst是否为空指针assert(pst);//判断栈是否为空assert(pst->top > 0);pst->top--;
}STDataType STTop(st* pst)
{//判断pst是否为空指针assert(pst);//判断栈是否为空assert(pst->top > 0);//这里top指向栈顶元素的下一个位置,-1刚好指向栈顶元素return pst->arr[pst->top - 1];
}int STSize(st* pst)
{assert(pst);return pst->top;
}bool STEmpty(st* pst)
{assert(pst);return pst->top == 0;
}void STPrint(st* pst)
{assert(pst);while(!STEmpty(pst)){printf("%d\n", STTop(pst));STPop(pst);}
}void STDestroy(st* pst)
{assert(pst);free(pst->arr);pst->arr = NULL;pst->top = pst->capacity = 0;
}

4. 链式栈的实现

Stack.h

//需要用到的库函数的头文件
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int STDataType;typedef struct StackNode //定义节点结构
{STDataType data;struct StackNode* next;
}stnode;typedef struct Stack //定义栈结构
{//记录栈顶stnode* top;//记录栈内有效数据个数int size;
}st;//初始化栈
void STInit(st* pst);
//入栈
void STPush(st* pst, STDataType x);
//出栈
void STPop(st* pst);
//获取栈顶元素
STDataType STTop(st* pst);
//获取栈内有效数据个数
int STSize(st* pst);
//判断栈是否为空
bool STEmpty(st* pst);
//打印栈内元素
void STPrint(st* pst);
//销毁栈
void STDestroy(st* pst);

4.1 链式栈的声明

Stack.h

typedef int STDataType;typedef struct StackNode //定义节点结构
{STDataType data;struct StackNode* next;
}stnode;typedef struct Stack //定义栈结构
{//记录栈顶stnode* top;//记录栈内有效数据个数int size;
}st;

这里如果我们用单链表的形式实现栈的话,单链表头插的时间复杂度为O(1),尾插的时间复杂度为O(N),所以这里我们需要把单链表的第一个有效节点设置为栈顶,如果想把链表的尾设置尾栈顶的话,那我们这里可能就需要使用双向链表来实现了,本章主要使用单链表来实现栈。

我们在声明链式栈的时候,我们这里使用了两个结构体,其中一个结构体声明链式栈里的数据节点,另一个结构体声明栈的结构,其中里面有个指向栈顶指针,还有一个记录栈内有效数据个数的size,这样我们在获取栈内有效数据个数的时候不需要遍历链表,时间复杂度从O(N)变成O(1)

4.2 链式栈的初始化

Stack.c

void STInit(st* pst)
{assert(pst);pst->top = NULL;pst->size = 0;
}

4.3 链式栈的入栈

Stack.c

void STPush(st* pst, STDataType x)
{assert(pst);stnode* newnode = (stnode*)malloc(sizeof(stnode));if (newnode == NULL){perror("malloc");exit(1);}newnode->data = x;newnode->next = NULL;if (pst->top== NULL){pst->top = newnode;}else{newnode->next = pst->top;pst->top = newnode;}pst->size++;
}

4.4 链式栈的出栈

Stack.c

void STPop(st* pst)
{assert(pst);assert(pst->size > 0);stnode* next = pst->top->next;free(pst->top);pst->top = next;pst->size--;
}

4.5 链式栈获取栈顶元素

Stack.c

STDataType STTop(st* pst)
{assert(pst);assert(pst->size > 0);return pst->top->data;
}

4.6 链式栈获取栈内有效数据个数

Stack.c

int STSize(st* pst)
{assert(pst);return pst->size;
}

4.7 链式栈判断栈是否为空

Stack.c

bool STEmpty(st* pst)
{assert(pst);return pst->size == 0;
}

4.8 链式栈打印栈内元素

Stack.c

void STPrint(st* pst)
{assert(pst);while (!STEmpty(pst)){printf("%d\n",STTop(pst));STPop(pst);}
}

4.9 链式栈销毁栈

Stack.c

void STDestroy(st* pst)
{assert(pst);stnode* pcur = pst->top;while (pcur){stnode* next = pcur->next;free(pcur);pcur = next;}pst->top = NULL;pst->size = 0;
}

4.10 完整代码

Stack.h

//需要用到的库函数的头文件
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int STDataType;typedef struct StackNode //定义节点结构
{STDataType data;struct StackNode* next;
}stnode;typedef struct Stack //定义栈结构
{//记录栈顶stnode* top;//记录栈内有效数据个数int size;
}st;//初始化栈
void STInit(st* pst);
//入栈
void STPush(st* pst, STDataType x);
//出栈
void STPop(st* pst);
//获取栈顶元素
STDataType STTop(st* pst);
//获取栈内有效数据个数
int STSize(st* pst);
//判断栈是否为空
bool STEmpty(st* pst);
//打印栈内元素
void STPrint(st* pst);
//销毁栈
void STDestroy(st* pst);

Stack.c

void STInit(st* pst)
{assert(pst);pst->top = NULL;pst->size = 0;
}void STPush(st* pst, STDataType x)
{assert(pst);stnode* newnode = (stnode*)malloc(sizeof(stnode));if (newnode == NULL){perror("malloc");exit(1);}newnode->data = x;newnode->next = NULL;if (pst->top== NULL){pst->top = newnode;}else{newnode->next = pst->top;pst->top = newnode;}pst->size++;
}void STPop(st* pst)
{assert(pst);assert(pst->size > 0);stnode* next = pst->top->next;free(pst->top);pst->top = next;pst->size--;
}STDataType STTop(st* pst)
{assert(pst);assert(pst->size > 0);return pst->top->data;
}int STSize(st* pst)
{assert(pst);return pst->size;
}bool STEmpty(st* pst)
{assert(pst);return pst->size == 0;
}void STPrint(st* pst)
{assert(pst);while (!STEmpty(pst)){printf("%d\n",STTop(pst));STPop(pst);}
}void STDestroy(st* pst)
{assert(pst);stnode* pcur = pst->top;while (pcur){stnode* next = pcur->next;free(pcur);pcur = next;}pst->top = NULL;pst->size = 0;
}

5. 疑问

我们发现,我们很多的接口函数只有几行代码,有必要单独写成一个函数吗?比如说出栈,我们直接通过访问结构体进行删除。

其实有必要的,为了规范一定的写法,保持一致性,我们可以通过接口来调用它的函数,不建议自行访问,因为我们不知道设计者在设计top的时候,top是指向栈顶元素还是栈顶元素的下一个位置。

所以,不管再简单,数据结构里面不要直接访问数据,建议调用它的接口方法。

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

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

相关文章

[数据集][目标检测]鸡蛋缺陷检测数据集VOC+YOLO格式2918张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2918 标注数量(xml文件个数)&#xff1a;2918 标注数量(txt文件个数)&#xff1a;2918 标注…

算法金 | 决策树、随机森林、bagging、boosting、Adaboost、GBDT、XGBoost 算法大全

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 决策树是一种简单直观的机器学习算法&#xff0c;它广泛应用于分类和回归问题中。它的核心思想是将复杂的决策过程分解成一系列简单的决…

【推荐】Prometheus+Grafana企业级监控预警实战

新鲜出炉&#xff01;&#xff01;&#xff01;PrometheusGrafanaAlertmanager springboot 企业级监控预警实战课程&#xff0c;从0到1快速搭建企业监控预警平台&#xff0c;实现接口调用量统计&#xff0c;接口请求耗时统计…… 详情请戳 https://edu.csdn.net/course/detai…

Word页码设置,封面无页码,目录摘要阿拉伯数字I,II,III页码,正文开始123为页码

一、背景 使用Word写项目书或论文时&#xff0c;需要正确插入页码&#xff0c;比如封面无页码&#xff0c;目录摘要阿拉伯数字I&#xff0c;II&#xff0c;III为页码&#xff0c;正文开始以123为页码&#xff0c;下面介绍具体实施方法。 所用Word版本&#xff1a;2021 二、W…

HTTPS 代理的优点和缺点是什么?

HTTPS&#xff08;超文本安全传输协议&#xff09;作为一种基于HTTP加上SSL安全层的网络通信协议&#xff0c;已经成为互联网上广泛使用的IP协议之一。它在保证信息安全和隐私方面具有很多优势&#xff0c;但也存在一些缺点。接下来&#xff0c;我们就来探究一下HTTPS协议的优缺…

Qt篇——获取Windows系统上插入的串口设备的物理序号

先右键【此电脑-管理- 设备管理器-端口&#xff08;COM和LPT&#xff09;】中找到我们插入的某个设备的物理序号&#xff0c;如下图红色矩形框出的信息&#xff0c;这个就是已插入设备的物理序号&#xff08;就是插在哪个USB口的意思&#xff09;。 在Linux下我们可以通过往/et…

【踩坑】修复循环设置os.environ[‘CUDA_VISIBLE_DEVICES‘]无效

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 问题示例 for gpus in [0, 1, 2, 3, 4, 5, 6, 7]:os.environ[CUDA_VISIBLE_DEVICES] gpusprint(torch.cuda.get_device_name(0)) 始终将使用第…

Mac安装多版本node

Mac下使用n模块去安装多个指定版本的Node.js&#xff0c;并使用命令随时切换。 node中的n模块是&#xff0c;node专门用来管理node版本的模块&#xff0c;可以进行node版本的切换&#xff0c;下载&#xff0c;安装。 1.安装n npm install -g n 2.查看版本 n --version 3.展…

动作捕捉与数字人实训室,引领动漫专业创新发展

如今&#xff0c;随着全身动作捕捉设备在动漫行业中的应用越来越重要&#xff0c;传统的教学模式与市场需求逐渐脱节&#xff0c;原有的教学方式和思路急需进行调整。高校通过搭建动作捕捉与数字人实训室&#xff0c;可以使得教学质量和效率大大提升&#xff0c;让学生能够接触…

如何采集拼多多的商品或店铺数据

怎么使用简数采集器批量采集拼多多的商品或店铺相关信息呢&#xff1f; 简数采集器暂时不支持采集拼多多的商品或店铺相关数据&#xff0c;只能采集页面公开显示的信息&#xff0c;谢谢。 简数采集器采集网站文章资讯等数据特别简单高效&#xff1a;只需输入网站网址&#xf…

全景vr交互微课视频开发让学习变得更加有趣、高效

在数字化教育的浪潮中&#xff0c;3D虚拟微课系统操作平台以其独特的魅力和创新的功能&#xff0c;成为吸引学生目光的焦点。这个平台不仅提供了引人入胜的画面和内容丰富的课件&#xff0c;更通过技术革新和制作方式的探索&#xff0c;将课程制作推向了一个全新的高度。 随着技…

HarmonyOS NEXT Developer Beta1配套相关说明

一、版本概述 2024华为开发者大会&#xff0c;HarmonyOS NEXT终于在万千开发者的期待下从幕后走向台前。 HarmonyOS NEXT采用全新升级的系统架构&#xff0c;贯穿HarmonyOS全场景体验的底层优化&#xff0c;系统更流畅&#xff0c;隐私安全能力更强大&#xff0c;将给您带来更高…

基于Cisco的校园网络拓扑搭建

特此说明&#xff1a;请先看评论区留言哦~ 一、基础配置 1.新建拓扑图 2.服务器配置 3.PC端配置 4.核心交换机配置 a.CORE-S1 Switch>enable Switch#configure terminal Switch(config)#hostname CORE-S1 CORE-S1(config)#vlan 10 CORE-S1(config-vlan)#vlan 20 CO…

【zabbix】zabbix 自动发现与自动注册、proxy代理

1、配置zabbix自动发现&#xff0c;要求发现的主机不低于2台 zabbix 自动发现&#xff08;对于 agent2 是被动模式&#xff09; zabbix server 主动的去发现所有的客户端&#xff0c;然后将客户端的信息登记在服务端上。 缺点是如果定义的网段中的主机数量多&#xff0c;zabbi…

第1章,物联网模式简介

物联网模式简介 物联网&#xff08;IoT&#xff09;在最近几年获得了巨大的吸引力&#xff0c;该领域在未来几年将呈指数级增长。这一增长将跨越所有主要领域/垂直行业&#xff0c;包括消费者、家庭、制造业、健康、旅游和运输。这本书将为那些想了解基本物联网模式以及如何混…

俄罗斯Yandex广告(Yandex ads)怎么做?Yandex广告搭建与效果优化技巧设置终极指南

您可以在Yandex推广中使用移动应用广告来覆盖数百万搜索和Yandex广告网络受众&#xff0c;从而提高应用的盈利能力。为了获得最佳效果&#xff0c;请在设置广告系列时遵循我们的建议。 入门 在 Yandex Direct 中创建广告活动。转到营销活动向导 → 应用安装和应用内转化&…

三叉神经痛多发于哪些部位,手术治疗会引起颅内感染吗?

三叉神经痛&#xff0c;一种突发的阵发性疾病&#xff0c;主要影响面部、口腔及下颌的特定区域。在日常无发作时期&#xff0c;患者与常人无异&#xff0c;但一旦发作&#xff0c;其疼痛之剧烈&#xff0c;常令人难以忍受。这种疼痛常表现为突发性的剧烈、短暂、如闪电般的抽痛…

【C语言】--常见类型和概念

❤️个人主页: 起名字真南 &#x1f495;个人专栏:【数据结构初阶】 【C语言】 目录 第一个C语言程序main函数printf函数库函数关键字字符和ASCII码字符串和\0转义字符 第一个C语言程序 #include<stdio.h> int main() {printf("Hello World\n");return 0; }ma…

React useId Hook

React 中有一个 useId hook&#xff0c;可以生成一个唯一 ID&#xff0c;这个有什么用处呢&#xff0c;用个 UUID 是不是可以替代呢&#xff1f;如果我们只考虑客户端&#xff0c;那么生成唯一 Id 的方法比较简单&#xff0c;我们在 State 中保存一个计数器就好&#xff0c;但是…

windows 安装 Kubernetes(k8s)

windows 安装 docker 详情见&#xff1a; https://blog.csdn.net/sinat_32502451/article/details/133026301 minikube Minikube 是一种轻量级的Kubernetes 实现&#xff0c;可在本地计算机上创建VM 并部署仅包含一个节点的简单集群。 下载地址&#xff1a;https://github.…