算法与数据结构——栈

news/2024/11/13 10:19:05/文章来源:https://www.cnblogs.com/1873cy/p/18380633

栈(stack)是一种遵循先入后出逻辑的线性数据结构。

如图所示,我们将堆叠元素的顶部称为“栈顶”,底部称为“栈底”。将吧元素添加到栈顶的操作叫做“入栈”,删除栈顶的操作叫做“出栈”。

栈的常用操作

方法 描述 时间复杂度
push() 元素入栈(添加至栈顶) O(1)
pop() 栈顶元素出栈 O(1)
peek() 访问栈顶元素 O(1)

通常情况下,我们可以直接使用编程语言内置的栈类,而一些语言没有专门提供栈类,我们可以将该语言的“数组”或“链表”当做栈来使用,并在程序逻辑上忽略与栈无关的操作。

	/*初始化栈*/stack<int> sta;/*元素入栈*/sta.push(1);sta.push(3);sta.push(2);sta.push(5);sta.push(4);/*访问栈顶元素*/int top = sta.top();cout << "栈顶元素:" << top << endl;/*元素出栈*/sta.pop();cout << "元素出栈" << endl;top = sta.top();cout << "栈顶元素:" << top << endl;/*获取栈的长度*/int sta_size = sta.size();cout << "栈长度:" << sta_size << endl;/*判断是否为空*/bool sta_empty = sta.empty();cout << "是否为空:" << sta_empty << endl;

栈的实现

为深入了解栈的运行机制,尝试自己实现一个栈类。

遵循先入后出的原则,因此我们只能在栈顶添加或删除元素。而数组和链表都可以在任意位置添加和删除元素,因此栈可以视为一种受限制的数组或链表。我们可以“屏蔽”数组或链表的部分无关操作,使其对外表现的逻辑符合栈的特性。

基于链表实现栈

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

struct ListNode{int val;ListNode *next;ListNode(int x) :val(x), next(nullptr){}ListNode(int x,ListNode *next) :val(x), next(next){}
};class LinkedListStack{
private:ListNode * stackTop; // 将头节点作为栈顶int stackSize;   // 栈长度
public:LinkedListStack(){stackTop = nullptr;stackSize = 0;}~LinkedListStack(){/*遍历链表每个节点 释放内存*/while (stackTop != nullptr){ListNode *tem = stackTop;stackTop = stackTop->next;delete tem;}}/*获取栈长度*/int size(){return stackSize;}/*判断栈是否为空*/bool isEmpty(){return (stackSize == 0);}/*入栈*/void push(int num){ListNode * node = new ListNode(num);node->next = stackTop;stackTop = node;stackSize++;}/*出栈*/int pop(){int num = top();ListNode * tem = stackTop;stackTop = stackTop->next;delete tem;stackSize--;return num;}/*访问栈顶元素*/int top(){if (isEmpty())throw out_of_range("栈为空");return stackTop->val;}
};

基于数组实现

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

class ArrayStack{
private:vector<int> sta;
public:/*获取栈长度*/int size(){return sta.size();}/*判断栈是否为空*/bool isEmpty(){return (size() == 0);}/*入栈*/void push(int num){sta.push_back(num);}/*出栈*/int pop(){int num = top();sta.pop_back();return num;}/*访问栈顶元素*/int top(){if (isEmpty())throw out_of_range("栈为空");return sta[size()-1];}
};

两种实现对比

支持操作:

两种结果实现都支持栈定义中的各项操作。数组实现额外支持随机访问,但这已经超出了栈的定义范畴,因此一般不会用到。

时间效率:

在基于数组实现中,入栈和出栈操作都在预先分配好的连续内存中进行,具有很好的缓存本地性,因此效率较高。但如果入栈时超出数组容量,会触发扩容机制,导致该次入栈操作时间复杂度变为O(n)。

在基于链表实现中,链表的扩容十分灵活,不存在上述数组扩容时效率降低的问题。但是,入栈操作需要初始化节点对象并修改指针,因此效率相对较低。

空间效率

在初始化列表时,系统会为列表分配“初识容量”,该容量可能超出实际需求,并且扩容机制通常是按照特定的倍率(如2倍)进行扩容,扩容后的容量也可能超出实际需求。基于数组实现的栈可能造成一定的空间浪费。

基于链表实现的栈由于需要额外存储指针,因此链表节点占的空间相对较大。

