(超详细)数据结构——“栈”的深度解析

前言:

   在前几章我们介绍了线性表的基本概念,也讲解了包括顺序表,单链表,双向链表等线性表,相信大家已经对线性表比较熟悉了,今天我们要实现线性表的另一种结构——栈。

1.栈的概念

    栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFOLast In First Out)的原则。这里的栈与内存中的栈在结构上是一致的,它们提取数据和存放数据也叫出栈和压栈。

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

2.栈的实现 

   栈的实现可以选择使用链表或者数组,这两种结构都可以很好的实现栈的各种操作,相对而言,数组是更好的选择,因为栈的插入只需要对结构进行尾插,而数组尾插的代价相较于链表来说没有那么大。

3.代码实现 

   为了方便管理,我们将栈的实现分为三个文件,分别是test.c ,Stack.c ,Stack.h(stack中译为堆叠,也就是栈的意思) ,由于我们选择使用数组来实现栈,所以在数据结构中我们就使用动态顺序表,顺序表中要包含顺序表空间大小,一个指向这块空间的指针和top来表示栈顶,而这个数据的类型是视情况而定的,我们使用typedef对数组中的元素类型改名,使栈存储的数据类型更加灵活,为了方便使用,我们也将栈类型改名为ST:

typedef int STDataType;
typedef struct Stack
{STDataType* arr;int top;int capacity;//表示当前空间大小}ST;

实现了栈的基本结构之后,我们接下来要实现栈的各种操作,例如栈的压栈和出栈等操作。

3.1 栈的初始化 

   在程序刚开始执行使,栈内部的所有成员都没有初始化,它们的值都是不确定的,而不确定意味着不可控,我们后续需要通过这些成员的值来判断执行一些操作,例如表示数组的空间大小capacity变量,如果它的值是不确定的,那么我们也无法对数组执行有效操作,所以我们要对它进行初始化,而刚开始栈是空的,所以我们让指向栈的指针指向空,元素为0个:

void STInit(ST* pst)
{assert(pst);pst->arr = NULL;pst->capacity = 0;pst->top = 0;
}//初始化

3.2 栈的销毁

   我们栈的空间使用的的是顺序表结构实现的,而顺序表的空间都是在堆上开辟的,所以我们需要手动将这些空间释放:

void STDestroy(ST* pst)
{assert(pst);free(pst->arr);pst->arr = NULL;pst->capacity = pst->top = 0;
}//销毁

3.3 压栈操作 

   压栈就是进栈的意思,对栈进行压栈操作之前,我们要判断栈空间够不够,如果不够,我们需要手动从堆上开辟一块空间,而一次开辟的空间是有限的,将空间开辟得太大也会造成空间浪费,所以我们判断在空间不够时使用realloc函数重新开辟一块更大的空间,而插入操作则比较简单,只需要在数组中top指向的位置将我们要插入的数据插入,再让top加一就可以了:

void STPush(ST* pst, STDataType x)
{assert(pst);if (pst->capacity == pst->top){int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDataType* ret = (STDataType*)realloc(pst->arr, newcapacity * sizeof(STDataType));if (ret == NULL){perror("realloc fail");return;}pst->capacity = newcapacity;pst->arr = ret;}pst->arr[pst->top++] = x;
}//压栈

3.4 出栈操作 

    出栈操作也就是删除栈顶的元素,这个操作比较简单,只需要让top减一,因为我们在取数据时,只取top下面的数据,top上面的数据则默认不在栈内,这样就相当于我们将这个元素删除了:

void STPop(ST* pst)
{assert(pst);pst->top--;
}//删除

3.5 栈顶 

 有时我们频繁对栈进行插入和删除操作,我们需要查看栈顶情况,就可以使用这个方法,,这个方法的实现也相对简单,只需要返回栈中top下标的下一个 元素,因为top始终指向栈顶元素的下一个位置,我们插入元素也是先将元素放到下标为top的位置中,再让top加一:

STDataType STTop(ST* pst)
{assert(pst);assert(pst->top > 0);return pst->arr[pst->top - 1];
}//栈顶

3.6 判空 

  我们有时要对栈进行置空操作,如果不确定栈何时为空就可以使用这个方法,判空操作只需要判断top是否为0就可以了,如果为零,就为真,返回true,如果不为空,就为假返回false:

bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;
}//判空

3.7 栈的大小 

   我们前面提到了,top就是栈的大小,如果我们直接查看top不是更快吗,为什么要单独写一个方法呢,事实上我们单独实现一个方法是为了方便统一操作,要执行何种操作,只需要调用一个方法就可以实现:

int STSize(ST* pst)
{assert(pst);return pst->top;
}//大小

3.8 测试

