日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

算法动画图解 | 被 “废弃“ 的 Java 栈,为什么还在用

發(fā)布時間:2024/8/1 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法动画图解 | 被 “废弃“ 的 Java 栈,为什么还在用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

公眾號:ByteCode,致力于分享最新技術(shù)原創(chuàng)文章,涉及 Kotlin、Jetpack、譯文、系統(tǒng)源碼、 LeetCode / 劍指 Offer / 多線程 / 國內(nèi)外大廠算法題 等等一系列文章。

在 LeetCode 上不知不覺已經(jīng)刷了 210+ 題,總提交次數(shù) 1000+ 次,從這篇文章開始,每篇算法類型的文章,將會做成動畫的形式,每篇文章都會用 Java 和 kotlin 去實(shí)現(xiàn),并且每道題目都有解題思路、時間復(fù)雜度、空間復(fù)雜度和源代碼,更多內(nèi)容點(diǎn)擊下方鏈接前去查看。

  • 劍指 Offer 及國內(nèi)外大廠面試題解:在線閱讀
  • LeetCode 系列題解:在線閱讀

通過這篇文章你將學(xué)習(xí)到以下內(nèi)容:

  • 棧的定義
  • 棧的實(shí)現(xiàn)
    • 為什么不推薦使用 Java 棧
      • 性能低
      • 破壞了原有的數(shù)據(jù)結(jié)構(gòu)
    • 不推薦使用了,為什么現(xiàn)在還在用
    • 為什么推薦使用 Deque 接口替換棧
      • 效率比 Java ???/li>
      • 屏蔽掉無關(guān)的方法
    • Stack 和 ArrayDeque 區(qū)別
    • 棧的時間復(fù)雜度
  • 棧的應(yīng)用:有效的括號

棧的定義

棧是 后入先出(LIFO) 的數(shù)據(jù)結(jié)構(gòu),入棧通常使用 push 操作,往棧中插入數(shù)據(jù)到棧底,出棧使用 pop 操作,從棧頂刪除數(shù)據(jù)。入棧和出棧操作動畫如下所示。

棧的實(shí)現(xiàn)

棧常用的實(shí)現(xiàn)方式是通過動態(tài)數(shù)組來實(shí)現(xiàn)的,在 Java 和 Kotlin 中也內(nèi)置了棧庫 Stack,但是 Stack 已經(jīng)不推薦使用了。

為什么不推薦使用

  • 性能低

性能低是因?yàn)?Stack 繼承自 Vector, 而 Vector 在每個方法中都加了鎖,如下所示:

...... public synchronized void trimToSize() { }public synchronized void ensureCapacity(int minCapacity) { }public synchronized void setSize(int newSize) { }public synchronized int capacity() { }public synchronized int size() { }public synchronized boolean isEmpty() { } ......

由于需要兼容老的項(xiàng)目,很難在原有的基礎(chǔ)上進(jìn)行優(yōu)化,因此 Vector 就被淘汰掉了,使用 ArrayList 和 CopyOnWriteArrayList 來代替,如果在非線程安全的情況下可以使用 ArrayList,線程安全的情況下可以使用 CopyOnWriteArrayList 。

  • 破壞了原有的數(shù)據(jù)結(jié)構(gòu)

棧的定義是在一端進(jìn)行 push 和 pop 操作,除此之外不應(yīng)該包含其他 入棧和出棧 的方法,但是 Stack 繼承自 Vector,使得 Stack 可以使用父類 Vector 公有的方法,如下所示。

val stack = Stack<Int>() stack.push(6) stack.add(1,10) stack.removeAt(1) stack.pop() stack.addAll(arrayListOf()) ......

正如你所見,除了調(diào)用 push() 和 pop() 方法之外,還可以調(diào)用 addXXX() 、 removeXXX() 等等方法,但是這樣會破壞棧原有的結(jié)構(gòu)。所以對于棧的數(shù)據(jù)結(jié)構(gòu),不應(yīng)該有可以在任何位置添加或者刪除元素的能力。

為什么現(xiàn)在還在用

