Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

精通 Ruby Stacks:新手實用資料結構技巧

如果你沒有 CS(電腦科學)學位,你可能覺得錯過了什麼……

或者你覺得 CS 太抽象不實用……

或者 Ruby 已經幫你做完所有苦工……

無論如何……

了解資料結構基礎像雜湊、stacks 和 queues 是有幫助的。

這篇文章:

你將發現如何在 Ruby 使用 stacks。

一個你現在就能開始實踐的實用電腦科學概念!

理解 Ruby 中的 Stacks

Ruby 中的 stack 是什麼?

Stack 是一個資料結構,你可以當作「待辦事項」清單用。你不斷從 stack 取元素並處理,直到 stack 空了。

這裡是視覺化表示。

Push 5 進空 stack:

5

Push 3 進 stack:

3
5

Push 9 進 stack:

9
3
5

從 stack 取一個項目:

3
5

要注意的重點是新項目加在 stack 的頂端。以「後進先出」(LIFO)方式。意思是當你取(pop)項目時,會是最後被 push 進去的項目。

另一種視覺化方式是想像一疊盤子。如果你把一個盤子疊在另一個上,不拿掉最上面的盤子就拿不出底下的盤子。

這就是 stack 全部在做的事,把東西推到頂端或彈出。沒有索引。

來看一些程式碼範例怎麼用。

如何用 Stack 攤平陣列

Stack 的經典例子是用它們攤平陣列。換句話說,把多維陣列轉成一維陣列。

例子:

 arr = [1,2,3,[4,5],6] arr.flatten 

在 Ruby 我們有 flatten 方法幫你做這事。但如果你沒有這個方法?這方法怎麼運作?

這就是 stack 派上用場的地方!

Ruby 實作了 push 和 pop 方法,所以我們可以把陣列當 stack 用。

注意:push 和 << 是同一個方法。我會在程式碼範例用 <<。

想法是遍歷每個元素檢查它是陣列還是其他東西。如果是陣列,我們把這陣列裡的元素 push 回 stack。

發生的事是我們不斷移除陣列層(像洋蔥)直到沒有為止。這留給我們攤平的陣列。

程式碼:

 arr = [1,2,3,[4,5],6] flat = [] arr.each do |thing| if thing.is_a? Array thing.each { |i| arr << i } else flat << thing end end p flat # [1, 2, 3, 6, 4, 5] 

你會注意到這程式碼沒有 pop 方法呼叫。

這是因為我讓 each 做從 stack 取項目並餵給演算法的苦工。也注意這樣做元素順序不保持。

另一個用 until 和 empty? 的版本:

 until arr.empty? thing = arr.pop if thing.is_a? Array thing.each { |i| arr << i } else flat << thing end end p flat # [6, 5, 4, 3, 2, 1] 

既然用 pop,不讓 each 做事,我們得到正確順序的攤平陣列... 但反轉了。

這揭示了 stack 的一個有趣屬性:

你放進去的任何東西清單,會以相同順序但反轉回來。

提示:Array#flatten 方法接受一個參數,讓你定義想移除多少層巢狀(預設全移除)。

解決平衡括號問題

這裡有另一個例子,Ruby 沒有對等方法幫你做!

這也是電腦科學的經典問題……

名字是:

配對平衡括號。

想法是給你一個字串,你需要驗證括號是否有效。

例如,假設你在寫數學評估程式。你想在處理前確保輸入有效。

例子(有效輸入):

 input = "1 + (4 + 6) * 2" 

例子(無效輸入):

 input = "1 + (4 + 6 * 2" 

你可以用 stack 追蹤在輸入中找到的任何括號,然後當你找到新括號時檢查 stack 頂端確保它符合閉合括號。

如果沒有匹配,代表輸入無效。

例子:

 PARENS = { "(" => ")", "{" => "}", "[" => "]" } OPENING_PARENS = PARENS.keys CLOSING_PARENS = PARENS.values def valid_parentheses(string) stack = [] string.each_char do |ch| if OPENING_PARENS.include?(ch) stack << ch elsif CLOSING_PARENS.include?(ch) ch == PARENS[stack.last] ? stack.pop : (return false) end end stack.empty? end p valid_parentheses("(){}[]") # true p valid_parentheses("[(])") # false 

另一件事你會注意到是我用 stack.empty? 結束 valid_parentheses 方法。那是為了確保我們不會以未閉合的括號結束。

如果所有括號都正確閉合,stack 應該是空的 🙂

範例 3(方向)

再一個例子確保你懂怎麼應用這個。

這種情況我們得到一組方向,被告知需要優化以節省旅行者時間。

這裡是範例集:

 ["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"] 

你會注意到如果你往北再往南會回到同樣地方(假設距離相同)。這就是我們要優化的,用 stack 可以做到。

例子:

 input = ["NORTH", "SOUTH", "SOUTH", "EAST", "WEST", "NORTH", "WEST"] directions = [] opposites = { "NORTH" => "SOUTH", "SOUTH" => "NORTH", "EAST" => "WEST", "WEST" => "EAST" } input.each do |dir| opposites[dir] == directions.last ? directions.pop : directions << dir end p directions 

結論

希望你學到新東西,開始找方法用 stacks 解決程式挑戰。

別忘了 分享這篇文章 讓更多人讀到!