实现完这些方法之后,我们要测试一下我们的代码有没有问题:

经过我们测试,这些方法都没有问题,本期栈的讲解到这就结束了,是不是比前几期简单一些呢,我们亲自上手就知道了,代码放在下面感兴趣的小伙伴们可以试试哦。 

Stack.h :

#pragma once
#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 STDestroy(ST* pst);//销毁void STPush(ST* pst, STDataType x);//压栈void STPop(ST* pst);//删除STDataType STTop(ST* pst);//栈顶元素bool STEmpty(ST* pst);//判空int STSize(ST* pst);//大小

Stack.c :

#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"void STInit(ST* pst)
{assert(pst);pst->arr = NULL;pst->capacity = 0;pst->top = 0;
}//初始化void STPush(ST* pst, STDataType x)
{assert(pst);if (pst->capacity == pst->top){int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDataType* ret = (STDataType*)realloc(pst->arr, newcapacity * sizeof(STDataType));if (ret == NULL){perror("realloc fail");return;}pst->capacity = newcapacity;pst->arr = ret;}pst->arr[pst->top++] = x;
}//压栈void STPop(ST* pst)
{assert(pst);pst->top--;
}//删除STDataType STTop(ST* pst)
{assert(pst);assert(pst->top > 0);return pst->arr[pst->top - 1];
}//栈顶bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;
}//判空int STSize(ST* pst)
{assert(pst);return pst->top;
}//大小void STDestroy(ST* pst)
{assert(pst);free(pst->arr);pst->arr = NULL;pst->capacity = pst->top = 0;
}//销毁

test.c :

#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"
void test()
{ST s;STInit(&s);printf("插入四个元素\n");STPush(&s, 1);STPush(&s, 2);STPush(&s, 3);STPush(&s, 4);printf("栈顶元素为:%d\n", STTop(&s));printf("%d个元素\n", STSize(&s));while (!STEmpty(&s)){printf("%d ", STTop(&s));STPop(&s);}STDestroy(&s);
}int main()
{test();return 0;
}

 

 

 

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

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

相关文章

【Docker】存储数据卷

目录 1、挂载数据卷到容器里 2、查询挂载文件 3、容器与主机之间映射共享卷 4、三个容器之间使用共享卷 5、卷数据的备份与恢复 5.1 备份 5.2 恢复 1、挂载数据卷到容器里 docker run -itd --name test02 -v /data nginx docker exec -it test02 bashls / docker inspe…

如何对C++代码进行性能调优

对C代码进行性能调优是一个涉及多个方面的过程&#xff0c;包括代码优化、数据结构设计、算法选择、内存管理、并行化等多个方面。以下是一些常用的C性能调优技巧&#xff1a; 代码优化&#xff1a; 避免不必要的复制&#xff1a;使用引用或指针传递大型对象或数据结构。常量优…

解决IDEA的Web项目右键无法创建Servlet问题

右键新建没有servlet? 在pom.xml文件中需要导入servlet依赖&#xff0c;很简单的&#xff0c;别担心&#xff0c;就20秒解决 看我操作&#xff01;&#xff01;&#xff01; 1. 找到自动生成的pom.xml文件 只要你创建了maven项目&#xff0c;就会自动生成pom.xml文件&#xf…

ESP32-C3模组上跑通MQTT(7)—— tcp例程(2)

接前一篇文章:ESP32-C3模组上跑通MQTT(6)—— tcp例程(1) 《ESP32-C3 物联网工程开发实战》 一分钟了解MQTT协议 ESP32 MQTT API指南-CSDN博客 ESP-IDF MQTT 示例入门_mqtt outbox-CSDN博客 ESP32用自签CA进行MQTT的TLS双向认证通信_esp32 mqtt ssl-CSDN博客 特此致谢…

qiankun微前端:qiankun+vite+vue3+ts(未完待续..)

目录 什么是微前端 目前现有的微前端 好处 使用 子应用的页面在主应用里显示 什么是微前端 微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。 我的理解就是将一个大型的前端应用拆分成多个模块&#xff0c;每个微前端模块可以由…

目标检测的常用算法和框架

