栈:如何实现有效括号的判断?

    点击上方蓝字,关注:无量测试之道


   做者 | 无量测试之道
   编辑 | 小 晴


有效括号,刷过LeetCode的也许对这道题很熟悉。

1.开篇问题:有效的括号[1]

假如如今要你来解这道题,你会想到怎样的解法了?

这就要用到咱们今天要讲的“栈”这种数据结构。带着这个问题,咱们来学习今天的内容。

2.如何理解“栈”?

    关于栈,有一个很是贴切的游戏--汉诺塔。玩这个游戏的时候,咱们都是从下往上一个一个放;取的时候,咱们也是从上往下一个一个地依次取,不能从中间任意抽出。后进者先出,先进者后出,这就是典型的“栈”结构

从栈的操做特性上来看,栈是一种“操做受限”的线性表,只容许在一端插入和删除数据。
栈的定义[2]


    栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操做的线性表。这一端被称为栈顶,相对地,把另外一端称为栈底。向一个栈插入新元素又称做进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称做出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

3.如何实现栈

    从刚才栈的定义里,咱们能够看出,栈主要包含两个操做,入栈和出栈,也就是在栈顶插入一个数据和从栈顶删除一个数据。理解了栈的定义以后,咱们来看一看如何用代码实现一个栈。
  【本文使用   swift 语言来编写代码,读者朋友们不要由于编程语言不一样而有畏难情绪,重要的是思惟和逻辑,语言只是表达方式。你能够用你本身熟悉的语言来表达你的逻辑,能够先试着写一写】
Talking is cheap,show you the code.
  
  
   
   
            
   
   
class Stack {
//初始化数组
var datas = [Int]()
//出栈操做
func pop() -> Int? {
return datas.popLast()
}
//入栈操做
func push(obj: Int) {
datas.append(obj)
}
//栈顶对象
func top() -> Int? {
return datas.last
}
}


4.栈在实际开发过程当中的应用

  • 栈在函数调用中的应用python

  
  
   
   
            
   
   
func calculate() {
let a = 3
let b = 5
var result = 0
result = add(x: a, y: b)
print(result)
}

func add(x: Int, y: Int) -> Int {
var sum= 0
sum = x + y
return sum
}
    从代码中咱们能够看出,calculate() 函数调用了 add() 函数,传入临时变量a和b,获取计算结果,最后打印 result 的值。
    为了让你清晰地看到这个过程对应的函数栈里出栈、入栈的操做,我画了一张图。图中显示的是,在执行到 add() 函数时,函数调用栈的状况。
  • 递归算法

    在算法中,常常会使用的一个思想就是递归思想。很著名的就是斐波那契数列 [3]
F(0) =0,
F(1) =1,
F(n) = F(n-1)+F(n-2)(n≥2,n∈N*)
计算 F(n) 时须要先计算 F(n-1) F(n-2)
计算
F(n-1) 时须要先计算 F(n-2) F(n-3)
计算
F(n-2) 时须要先计算 F(n-2) F(n-3)
···
最后的效果是,会有不少中间值压入栈中,这也是为何,当
n 很大的时候,会很是消耗内存。因此在实际的开发中,掌握这些底层的开发基础,会有助你选择合适的技术方案。

5.概念区分:数据结构堆栈 VS 内存中的堆栈

    在学习计算机基础的时候,咱们知道内存中有栈区和堆区。那它与数据结构中的堆栈有什么区别了,它们是同一个概念吗?
    内存中的堆栈数据结构堆栈不是一个概念,能够说内存中的堆栈是真实存在的物理区,数据结构中的堆栈是抽象的数据存储结构。
    内存空间在逻辑上分为三部分:代码区、静态数据区和动态数据区,动态数据区又分为栈区和堆区。
    代码区:存储方法体的二进制代码。高级调度(做业调度)、中级调度(内存调度)、低级调度(进程调度)控制代码区执行代码的切换。
    静态数据区:存储全局变量、静态变量、常量,常量包括final修饰的常量和String常量。系统自动分配和回收。
    栈区:存储运行方法的形参、局部变量、返回值。由系统自动分配和回收。
    堆区:new一个对象的引用或地址存储在栈区,指向该对象存储在堆区中的真实数据。

6.解答开篇

    好了,我想如今你已经彻底理解了栈的概念。咱们再回来看看开篇的思考题,如何实现有效括号的判断?其实使用栈的思想就能够很是完美的解决这个问题。
咱们开始分析:
  • 1.若是开始就是右括号 )、]、} ,很明显不合法,直接返回false
  • 2.若是是左括号  (、[、{ ,就压栈。若是是右括号 )、]、} ,在stack有值的状况下与栈顶元素匹配,匹配经过则栈顶元素出栈,不然直接返回false。
下面是 swift 解题的实现代码
  
  
   
   
            
   
   
class Solution {

func isValid(_ s: String) -> Bool {

if s.count == 0 { return false }
var stack = [String]()
let dict: [String:String] = ["(":")","[":"]","{":"}"]

for c in s {
if dict.keys.contains(c.description) {
stack.append(c.description) //若是是左括号就入栈
}else {
if stack.count > 0 && c.description == dict[stack.last!] { //若是是右括号,而且匹配就出栈
stack.removeLast()
}else {
return false
}
}
}
return stack.count == 0
}
}
在LeetCode上也有不少种语言的解法,这里分享一个python [4] 的解法

7.内容总结

    咱们来回顾一下今天讲的内容。栈是一种操做受限的数据结构,只支持入栈和出栈操做。后进先出是它最大的特色。咱们还知道数据结构中的堆栈和内存中的堆栈不是同一个概念。咱们也理解了栈在实际开发中的些应用,以及使用递归,当 n 值很大地时候,会有大量的临时变量被压如栈中而消耗内存。以及最后经过栈的核心思想来解LeetCode中比较经典的算法题。
    相信你也真正的掌握了栈这种数据结构了。那赶忙动手敲代码来实践吧!

参考资料:

  • 1.有效的括号:
    https://leetcode-cn.com/problems/valid-parentheses

  • 2.栈的定义:编程

    https://baike.baidu.com/item/%E6%A0%88/12808149?fr=aladdinswift



  • 3.斐波那契数列:数组

    https://baike.baidu.com/item/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97/99145?fr=aladdin 微信


  • 4.python语言实现:数据结构

    https://leetcode-cn.com/problems/valid-parentheses/solution/valid-parentheses-fu-zhu-zhan-fa-by-jin407891080/app

若是今天的分享对你有帮助的话,请坚决果断:分享、点赞、在看、收藏呀~
你的鼓励将会是我创做的最大动力。
编程语言


Python 经典算法之 “ 选择排序 ”
Python 之“栈为什么物”
Python 算法之一

点个赞,点个在看再走吧~~~编辑器


本文分享自微信公众号 - 无量测试之道(gh_858a1aa25a6d)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索