但是為什么在實(shí)際項(xiàng)目中還有很多小伙伴在使用 Stack。如果你經(jīng)常刷 LeetCode 應(yīng)該會見到很多小伙伴使用 Stack 做相關(guān)的算法題??偨Y(jié)了一下主要有兩個原因。

  • JDK 官方是不推薦使用 Stack,之所以還有很多人在使用,是因?yàn)?JDK 并沒有加 deprecation 注解,只是在文檔和注釋中聲明不建議使用,但是很少有人會去關(guān)注其實(shí)現(xiàn)細(xì)節(jié)
  • 在做算法題的時候,關(guān)注點(diǎn)在解決問題的算法邏輯思路上,并不會關(guān)注在不同語言下 Stack 實(shí)現(xiàn)細(xì)節(jié),但是對于使用 Java 語言的開發(fā)者,不僅需要關(guān)注算法邏輯本身,也需要關(guān)注它的實(shí)現(xiàn)細(xì)節(jié)

為什么推薦使用 Deque 接口替換棧

如果 JDK 不推薦使用 Stack,那應(yīng)該使用什么集合類來替換棧,一起看看官方的文檔。

正如圖中標(biāo)注部分所示,棧的相關(guān)操作應(yīng)該由 Deque 接口來提供,推薦使用 Deque 這種數(shù)據(jù)結(jié)構(gòu), 以及它的子類,例如 ArrayDeque。

val stack: Deque<Int> = ArrayDeque()

使用 Deque 接口來實(shí)現(xiàn)棧的功能有什么好處:

  • 速度比 Stack 快

這個類作為棧使用時可能比 Stack 快,作為隊列使用時可能比 LinkedList 快。因?yàn)樵瓉淼?Java 的 Stack 繼承自 Vector,而 Vector 在每個方法中都加了鎖,而 Deque 的子類 ArrayDeque 并沒有鎖的開銷。

  • 屏蔽掉無關(guān)的方法

原來的 Java 的 Stack,包含了在任何位置添加或者刪除元素的方法,這些不是棧應(yīng)該有的方法,所以需要屏蔽掉這些無關(guān)的方法。

聲明為 Deque 接口可以解決這個問題,在接口中聲明棧需要用到的方法,無需管子類是如何是實(shí)現(xiàn)的,對于上層使用者來說,只可以調(diào)用和棧相關(guān)的方法。

Stack 和 ArrayDeque 區(qū)別如下所示。

集合類型數(shù)據(jù)結(jié)構(gòu)是否線程安全
Stack數(shù)組
ArrayDeque數(shù)組

Stack 常用的方法如下所示。

操作方法
入棧push(E item)
出棧pop()
查看棧頂peek() 為空時返回 null

ArrayDeque 常用的方法如下所示。

操作方法
入棧push(E item)
出棧poll() 棧為空時返回 null
pop() 棧為空時會拋出異常
查看棧頂peek() 為空時返回 null

棧的時間復(fù)雜度

棧的核心實(shí)現(xiàn)是通過動態(tài)數(shù)組來實(shí)現(xiàn)的,所以在擴(kuò)容的時候,時間復(fù)雜度為 O(n),其他操作例如 push(E item) 和 pop() 、 peek() 等等時間復(fù)雜度為 O(1)。

棧的應(yīng)用:有效的括號

題解已收藏于 https://github.com/hi-dhl/Leetcode-Solutions-with-Java-And-Kotlin。每道題目都會用 Java 和 kotlin 去實(shí)現(xiàn),并且每道題目都有解題思路、時間復(fù)雜度、空間復(fù)雜度和源代碼,

題目描述

給定一個字符串, 只包括 ‘(’,’)’,’{’,’}’,’[’,’]’,判斷字符串是否有效

有效字符串需要滿足以下條件:

  • 左括號必須用相同類型的右括號閉合
  • 左括號必須以正確的順序閉合

注意空字符串可被認(rèn)為是有效字符串。

Example 1:Input: "()"Output: trueExample 2:Input: "()[]{}"Output: trueExample 3:Input: "(]"Output: falseExample 4:Input: "([)]"Output: falseExample 5:Input: "{[]}"Output: true

