【数据结构】栈的实现以及数组和链表的优缺点

个人主页:一代…
个人专栏:数据结构
在这里插入图片描述

1.栈

1.1栈的概念及结构

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

在这里插入图片描述
在这里插入图片描述

栈的实现

栈的实现可以用两种线性结构来实现,一种是数组,另一种是链表。

那么用哪种来实现栈比较合适呢?
那我们就要来考虑数组和链表的各自的好处了。

**学过顺序表的小伙伴都知道顺序表的底层是用数组来实现的。那么顺序表和链表有什么区别呢?

  1. 存储空间:
    顺序表的物理和逻辑上是连续的
    链表的物理上不一定连续,但逻辑上连续
  2. 随机访问
    顺序表随机访问某一个元素时时间复杂度为O(1)
    链表访问某一个元素时时间复杂度尾O(N)
  3. 在任意位置插入和删除元素
    顺序表插入和删除元素的时间复杂度为O(N)
    链表的时间复杂度为O(N)
  4. 空间利用
    动态顺序表空间不够是需要扩容,可能造成空间浪费
    链表没容量的概念,新增一个节点就malloc一个大小为STDataType的空间
  5. 缓存利用率
    顺序表的缓存利用率高
    链表的缓存利用率低

缓存利用率
在这里插入图片描述

这里主存就相当于内存,本地磁盘就相当于硬盘,这两个的一个区别就是带点和不带电的区别,内存和硬盘在带电状态下都能正常工作,但它们的工作方式和工作内容完全不同。
内存是易失性的,即当电源关闭时,内存中的数据会丢失。而硬盘是非易失性的,即使电源关闭,数据也会保留。
在不带电状态下,硬盘可以更安全地进行物理操作,而内存则无法进行任何操作(因为内存模块本身不包含任何电源或机械部件)。

    这里我浅浅讲一下顺序表和链表缓存利用率的区别

数组(顺序表)和链表在缓存利用率上的区别主要体现在它们的物理存储结构和访问方式上。
在访问一块数据内存空间时,要先把内存加载到缓存,在对其进行访问,而其并不是没此访问一个内存就将其加载到缓存,而是访问一块内存时将其后面的连续的内存一起加载到缓存,然后在对其进行访问。
数组是一块连续的内存空间,元素紧密排列,空间效率更高。这种物理空间的连续性使得数组在访问数据时具有更高的缓存利用率。当CPU执行指令运算需要访问数据时,会先去缓存中查找这个数据。如果数据已经在缓存中(缓存命中),那么CPU就可以直接从缓存中读取数据,而不需要从主存中读取,从而提高了程序的运行效率。由于数组的物理地址是连续的,因此数组中的数据在缓存中的命中率更高,减少了从主存中读取数据的次数,从而提高了缓存利用率。
相比之下,链表是由节点组成,节点之间通过引用(指针)连接。链表在添加和删除元素时只需要改变指针的指向,以节点为单位进行动态内存分配和回收,灵活并且插入和删除效率高。但是,链表的节点在物理存储上是不连续的,因此链表中的数据在缓存中的命中率相对较低。当CPU需要访问链表中的数据时,可能需要频繁地从主存中读取数据到缓存中,降低了缓存利用率,并且会造成缓存污染。
综上所述,数组(顺序表)由于物理空间的连续性,在缓存利用率上通常优于链表。这也是为什么在需要频繁访问数据的场景下,如数组的遍历、查找等操作,使用数组通常会比链表更高效。

所以链表和数组实现栈的区别并不大,但数组比链表更优一些。
(注:链表实现栈可以用单链表,用首元结点作栈顶,也可以用双链表来实现)
下面我们就开是讲解栈的实现

栈的初始化

void StackInit(Stack* ps)
{assert(ps);ps->_capacity = 0;//top指向栈顶数据的下一个位置ps->_top = 0;//top指向栈顶数据//ps->_top = -1;ps->_a = NULL;
}

