演算法學習筆記

由於缺乏對演算法和資料結構的知識,因此即便會用程序解決一些事情,但是對比專業的人員還是相差很大。如果可以了解演算法和熟悉運用資料結構,那麼對於後續的編寫程式會有很大的提升,因此即便是自學,也可以不落下這一塊的內容

演算法的簡單概念

輸入 + 演算法 = 輸出
設計演算法需要很嚴格的定義,但是對於演算法本身的定義卻是比較含糊的,對於入門的我來說,知道上面一個簡單的公式即可。

如何衡量演算法的好壞

  • 時間緯度(時間複雜度)
  • 記憶體緯度(空間/內存)
    由於現在cpu比記憶體珍貴很多,因此我們優先考慮時間緯度。

好的演算法 = 步驟少 + 空間佔用少

演算法的時間緯度符號很多,但目前用的多的是大O,所以入門暫時就把心思花在這裏吧。
另外執行的情況都是在最糟糕的情況下來算n。

常見的六種時間複雜度與演算法

  • O(1):陣列讀取(list讀取)
  • O(n):簡易搜索
  • O(log n ):二分搜索
  • O(nlogn):合併排序
  • O(n^2):選擇排序/插入排序
  • O(2^n):斐波那契數列

資料結構基礎知識

摘自《我的第一本算法書》,用於回憶學習用

鏈表

優點:增加和刪除快(只需時間O(1)),只需要改變指針即可
缺點:訪問慢(時間緯度O(n))
種類:單向鏈表,雙向鏈表,環形鏈表
特點:分散存儲於內存中,訪問則需要按照順序訪問。

數組

優點:訪問快(O(1)),直接通過下標訪問如:array[1]
缺點:創建和刪除慢(O(n))

特點:後進先出(LIFO),只能操作一端的數據,如若需要訪問其他層,需要調換順序,在只需要訪問最新數據時,使用棧就比較方便了.
入棧(push),出棧(pop)
舉例:規定(AB(C(DE)F)(G((H)IJ)K))這一串字符中括號的處理方式如下:
首先從左邊開始讀取字符,讀到左括號就將其入棧,讀到右邊括號就將棧頂的左括號出棧。此時,出棧的左括號便於當前讀取的右括號相匹配。
通過這種方式,我們就能得知配對括號的具體位置。
ps:在深度優先搜索算法中,通常會選擇最新的數據作為候補頂點。在候補頂點的管理上就可以使用棧.

隊列

特點:先進先出(FIFO),添加和刪除操作可以在兩端,添加操作(入隊),刪除操作(出隊)
ps:廣度優先搜索法中,通常就會從搜索候補中選擇最早的數據作為下一個頂點。此時,在候補頂點的管理上就可以使用隊列了。

哈希表

特點:類似於python中的字典,採用key-value的方式;
大概計算原理:假如有5個存儲位置,我們需要存儲每個名字和名字對應的性別;則我們可以根據名字(joy)計算出哈希值(通過哈希函數計算),
得到哈希值後,繼續採用mod運算,得到餘數,把該joy的數據存到該餘數的位置。
若存儲過程中,有多個數據餘數一樣(即是發生衝突),則可以採用鏈表存儲(鏈地址法),也可採用開放地址法(計算出一個/n個候補位置)

結構規則:

  • 子節點必定大於父節點(頂部的為父節點)
  • 最小值被存在頂點
  • 添加數據時,會把新數據放在最下面一行靠左的位置(然後於父節點對比,小於父節點則交換位置)
  • 取出最小值後,把最後一行,最右側的數據提升到最上方,同時與左右子節點對比(與較小的值換位置)
    時間複雜度:
  • 取最小值(O(1))
  • 數據重構時間(O(logn))
二叉查找樹

結構規則:

  • 左邊子節點均比父節點小,右邊子節點均比父節點大
  • 查找最小值(從頂端開始,往左下最底端查找)
  • 查找最大值(從頂端開始,往右下最底端查找)
  • 添加數據(不斷的與父節點對比,< 則往左,>則往右
  • 刪除數據(若在最底端,則直接刪除;若只有一個子節點,則刪除後子節點往上移;若存在兩個子節點,則把左樹中最大節點(或者右樹中最小節點)移動到被刪除的節點
    時間複雜度:
    節點若較為均衡,則為O(log(n)),最壞的情況為O(n),
    以二叉查找樹為基礎拓展的平衡二叉查找樹(B樹)則是為了提高查找效率而做的數據結構

先進們的貢獻

胡程維《談什麼是演算法和時間複雜度》

胡程維《從時間複雜度認識常見的演算法》