算法流程

  • 如果遇到左括號,將對應(yīng)的右括號壓入棧中
  • 如果遇到右括號
    • 判斷當(dāng)前棧是否為空
    • 如果不為空,判斷當(dāng)前元素是否和棧頂元素相等
    • 如果不相等,發(fā)現(xiàn)了不符合的括號,提前返回 false,結(jié)束循環(huán)
  • 重復(fù)執(zhí)行「步驟 1」 和「步驟 2」
  • 循環(huán)結(jié)束之后,通過判斷棧是否為空,來檢查是否是有效的括號
  • 復(fù)雜度分析

    假設(shè)字符串的長度為 N 則:

    • 時間復(fù)雜度:O(N)。正確有效的括號需要遍歷了一次字符串,所需要的時間復(fù)雜度為 O(N)。
    • 空間復(fù)雜度:O(N)。如果輸入字符串全是左括號,例如 (((((((,棧的大小即為輸入字符串的長度,所需要的空間復(fù)雜度為 O(N)

    Kotlin 實(shí)現(xiàn)

    class Solution {fun isValid(s: String): Boolean {val stack = ArrayDeque<Char>()// 開始遍歷字符串for (c in s) {when (c) {// 遇到左括號,將對應(yīng)的右括號壓入棧中'(' -> stack.push(')')'[' -> stack.push(']')'{' -> stack.push('}')else -> {// 遇到右括號,判斷當(dāng)前元素是否和棧頂元素相等,不相等提前返回,結(jié)束循環(huán)if (stack.isEmpty() || stack.poll() != c) {return false}}}}// 通過判斷棧是否為空,來檢查是否是有效的括號return stack.isEmpty()} }

    Java 實(shí)現(xiàn)

    class Solution {public boolean isValid(String s) {Deque<Character> stack = new ArrayDeque<Character>();// 開始遍歷字符串for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);// 遇到左括號,則將其對應(yīng)的右括號壓入棧中if (c == '(') {stack.push(')');} else if (c == '[') {stack.push(']');} else if (c == '{') {stack.push('}');} else {// 遇到右括號,判斷當(dāng)前元素是否和棧頂元素相等,不相等提前返回,結(jié)束循環(huán)if (stack.isEmpty() || stack.poll() != c) {return false;}}}// 通過判斷棧是否為空,來檢查是否是有效的括號return stack.isEmpty();} }

    倉庫 KtKit 是用 Kotlin 語言編寫的小巧而實(shí)用的工具庫,包含了項(xiàng)目中常用的一系列工具, 正在逐漸完善中。

    • KtKit 倉庫地址:https://github.com/hi-dhl/KtKit
    • KtKit 在線閱讀:https://ktkit.hi-dhl.com

    如果這個倉庫對你有幫助,請在倉庫右上角幫我 star 一下,非常感謝你的支持,同時也歡迎你提交 PR


    如果有幫助 點(diǎn)個贊 就是對我最大的鼓勵

    代碼不止,文章不停

    歡迎關(guān)注公眾號:ByteCode,持續(xù)分享最新的技術(shù)



    最后推薦我一直在更新維護(hù)的項(xiàng)目和網(wǎng)站:

    • 個人博客,將所有文章進(jìn)行分類,歡迎前去查看 https://hi-dhl.com

    • 計劃建立一個最全、最新的 AndroidX Jetpack 相關(guān)組件的實(shí)戰(zhàn)項(xiàng)目 以及 相關(guān)組件原理分析文章,正在逐漸增加 Jetpack 新成員,倉庫持續(xù)更新,歡迎前去查看:AndroidX-Jetpack-Practice

    • LeetCode / 劍指 offer / 國內(nèi)外大廠面試題 / 多線程 題解,語言 Java 和 kotlin,包含多種解法、解題思路、時間復(fù)雜度、空間復(fù)雜度分析

      • 劍指 offer 及國內(nèi)外大廠面試題解:在線閱讀
      • LeetCode 系列題解:在線閱讀
    • 最新 Android 10 源碼分析系列文章,了解系統(tǒng)源碼,不僅有助于分析問題,在面試過程中,對我們也是非常有幫助的,倉庫持續(xù)更新,歡迎前去查看 Android10-Source-Analysis

    • 整理和翻譯一系列精選國外的技術(shù)文章,每篇文章都會有譯者思考部分,對原文的更加深入的解讀,倉庫持續(xù)更新,歡迎前去查看 Technical-Article-Translation

    總結(jié)

    以上是生活随笔為你收集整理的算法动画图解 | 被 “废弃“ 的 Java 栈,为什么还在用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。