这里初始化top既可以为0,也可以为-1,为0为top指向栈顶数据的下一个位置,为-1时指向栈顶数据。
在这里插入图片描述

栈的销毁

void StackDestroy(Stack* ps)
{assert(ps);free(ps->_a);ps->_a = NULL;ps->_top = ps->_capacity = 0;
}

入栈

void StackPush(Stack* ps, STDataType data)
{assert(ps);//扩容if (ps->_top == ps->_capacity){int newcapacity = ps->_capacity == 0 ? 4 : 2 * ps->_capacity;STDataType* tmp = (STDataType*)realloc(ps->_a, newcapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}ps->_a = tmp;ps->_capacity = newcapacity;}ps->_a[ps->_top] = data;ps->_top++;
}

出栈

void StackPop(Stack* ps)
{assert(ps);assert(ps->_top > 0);ps->_top--;
}

取出栈顶元素

STDataType StackTop(Stack* ps)
{assert(ps);assert(ps->_top > 0);return ps->_a[ps->_top - 1];
}

栈的大小

int StackSize(Stack* ps)
{assert(ps);return ps->_top;
}

栈是否为空

void StackDestroy(Stack* ps)
{assert(ps);free(ps->_a);ps->_a = NULL;ps->_top = ps->_capacity = 0;
}

栈的全部代码
stack.h

#define  _CRT_SECURE_NO_WARNINGS 1
// 支持动态增长的栈
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int STDataType;
typedef struct Stack
{STDataType* _a;int _top;		// 栈顶int _capacity;  // 容量 
}Stack;
// 初始化栈 
void StackInit(Stack* ps);
// 入栈 
void StackPush(Stack* ps, STDataType data);
// 出栈 
void StackPop(Stack* ps);
// 获取栈顶元素 
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数 
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps);
// 销毁栈 
void StackDestroy(Stack* ps);

stack.c

#define  _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"void StackInit(Stack* ps)
{assert(ps);ps->_capacity = 0;//top指向栈顶数据的下一个位置ps->_top = 0;//top指向栈顶数据//ps->_top = -1;ps->_a = NULL;
}void StackPush(Stack* ps, STDataType data)
{assert(ps);//扩容if (ps->_top == ps->_capacity){int newcapacity = ps->_capacity == 0 ? 4 : 2 * ps->_capacity;STDataType* tmp = (STDataType*)realloc(ps->_a, newcapacity * sizeof(STDataType));if (tmp == NULL){perror("relloc fail");return;}ps->_a = tmp;ps->_capacity = newcapacity;}ps->_a[ps->_top] = data;ps->_top++;
}void StackPop(Stack* ps)
{assert(ps);assert(ps->_top > 0);ps->_top--;
}STDataType StackTop(Stack* ps)
{assert(ps);assert(ps->_top > 0);return ps->_a[ps->_top - 1];
}int StackSize(Stack* ps)
{assert(ps);return ps->_top;
}int StackEmpty(Stack* ps)
{assert(ps);return ps->_top == 0;
}void StackDestroy(Stack* ps)
{assert(ps);free(ps->_a);ps->_a = NULL;ps->_top = ps->_capacity = 0;
}

test.c


#include"stack.h"
int main()
{Stack st;StackInit(&st);StackPush(&st, 5);StackPush(&st, 3);StackPush(&st, 4);StackPush(&st, 6);StackPop(&st);StackPop(&st);StackPop(&st);printf("%d\n",StackSize(&st));if (StackEmpty(&st)){printf("栈为空\n");}else{printf("栈不为空\n");}int ret=StackTop(&st);printf("%d\n", ret);if (!StackEmpty(&st)){for (int i = 0; i < st._top; i++){printf("%d ", st._a[i]);}}StackDestroy(&st);return 0;
}

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

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

相关文章

ETL工具kettle(PDI)入门教程,Job

