數據結構基礎--棧和隊列

目錄

  • 基本性質
  • 棧和隊列的基本操作
  • 雙端隊列和優先級隊列
  • 深度優先遍歷(DFS)和廣度優先遍歷(BFS)
  • 遞歸函數與系統函數棧
  • 實現一個特殊的棧,在實現棧的基本功能的基礎上,再實現返回棧中最小元素的操作
    • 如何保存最小值
  • 僅用棧結構實現隊列結構
    • 如何保證棧結構能夠先進先出
    • 何時進行傾倒操作
  • 僅用隊列結構實現棧結
  • 實現一個棧的逆序,不能申請額外的數據結構,只能使用棧本身的功能
    • 移除棧底元素,並將其返回
  • 將棧中的元素排序

基本性質

  • 棧---先進後出
  • 隊列---先進先出
  • 棧和隊列通常都有數組和鏈表兩種實現方式

數組相對容易,鏈表需要進行一些指針操作


棧和隊列的基本操作

  • pop操作

彈出棧頂元素

  • top或peek操作

只訪問而不彈出棧頂元素

  • push操作

從棧頂壓入一個元素

  • size操作

返回當前棧中元素個數

對於隊列,push是在隊列頭部加入一個元素,pop是在尾部彈出一個元素。

棧和隊列的基本操作,時間複雜度都是O(1) 。


雙端隊列和優先級隊列

  • 雙端隊列

首尾都可以壓入和彈出元素

  • 優先級隊列

彈出時,根據元素的優先級決定彈出的順序。
具體實現上爲一個堆結構,而不是線性表結構。


深度優先遍歷(DFS)和廣度優先遍歷(BFS)

  • 深度優先遍歷(前序遍歷)。使用棧的結構

先嚐試將左元素入棧,若棧頂元素爲空則將棧頂推出然後嘗試遍歷右節點。直到棧爲空則遍歷結束。

func preorderTraversal(root: TreeNode?) -> [Int] {
  var res = [Int]()
  var stack = [TreeNode]() //遍歷用的棧
  var node = root//遍歷的根節點

  while !stack.isEmpty || node != nil {
    if node != nil {
      res.append(node!.val)  //將當前節點的值記錄
      stack.append(node!) //將當前節點加入棧中
      node = node!.left //嘗試遍歷當前節點的左節點
    } else {
      node = stack.removeLast().right  //將棧頂節點推出,並嘗試遍歷其父元素的右節點。
    }
  }

  return res
}

遍歷的結果爲:1,2,4,5,3,6,7

  • 廣度優先遍歷。使用隊列結構

從root節點開始依次入隊,當從隊列推出一個元素時,嘗試將其兩個子元素依次加入加入隊列。直到隊列爲空遍歷結束。

遍歷的結果爲:1,2,3,4,5,6,7


遞歸函數與系統函數棧

平時使用的遞歸函數實際上是有系統負責向系統函數棧中進行壓棧
遞歸過程可以看作是遞歸函數依次進入函數棧的處理過程
所有用遞歸函數可以做的過程,都可以用非遞歸的方式實現。


實現一個特殊的棧,在實現棧的基本功能的基礎上,再實現返回棧中最小元素的操作

【要求】

  1. pop、push、getMin操作的時間複雜度都是O(1)。
  2. 設計的棧類型可以使用現成的棧結構。

如何保存最小值
需要兩個棧,StackData以及StackMin。StackData負責正常壓棧,StackMin負責記錄當前最小值。
當進行push操作時,當前元素與StackMin棧頂元素進行比較,將較小的數壓入StackMin。

當進行pop操作時,StackData以及StackMin同時進行pop。
當進行getmin操作時,由StackMin負責進行peek。

時間複雜度爲O(1),額外空間複雜度爲O(N)


僅用棧結構實現隊列結構

需要兩個棧結構實現。一個棧作爲壓入棧(StackPush)負責承接push元素,一個棧作爲彈出棧(StackPop)負責彈出pop元素。

  • 如何保證棧結構能夠先進先出

通過將StackPush的數據倒入StackPop中,來將StackPush中數據的順序顛倒,保證先進先出。

這個傾倒操作需要有兩個注意的點:

  1. StackPop棧爲空。
  2. 每次需要將StackPush棧所有的數據全部倒入StackPop棧
  • 何時進行傾倒操作

當任何StackPush或者StackPop棧內的數據改變時,可以嘗試傾倒操作。


僅用隊列結構實現棧結

需要兩個隊列實現。
當進行pop操作時,將當前使用的CurrentQueue中元素推入輔助隊列HelpQueue,僅保留隊尾元素返回給用戶。
然後將CurrentQueue與HelpQueue的指針互換,保證push操作時,CurrentQueue始終爲有內容的隊列。


實現一個棧的逆序,不能申請額外的數據結構,只能使用棧本身的功能

  • 移除棧底元素,並將其返回

通過遞歸的方式,每層保存相應的棧頂元素。獲取到棧底元素後再依次壓入棧中

/// 移除棧底元素,並將其返回
///
/// - Parameter stack: 棧
/// - Returns:棧底元素
func getLast(stack : Stack) -> Int {
    let value = stack.pop() //獲得當前棧頂元素
    if stack.isEmpty() { //如果棧爲空
        return value //當前元素則爲棧底元素
    }else {
        let last = getLast(stack)
        stack.push(value)
        return last
    }
}

將棧中的元素排序

【要求】

  1. 值允許申請一個棧
  2. 可以申請變量
  3. 不能申請額外的數據結構

原棧爲stack,輔助棧爲help。
從stack棧中pop出來的元素計作current
若current小於help棧頂元素,則直接壓入棧中。
若current大於help棧頂元素,則將help棧頂推出並壓入stack。
重複,直到stack中元素爲0。然後將help倒回給stack


參考資料

左神牛課網算法課

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章