一、常见算法 下面介绍几种常见的目标检测算法: Haar特征+级联分类器:该算法使用Haar特征作为特征提取器,并通过级联分类器来检测目标。这种算法运行速度快,在处理实时视频时表现良好,但对于复杂场景的目标检测效果可能不理想。 HOG特征+SVM:该算法使用方向梯度直方图(…

C++ 设计模式之中介者模式

C 设计模式之中介者模式 简介 1、中介者模式&#xff08;Mediator&#xff09;是一种行为型设计模式&#xff0c;它用于减少对象之间的直接耦合&#xff0c;使得这些对象可以松散地耦合在一起&#xff0c;并且可以通过一个中介者对象来间接地交互。中介者模式通常用于一组对象…

Linux基础篇——目录结构

基本介绍 Linux的文件系统是采用级层式的树状目录结构&#xff0c;在此结构中的最上层是根目录"/"&#xff0c;然后在根目录下再创建其他的目录 在Linux中&#xff0c;有一句经典的话&#xff1a;在Linux世界里&#xff0c;一切皆文件 Linux中根目录下的目录 具体的…

木各力“GERRI”被“GREE”格力无效宣告成功

近日“GERRI”被“GREE”格力无效宣告成功&#xff0c;“GERRI”和“GREE”近似不&#xff0c;如果很近似当初就不会通过初审和下商标注册证&#xff0c;但是如果涉及知名商标和驰名商标&#xff0c;人家就可以异议和无效。 “GERRI”在被无效宣告时&#xff0c;引用了6个相关的…

(笔记)M1使用hombrew安装qemu

homebrew formulae的网址&#xff1a; qemu — Homebrew Formulae​​​​​​ brew install qemu 如果要支持OpenGL&#xff0c;执行下面的命令 brew tap knazarov/qemu-virglbrew install qemu-virgl 报错Error: qemu-virgl: Failed to download resource "qemu-virgl…

232. 用栈实现队列 (Implement Queue using Stacks)

用栈实现队列 (Implement Queue using Stacks) 题目描述 使用两个栈实现一个队列。队列的操作包括 push(x)、pop()、peek() 和 empty()。 示例&#xff1a; MyQueue queue new MyQueue();queue.push(1); queue.push(2); queue.peek(); // 返回 1 queue.pop(); // 返回…

深入剖析C++多态的实现与原理-详解 (三万字)

100编程书屋_孔夫子旧书网 目录 一、多态基础 虚函数 虚函数的继承虚类/虚基类重写/覆盖 条件:概念:多态的条件 其他的多态行为 多态中子类可以不写virtual协变 代码举例继承遗留问题解决 析构函数 具体解决方式:题目1 答案:解析:题目2 答案:C11 override和final final 功能1…

web渗透-反序列化漏洞

一、简介 就是把一个对象变成可以传输的字符串&#xff0c;目的就是为了方便传输。假设&#xff0c;我们写了一个class,这个class里面存有一些变量。当这个class被实例化了之后&#xff0c;在使用过程中里面的一些变量值发生了改变。以后在某些时候还会用到这个变量&#xff0…

ctfshow sqli-libs web541--web551

web541 and和or 被替换为空格 # 还有 1 也是不能生效的?id-1 union select 1,2,3-- 双写绕过 ?id-1 union select 1,(select group_concat(table_name) from infoorrmation_schema.tables where table_schemactfshow),3 -- flags?id-1 union select 1,(select group_con…

Nginx软件的安装及使用

Nginx概述 Nginx功能介绍 静态的web资源服务器html&#xff0c;图片&#xff0c;js&#xff0c;css&#xff0c;txt等静态资源http/https协议的反向代理 &#xff0c;7层 url结合FastCGI /uWSGI/SCGI等协议反向代理动态资源请求tcp/udp协议的请求转发&#xff08;反向代理…

计算二叉树的深度

#include <iostream> // 定义二叉树节点 struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; // 递归函数来计算二叉树的深度 int maxDepth(TreeNode* root) { i…

【Linux】Linux系统配置,linux的交互方式

1.Linux系统环境安装 有三种方式 裸机安装或者双系统 -- 不推荐虚拟机安装 --- 不推荐云服务器/安装简单&#xff0c; 维护成本低——推荐&#xff0c; 未来学习效果好 我们借助云服务器 云服务器&#xff08;Elastic Compute Service&#xff0c;ECS&#xff09;的标准定义…

以太网交换机原理

没有配置&#xff0c;比较枯燥&#xff0c;二可以认识线缆&#xff0c; 三比较重要&#xff0c;慢慢理解&#xff0c;事半功倍。 各位老少爷们&#xff0c;在下给大家说段以太网交换机原理&#xff0c;说得不好大家多多包涵&#xff0c;说得好呢&#xff0c;大家叫个好&#x…

【面试系列】数据分析师高频面试题及详细解答

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来&#xff1a;详细讲解AIGC的概念、核心技术、…

数据库回表介绍

索引覆盖 索引覆盖或称为覆盖索引&#xff0c;是数据库中的一种优化手段当我们在执行一个sql查询时&#xff0c;如果只需要查询某几个字段的值&#xff0c;并且这几个字段的数据都已经被包含在某一个索引中(而不是全表扫描)&#xff0c;那么数据库引擎就会直接通过这个索引来取…