您当前的位置:首页 > 电脑百科 > 程序开发 > 算法

算法一看就懂之「 堆栈 」

时间:2019-09-17 10:34:18  来源:  作者:
算法一看就懂之「 堆栈 」

 

上一篇咱们聊完了数据结构中最基础的「 数组 」和「 链表 」,今天咱们再来继续看看「 堆栈 」吧,我写技术文章很少 show code,所以经常有人吐槽。好吧,这个算法系列的文章我打算每一篇的结尾处都找一道算法题写出代码示例,这总可以了吧。

一、「 堆栈 」是什么?

堆栈(stack)是一种先进后出的、操作受限的线性表,也可以直接称为 

算法一看就懂之「 堆栈 」

 

可以把栈想象成一个桶一样,往这个桶里面一层一层的放东西,先放进去的在里面,后放进去的东西依次在外面。但取东西的时候就是先取靠近外面的,再依次一层层取里面的。这就是 后进先出( Last In-First Out )的原则。

因此「 栈 」虽然是线性的,有2个端:顶端和底端,但它只允许从一端进行插入和删除数据,这就是为啥前面说「 栈 」是操作受限的了。

只有两种操作:Push 和 Pop 。我们用Push(压入)来表示往栈中插入数据,也叫入栈,用Pop(弹出)来表示从栈中删除数据,也叫出栈。我们可以既可以用 「 数组 」 来实现一个栈,也可以用 「 链表 」 来实现一个栈。

  • 用数组实现的栈,叫做 顺序栈
  • 顺序栈的实现非常简单,这里就不写代码了,写一下思路。先初始化一个数组,然后再用一个变量给这个数组里的元素进行计数,当有新元素需要入栈的时候,将这个新元素写入到数组的最后一个元素的后面,然后计数器加一。当需要做出栈操作时,将数组中最后一个元素返回,计数器减一。
  • 当然在入栈前需要判断数组是否已经满了,如果数组大小等于计数器大小,则表明数组是满的。
  • 出栈的时候也需要判断数组是不是空数组,如果计数器是0,则表明数组是空的。
  • 从上面的实现流程可以看出,通过数组实现的栈,其入栈和出栈都是对单个元素进行操作,因此其入栈和出栈的时间复杂度都是O(1),并且其入栈和出栈操作并没有额外开销更多空间,因此其空间复杂度也是O(1)的。
  • 用链表实现的栈,叫做 链式栈
  • 实现思路是先定义一个链表节点的类,基于这个类去定义一个头节点Head。当有新元素需要入栈的时候,将这个新元素的Next指针指向头结点Head的Next节点,然后再将Head的Next指向这个新节点。当需要做出栈操作时,直接将Head所指向的节点返回,同时让Head指向下一个节点。
  • 当然,在入栈和出栈时都需要判断链表是否为空的情况。
  • 链式栈的入栈和出栈都是在处理头部节点,所以操作很简单,其时间和空间复杂度均为O(1)。

二、「 堆栈 」的算法实践?

我们来看一个基于用  来完成的 算法题(来源leetcode)

算法题:给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
 左括号必须用相同类型的右括号闭合。
 左括号必须以正确的顺序闭合。
举例:字符串 "()"有效、"()[]{}"有效、"(]"无效、"([)]"无效、"{[]}"有效。
解题思路:
使用1个堆栈即可解决,依次遍历这个字符串,如果遇到是左括号就入栈到堆栈中,如果遇到的是右括号,则从堆栈中取出栈顶的第一个左括号,比对一下这个左括号和当前遇到的右括号是否匹配,如果不匹配这认为这整个字符串无效。如果能匹配,则OK,删除这个左括号和右括号,继续往后走,继续遍历字符串中剩下的字符,只要遇到左括号就入栈,只要遇到右括号就与将栈顶的左括号出栈与之比较。一直走到字符串结束,再来检查堆栈中是否还有元素,如果还有元素,则这个字符串同样无效,如果堆栈为空,则字符串有效。
就以这个思路实现一个初版代码:
class Solution {
 public boolean isValid(String s) {
 Stack<Character> satck = new Stack<Character>();
 for(int i=0; i<s.length();i++){
 char c = s.charAt(i);
 if(c=='(' || c=='{' || c=='['){
 satck.push(c);
 }else{
 if(satck.isEmpty()) return false;
 char temp = satck.pop();
 if( (temp=='('&&c==')') || (temp=='{'&&c=='}') || (temp=='['&&c==']') ){
 continue;
 }else{
 return false;
 }
 }
 }
 return satck.isEmpty();
 }
}
这个代码的时间复杂度o(n),空间复杂度o(n)搞定。
但是想了想,好像代码不是很优雅,写了一个优化版,提前将左右括号放入到MAP中,这个方法的时间和空间复杂度跟上面的一样。
class Solution {
 public boolean isValid(String s) {
 Stack<Character> stack = new Stack<Character>();
 HashMap<Character,Character> map = new HashMap<Character,Character>();
 map.put('(', ')');
 map.put('{','}' );
 map.put('[', ']');
 for(int i=0;i<s.length();i++){
 char c = s.charAt(i);
 if(map.containsKey(c)){
 stack.push(c);
 }else{
 if(stack.isEmpty()) return false;
 char temp = stack.pop();
 if(map.get(temp)!=c) return false;
 }
 } 
 return stack.isEmpty();
 }
}
继续思考有没有更简洁的方法,竟然在leetcode上找到了一个:
但是这个方法并没有用到堆栈哦,它的思路是不断的遍历这个字符串,将字符串中的(){}[]全部调换成空字符串,如果最后全部替换完成了,并且字符串为空了,就说明字符串是有效的,否者就是无效的字符串。
class Solution {
 public boolean isValid(String s) {
 int length = s.length();
 do{
 length = s.length();
 s = s.replaceAll("\(\)","").replaceAll("\{\}","").replaceAll("\[\]","");
 }while(s.length()!=length);
 return s.length()==0;
 }
}
不过这个方法的时间复杂度要高一些。