栈的典型应用

  • 浏览器中的后退与前进、软件中的撤销与反撤销。每当我们打开新的网页,浏览器就会对上一个网页执行入栈,这样我们就可以通过后退操作回到上一个网页。后退操作实际上是在出栈,如果要同时支持后退和前进,那么需要两个栈来配合实现。
  • 程序内存管理。每次调用函数时,系统都会在栈顶添加一个栈帧,用于记录函数的上下文信息。在递归函数中,向下递推阶段会不断执行入栈操作,而向上回溯阶段则会不断执行出栈操作。

 

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

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

相关文章

LuCI Themes

OpenWrt 2020BootstrapBootstrap LightBootstrap DarkMaterialOpenWrt

指挥网络

树形图的定义:没有环,每个点(除了根节点)的入度都是\(1\),根节点的入度为\(0\) 朱刘算法的过程见OI-wiki;当没有环的时候,就满足了树形图的定义,于是可以结束;否则的话就将所有环缩点(注意此时由于每个点的入度都是\(1\),所以不可能存在两个环有公共点和公共边)得到…

处理异常

2、.map 没用用吗1、pdb、看完后 反汇编

CSS处理font-weight不生效问题

如何解决 Android 系统中文字体字重问题 翻找了几天资料,发现Noto Sans SC字体能支持中文/数字/英文字体 100,300,400,500,700,900 的字重,具体如下图所示:<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans+SC:300,400,…

处理font-weight不生效问题

如何解决 Android 系统中文字体字重问题 翻找了几天资料,发现Noto Sans SC字体能支持中文/数字/英文字体 100,300,400,500,700,900 的字重,具体如下图所示:<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans+SC:300,400,…

Kubernetes API资源规范

1. 资源类型和资源对象 1.1 资源类型 (Resource Types) 1.1.1 核心资源类型Kubernetes API Primitive用于描述在Kubernetes上运行应用程序的基本组件,即俗称的Kubernetes对象(Object) 它们持久存储于API Server上,用于描述集群的状态依据资源的主要功能作为分类标准,Kuber…

一本通信奥解题: 1251:仙岛求药

1251:仙岛求药 时间限制: 1000 ms 内存限制: 65536 KB提交数:31087 通过数: 13638 【题目描述】少年李逍遥的婶婶病了,王小虎介绍他去一趟仙灵岛,向仙女姐姐要仙丹救婶婶。叛逆但孝顺的李逍遥闯进了仙灵岛,克服了千险万难来到岛的中心,发现仙药摆在了迷阵的深处…

TwinCAT3 - 实现CiA402

目录1,起缘2,想办法3,开搞3.1,CANOpen通信3.1.1 对象字典3.1.2 通信建立3.2,CiA402伺服状态机3.3,伺服运行3.3.1 操作模式3.3.2 轮廓位置模式3.3.3 轮廓速度模式3.3.4 其他4,用起来 1,起缘 在TwinCAT3项目中涉及到轴运动时,通常做法都是在PLC中安装TC1250或者TF5000,…

地理:美国各州首府系列

America1.botson文化重镇波士顿 2.annapolis 3.弗吉尼亚州首府里士满 4.罗得岛州的普罗维登斯 5.加利福尼亚州的萨克拉门托 6.纽约州奥尔巴尼市 7.阿拉巴马州蒙哥马利市 8.alascap 9.arizona 10.little阿肯色州首府小石城 11.康涅狄格州哈特福德市 12.特拉华州多佛市 13.印第安…

利用kafka和kafka connect插件debezium实现oracle表同步

1.kafka安装 1.1.java安装 openjdk下载,建议使用17,至少应该高于版本11 # 进入家目录,解压下载的java包,配置环境变量 tar vxf openjdk-20.0.1_linux-x64_bin.tar.gz -C /usr/local/ vi .bash_profile # 注意要把JAVA的目录放到$PATH之前 export JAVA_HOME=/usr/local/jdk-…

WPF中如何根据数据类型使用不同的数据模板

我们在将一个数据集合绑定到列表控件时,有时候想根据不同的数据类型,显示为不同的效果。 例如将一个文件夹集合绑定到ListBox时,系统文件夹显示为不同的效果,就可以使用模板选择器功能。 WPF提供了一个模板选择器类型DataTemplateSelector,它可以根据数据对象和数据绑定元…

Typecho Joe 导航菜单目录以及搜索关键字回显主题优化版

Joe 是 Typecho 博客中一款开源免费且非常精美的主题,但是这款主题很早就停止维护了,有些功能作者并没有开发,并且在 Typecho 更新到 1.2.1 版本后还出现了一个小 BUG Joe 主题的知名度很高,所以在原作者停止维护后很多大佬发布过自己魔改的版本,不可否认魔改后的主题 BUG…