先新建两个Transform&#xff0c;MysqlToMysql.ktr和CsvToExcel.ktrURL&#xff1a;ETL工具kettle入门教程&#xff0c;transform&#xff0c;Mysql-&#xff1e;Mysql&#xff0c;Csv-&#xff1e;Excel-CSDN博客 主对象树&#xff0c;作业上右击&#xff0c;点击新建 核心对…

面试题库-项目

1.项目主要实现了哪些功能&#xff1f; 本项目是专门为校园食堂窗口定制的一款软件产品&#xff0c;包括系统管理后台和客户端两部分。其中系统管理后台主要提供给食堂内部员工使用&#xff0c;可以对餐厅的菜品、套餐、订单、员工等进行管理维护。客户端主要提供给学生及校职…

台球桌上的答案 如何优化图形化编程对复杂程序的展现

在公司的休息区&#xff0c;卧龙和凤雏正站在台球桌旁&#xff0c;一场激战即将打响。 “来吧&#xff0c;凤雏&#xff0c;让我们一决高下&#xff01;”卧龙手持台球杆&#xff0c;面带自信的微笑&#xff0c;向凤雏发起挑战。 凤雏点了点头&#xff0c;拿起台球杆&#xff0…

自定义表单工作流的优势介绍

当前&#xff0c;应用低代码技术平台可以助力企业提高效率&#xff0c;降低开发成本&#xff0c;实现个性化场景定制&#xff0c;因而越来越得到了客户的信赖与喜爱。很多客户朋友询问自定义表单工作流的优势和特点&#xff0c;为了帮助大家解决这个疑问&#xff0c;今天&#…

代码随想录算法训练营Day 38| 动态规划part01 | 理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

代码随想录算法训练营Day 38| 动态规划part01 | 理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯 文章目录 代码随想录算法训练营Day 38| 动态规划part01 | 理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯理论基础一、常规题目二、解题步骤…

PLC设备通过智能网关采用HTTP协议JSON文件对接MES等系统平台

智能网关IGT-DSER集成了多种PLC的原厂协议&#xff0c;方便实现各种PLC、智能仪表通过HTTP协议与MES等各种系统平台通讯对接。PLC内不用编写程序&#xff0c;设备不用停机&#xff0c;通过网关的参数配置软件(下载地址)配置JSON文件的字段与PLC寄存器地址等参数即可。 智能网关…

如何给文件和文件夹添加备注信息

1. 给文件添加备注信息 1. 打开文件夹&#xff0c;点击查看 → 选项 → 更改文件夹和搜索选项 → 勾除隐藏受保护的操作系统文件 → 勾选显示隐藏的文件、文件夹和驱动器&#xff1b; 2. listary工具搜索desktop.ini&#xff0c;随便点击一个desktop.ini文件&#xff0c;即可…

Gartner发布准备应对勒索软件攻击指南:勒索软件攻击的三个阶段及其防御生命周期

攻击者改变了策略&#xff0c;在某些情况下转向勒索软件。安全和风险管理领导者必须通过提高检测和预防能力来为勒索软件攻击做好准备&#xff0c;同时还要改进其事后应对策略。 主要发现 勒索软件&#xff08;无加密的数据盗窃攻击&#xff09;是攻击者越来越多地使用的策略。…

git的标签管理

理解标签 在Git中,标签tag用于标记特定的一个重要点&#xff0c;比如版本发布。标签允许捕捉某一次提交的状态&#xff0c;当我们需要退回到某次提叫的版本时&#xff0c;通过标签我们快速定位到。标签具有两种类型&#xff1a; 轻量标签&#xff1a;最简单的标签形式&#x…

Linux(CentOS7)离线使用安装盘部署Telnet

