戀上數據結構與算法(精簡版)

標題解析

經過標題就知道當前文檔的學習來自哪裏,挺棒的學習資源,學習以後受益不淺。
Pascal 之父 Nicklaus Wirth 憑藉一個公式得到了圖靈獎:算法 + 數據結構 = 程序。node

0x00 複雜度

用於衡量其算法:正確性、可讀性、健壯性(對不合理輸入的反應能力與處理能力)。
時間複雜度(time complexity):估算程序指令的執行次數(執行時間)
空間複雜度(space complexity):估算所需佔用的存儲空間算法

因此咱們在敲代碼的時候,須要有複雜度的考慮,不以結果而結果。好比 斐波那契數列 的算法能夠是如下三種實現:數據庫

/// 斐波那契數列 -> 遞歸
func fib_recarsive(data:Int) -> Int {
    if data <= 1 {
        return data
    }
    return fib_recarsive(data: (data-1)) + fib_recarsive(data: (data-2))
}

/// 斐波那契數列 -> 優化
func fib_optimize(data:Int) -> Int {
    if data <= 1 {
        return data
    }
    
    var first = 0
    var second = 1
    for _ in 0...(data-2) {
        let sum = first + second
        first = second
        second = sum
    }
    
    return second
}

/// 斐波那契數列 -> 優化 (減小了一個變量的開銷)
func fib_optimize_best(data:Int) -> Int {
    if data <= 1 {
        return data
    }
    
    var first = 0
    var second = 1
    
    // Swift 能夠這麼玩
    var data = data
    
    repeat {
        second += first
        first = second - first
        data -= 1
    } while data > 1
    
    return second
}
複製代碼

以上三種方式都能實現 斐波那契數列, 可是其執行效率以下所示:數組

圖中的結論是經過自定義 Instruments 實現,更多細節能夠參考:Xcode 中自定義 Instruments瀏覽器

經過圖中顯示,使用遞歸是效率最低的,在相同條件下使用了 5.48s,而另外兩種實現都不到 1s 的時間。bash

0x01 動態數組(Array)

數組、一個很常規的線性數據結構。在數組中又分紅兩種,好比 OC 中有不可變數組與可變數組。這裏所談到的動態數組的實現,相似可變數組。故須要考慮這些方面的實現:數據結構

  • 一、元素數量
  • 二、是否爲空
  • 三、是否包含
  • 四、設置/添加元素(末尾與指定的 index)
  • 五、刪除元素
  • 六、查看與清空元素

在實現動態數組的過程當中,須要考慮的是 擴/縮容 與及 添加/刪除時元素位置移動 的問題。post

0x02 鏈表(Link)

與數組相似、也是線性數據結構,其優勢是節省內存空間、不像數組須要有預留內存空間。性能

  • 一、單項鍊表
  • 二、雙向鏈表 相關實現接口與動態數組相似。

0x03 棧(Stack)

相對特殊的線性結構,僅在一端(棧頂)進行操做。學習

  • 一、添加元素:入棧(push)
  • 二、移除元素:出站(pop)、彈出頂端元素
  • 三、獲取頂端元素(不出棧):top

原則:後進先出(Last In First Out、LIFO)
內部實現能夠藉助:鏈表與動態數組。
應用場景: 瀏覽器前進/後退、撤銷/後退、括號有效性判斷、逆波蘭表示法、等等。

0x04 隊列(Queue)

只能在 頭尾 兩端進行操做。

  • 一、隊尾(rear):添加元素、叫入隊(enQueue)
  • 二、對頭(front):移除元素、叫出隊(deQueue)

原則:先進先出(First In First Out, FIFO)
內部實現能夠藉助:鏈表與動態數組。
思考:用棧實現隊列,準備兩個棧(inStack、outStack)

雙端隊列(deque = double ended queue): 能在頭尾 添加/刪除
循環隊列: 使用動態數組方可實現,添加一個對頭指針(front)。
循環雙端隊列: 兩端能夠進行添加/刪除的循環隊列。

0x05 樹

概念(一)

節點、根節點、父節點、子節點、兄弟節點與子樹、左子樹、右子樹。
節點的度(degree):子樹的個數
樹的度:全部節點度中的最大值
葉子節點(leaf):度爲 0 的節點
非葉子節點:度 > 0 的節點

概念(二)

層數(level):根節點在第一層,跟節點的子節點在第二層,以此類推
節點的深度(depth):從跟節點到當前節點的惟一節點總數
節點的高度(height):從當前節點到最遠葉子節點的路勁上的節點數
樹的深度:全部節點深度中的最大值
樹的高度:全部節點高度的最大值
樹的深度 = 樹的高度

概念(三)

有序樹
無需樹、也稱 自由樹
森林

0x06 二叉樹(Binary Tree)

特色:有序樹、節點的度最大爲 2(左子樹與右子樹)、即便只有一個子樹也須要區分左右子樹。
真二叉樹(Proper Binary Tree): 全部節點的度,要麼爲 0、要麼爲 2。
滿二叉樹(Full Binary Tree): 最後一層節點的度都爲 0,其它節點度都爲 2。

