棧:如何實現有效括號的判斷?

    點擊上方藍字,關注:無量測試之道


   做者 | 無量測試之道
   編輯 | 小 晴


有效括號,刷過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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索