[在线工具网 - 各类免费AI工具合集&#xff0c;免费pdf转word等](https://www.orcc.online) https://orcc.online 挂载镜像CentOS-7-x86_64-DVD-1810.iso到/mnt下&#xff08;其他位置也行&#xff09;&#xff0c;命令如下&#xff1a; mount /dev/sr0 /mnt 安装包默认在Pa…

C++ 概览并发

并发 资源管理 资源 程序中符合先获取后释放&#xff08;显式或隐式&#xff09;规律的东西&#xff0c;比如内存、锁、套接字、线程句柄和文件句柄等。RAII&#xff1a; (Resource Acquisition Is Initialization),也称为“资源获取就是初始化”&#xff0c;是C语言的一种管…

Vue.js-----vue组件

能够说出vue生命周期能够掌握axios的使用能够了解$refs, $nextTick作用能够完成购物车案例 Vue 生命周期讲解 1.钩子函数 目标&#xff1a;Vue 框架内置函数&#xff0c;随着组件的生命周期阶段&#xff0c;自动执行 作用: 特定的时间点&#xff0c;执行特定的操作场景: 组…

[前后端基础]图片详解

[前后端基础]图片传输与异步-CSDN博客 https://juejin.cn/post/6844903782959022093#heading-3 base64、file和blob用JS进行互转的方法大全【前端】_js base64转blob-CSDN博客 后端存储方式 对于第一种存储方式&#xff0c;我们前端直接将存储路径赋值给 src 属性即可轻松显示。…

STM32——GPIO输出(点亮第一个LED灯)

代码示例&#xff1a; #include "stm32f10x.h" // Device headerint main() {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP;GPIO_InitSt…

租赁商城小程序源码部署/售后更新/搭建上线维护

基于ThinkPHPFastAdminUniApp开发的租赁商城小程序&#xff0c;提供用户物品租赁服务的应用程序&#xff0c;方便客户搭建各种类型的租赁场景服务。通过小程序端多角色进行平台管理&#xff0c;用户租赁商品缴纳租金及押金&#xff0c;员工端可操作商品出库和归还&#xff0c;订…

文件夹名批量重命名:一键实现中文到意大利语的高效翻译!文件管理更高效!

文件夹管理成为了我们日常工作和生活中的重要一环。当文件夹名称繁杂且多样&#xff0c;尤其是涉及到不同语言时&#xff0c;如何快速、准确地批量重命名&#xff0c;成为了许多人的迫切需求。今天&#xff0c;我们就来聊聊如何轻松实现文件夹名从中文到意大利语的批量翻译&…

基于FPGA的视频矩阵切换方案

一、单个显示设备的系统方案&#xff1a;会议室只有1个显示设备 会议室的信号源有很多&#xff0c;但是显示设备只有1个&#xff0c;这个时候最佳方案是使用切换器。 &#xff08;1&#xff09;切换器&#xff08;控制方式&#xff1a;遥控器、软件、机箱面板、中控&#xff…

版本控制工具之Git的基础使用教程

Git Git是一个分布式版本控制系统&#xff0c;由Linux之父Linus Torvalds 开发。它既可以用来管理和追踪计算机文件的变化&#xff0c;也是开发者协作编写代码的工具。 本文将介绍 Git 的基础原理、用法、操作等内容。 一、基础概念 1.1 版本控制系统 版本控制系统&#x…

Python-----容器的介绍以及操作

1.列表和元组 1.列表是什么, 元组是什么&#xff1a; 编程中, 经常需要使用变量, 来保存/表示数据. 如果代码中需要表示的数据个数比较少, 我们直接创建多个变量即可. 但是有的时候, 代码中需要表示的数据特别多, 甚至也不知道要表示多少个数据. 这个时候, 就需要用到列表 列表…

论文解读--High-resolution Automotive Radar Point Cloud Imaging and Processing

高分辨汽车雷达点云成像和处理 摘要 汽车雷达具有体积小、硬件成本低、全天候工作、高分辨率等公认的优点&#xff0c;是高级驾驶辅助系统(ADAS)必不可少的一类重要传感器。然而&#xff0c;低角度分辨率和低成像性能的限制很难满足下一阶段ADAS的需要。新兴的4D成像雷达采用多…