滿二叉樹必定是真二叉樹,一樣高度的二叉樹中,滿二叉樹的節點最多。

徹底二叉樹(Complete Binary Tree): 對節點從上至下、從左至右開始編號,其全部編號都能與滿二叉樹對應。

度爲 1 的節點只有左子樹
度爲 1 的節點,要麼有 1 個、要麼是 0 個
一樣節點數量的二叉樹、徹底二叉樹的高度最小
二叉樹的高度爲 h(h>1),節點數爲[2h-1, 2h -1]
總節點數爲 n,則:2h-1 ≤ n < 2h,h-1 ≤ \log_2 n < h,h = floor(\log_2 n) + 1
i 爲節點編號、i=1 爲根節點,若是 i>1,父節點編號爲 floor(i/2),若是 2i ≤ 它的左子節點編號爲 2i,若是 2i > n 則沒有左子節點,若是 2i+1 ≤ n 則右子節點編號爲 2i+1,2i+1 > n 則無由子節點
公式:n0 = n2 + 1

遍歷(Traversal): 把全部數據結構中的元素都訪問一遍。
線性遍歷:正序與逆序。
二叉樹遍歷:
前序(Preorder):根、左、右
中序(Inorder):左、根、右
後序(Postorder):左、右、根
層序(Levelorder):從上至下
二叉樹的惟一性:
前序 + 中序
後續 + 中序
兩個節點:
前驅節點(predecessor):中序遍歷的前一個節點
後繼節點(successor):中序遍歷的後一個節點

0x07 二叉搜索樹(Binary Search Tree)

簡稱 BST,又名二叉查找、二叉排序樹。其特色:
一、任意一個節點的值都大於左子樹全部節點的值
二、任意一個節點的值都小於右子樹全部節點的值

故此樹的節點必需要具備 可比性 。接口設計:
一、size 與 clear
二、添加與刪除
三、包含(node 與內容)

0x08 平衡二叉搜索樹(Binary Search Tree)

爲了防止二叉搜索樹退化成 「鏈表」 的形式,故再來研究一個 平衡二叉搜索樹。目的是讓二叉搜索樹的高度控制到最矮,相比其它二叉樹,在修改(添加/刪除)節點以後,恢復搜索二叉樹,讓其更加平衡(Balance),故稱爲 平衡二叉搜索樹,簡稱 BBST。
經典的平衡二叉搜索樹有:AVL 樹與紅黑樹,也稱他們爲自平衡二叉樹。

0x09 AVL 樹

一個與之對應的概念,叫平航因子(Balance Factor):某節點的左右子樹的高度差。
AV 的特色:

每一個節點的平衡因子只多是 一、0、-1
每一個節點的左右子樹高度差不超過 1
搜索、添加與刪除的時間複雜度度是 O(\log n)

理解的難點是恢復平衡:右旋轉、左旋轉、左右旋轉

0x10 B 樹(B-Tree)

是一種平衡的多路(多叉)搜索樹、多使用於文件系統、數據庫的實現。
特色:

1 個節點能夠存儲超過 2 個元素,能夠擁有超過 2 個子節點
擁有二叉搜索樹的一些性質
平衡、每一個節點的全部子樹高度一致
比較矮

若是這個 B 數中一個節點最多能存儲 3 個元素,就是最多有 4 個子樹,那稱爲 4階B樹
4 階 B 樹、也稱 2-3-4 樹。關於 B 樹,相對比較複雜的,主要仍是在於恢復平衡,相繼引出了 上溢、下溢 的概念。

0x11 紅黑樹(Red Black Tree)

也稱自平衡二叉搜索樹、也叫平衡二叉B樹,僅看概念就知道這是一顆有顏色的樹。
性質:

一、節點的顏色是 RED 或者 BLACK
二、根節點都是 BLACK
三、葉子節點(外部節點、空節點)都是 BLACK
四、RED 節點的子節點都是 BLACK : RED 節點的 parent 都是 BLACK, 根節點到葉子節點的全部路勁上不能有兩個連續的 RED 節點
五、從任一節點到葉子節點的全部路徑都包含相同數目的 BLACK 節點

紅黑樹依舊是在恢復平衡的處理上很複雜,與 4 階 B 樹有着千絲萬縷的關係(在研究 紅黑樹的時候、心中必定要有一點 B 數)。其過程當中須要知道的幾個概念:
parent:父節點
sibling:兄弟節點
uncle:叔父節點
grand:祖父節點

紅黑樹的實現很複雜,可是性能方面是相對較優的,應用也比較普遍。好比這些:

  • 一、C++ STL(好比 map、set...)
  • 二、Java 的 TreeMap、TreeSet、HashMap、HashSet
  • 三、Linux 的進度調度
  • 四、Ngix 的 timer 管理
相關文章
相關標籤/搜索