以上,就是对数据结构中「 堆栈 」的一些思考。

码字不易啊,喜欢的话不妨转发朋友,或点击文章右下角的“在看”吧。

本文原创发布于微信公众号「 不止思考 」,欢迎关注。涉及 思维认知、个人成长、架构、大数据、Web技术 等。



Tags:堆栈   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
上一篇咱们聊完了数据结构中最基础的「 数组 」和「 链表 」,今天咱们再来继续看看「 堆栈 」吧,我写技术文章很少 show code,所以经常有人吐槽。好吧,这个算法系列的文章我打...【详细内容】
2019-09-17  Tags: 堆栈  点击:(131)  评论:(0)  加入收藏
▌简易百科推荐
前言Kafka 中有很多延时操作,比如对于耗时的网络请求(比如 Produce 是等待 ISR 副本复制成功)会被封装成 DelayOperation 进行延迟处理操作,防止阻塞 Kafka请求处理线程。Kafka...【详细内容】
2021-12-27  Java技术那些事    Tags:时间轮   点击:(1)  评论:(0)  加入收藏
博雯 发自 凹非寺量子位 报道 | 公众号 QbitAI在炼丹过程中,为了减少训练所需资源,MLer有时会将大型复杂的大模型“蒸馏”为较小的模型,同时还要保证与压缩前相当的结果。这就...【详细内容】
2021-12-24  量子位    Tags:蒸馏法   点击:(11)  评论:(0)  加入收藏
分稀疏重建和稠密重建两类:稀疏重建:使用RGB相机SLAMOrb-slam,Orb-slam2,orb-slam3:工程地址在: http://webdiis.unizar.es/~raulmur/orbslam/ DSO(Direct Sparse Odometry)因为...【详细内容】
2021-12-23  老师明明可以靠颜值    Tags:算法   点击:(7)  评论:(0)  加入收藏
1. 基本概念希尔排序又叫递减增量排序算法,它是在直接插入排序算法的基础上进行改进而来的,综合来说它的效率肯定是要高于直接插入排序算法的;希尔排序是一种不稳定的排序算法...【详细内容】
2021-12-22  青石野草    Tags:希尔排序   点击:(6)  评论:(0)  加入收藏
ROP是一种技巧,我们对execve函数进行拼凑来进行system /bin/sh。栈迁移的特征是溢出0x10个字符,在本次getshell中,还碰到了如何利用printf函数来进行canary的泄露。ROP+栈迁移...【详细内容】
2021-12-15  星云博创    Tags:栈迁移   点击:(22)  评论:(0)  加入收藏
一、什么是冒泡排序1.1、文字描述冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地...【详细内容】
2021-12-15    晓掌柜丶韶华  Tags:排序算法   点击:(16)  评论:(0)  加入收藏
在了解golang的map之前,我们需要了解哈希这个概念。哈希表,又称散列表(Hash table),是根据键(key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算出一个键值的函数,将...【详细内容】
2021-12-07  一棵梧桐木    Tags:哈希表   点击:(14)  评论:(0)  加入收藏
前面文章在谈论分布式唯一ID生成的时候,有提到雪花算法,这一次,我们详细点讲解,只讲它。SnowFlake算法据国家大气研究中心的查尔斯&middot;奈特称,一般的雪花大约由10^19个水分子...【详细内容】
2021-11-17  小心程序猿QAQ    Tags:雪花算法   点击:(24)  评论:(0)  加入收藏
导读:在大数据时代,对复杂数据结构中的各数据项进行有效的排序和查找的能力非常重要,因为很多现代算法都需要用到它。在为数据恰当选择排序和查找策略时,需要根据数据的规模和类型进行判断。尽管不同策略最终得到的结果完...【详细内容】
2021-11-04  华章科技    Tags:排序算法   点击:(40)  评论:(0)  加入收藏
这是我在网上找的资源的一个总结,会先给出一个我看了觉得还行的关于算法的讲解,再配上实现的代码: Original author: Bill_Hoo Original Address: http://blog.sina.com.cn/s/bl...【详细内容】
2021-11-04  有AI野心的电工和码农    Tags: KMP算法   点击:(36)  评论:(0)  加入收藏
相关文章
    无相关信息
最新更新
栏目热门
栏目头条