算法图解
《算法圖解》各章學習
1、算法簡介
二分法
二分查找法,用于有序元素列表,以一半為界分開,確定元素在哪一部分,繼續前述操作。速度最快,包含n個元素時為 $ \log_2 n$
大O表示法
用于表示算法的速度,O()。真正的速度需要乘以時間常數c,一般分析時不考慮。
2、選擇排序
數組
數組在內存中儲存的信息是連在一起的,方便讀取操作。
鏈表
鏈表的信息在內存中是無序的,下一個內存地址由上一個內存中的信息給出,方便插入和刪除操作。
選擇排序
不斷遍歷整個無序列表,將元素有序排列出來,速度為O(n×n)或O(n2)
(大O表示法省略常數)
3、遞歸
遞歸:自己調用自己的函數。
遞歸函數條件:基線條件和遞歸條件,遞歸條件指的是函數調用自己,而基線條件則指的是函數不再調用自己(例如設置調用次數),從而避免形成無限循環。
棧(stack)
調用棧有壓入和彈出兩個操作,都只操作最上面的內存塊,而不是壓入底部的內存。所有函數調用都進入調用棧。
遞歸時函數不斷將同名不同參考值的函數壓入調用棧,使用時彈出。因此調用棧可能很長,這將占用大量的內存。
4、快速排序
D&C算法思想:找出簡單的基線條件,)確定如何縮小問題的規模,使其符合基線條件。
因此處理列表時基線條件很可能是空數組或只包含一個元素的數組。
快速排序
方法:首先在數組中選擇一個元素作為基準值。接下來,找出比基準值小的元素以及比基準值大的元素各自分為兩個子數組。對子數組進行基準值→子數組的遞歸,直到子數組中只剩1個或沒有元素停止(基線條件)。最后左邊的數組 + 基準值 + 右邊的數組合并為排序結果。
算法速度:實現快速排序時,隨機地選擇用作基準值的元素。快速排序的平均運行時間為O(nlog?n)O(n\log n)O(nlogn),也是最佳情況下的時間,最壞情況(取到了數組中最大或最小的基準值)運行時間是O(n2)。
5、散列表
散列函數
數據的存儲位置和它的關鍵字之間建立一個確定的對應關系f,使每個關鍵字和結構中一個唯一的存儲位置相對應,因此散列函數可以直接確定元素的儲存位置。
散列表(hash table)
使用散列函數和數組創建了一種被稱為散列表 (hash table)的數據結構。Python提供的散列表實現為字典 ,使用函數dict()來創建散列表。
用途:除了快速查找數據以外,還可以用于映射關系,緩存數據(例如,在Web服務器上),防止重復等。
沖突:在散列表中,不同的關鍵字值對應到同一個存儲位置的現象。
處理方法:(1)在沖突的位置儲存一個鏈表,極端情況鏈表很長造成散列表的速度很慢。(2)降低填裝因子,使每個關鍵字都有自己的儲存位置,一旦填裝因子超過0.7,就該加長散列表的長度。(3)良好的散列函數讓數組中的值呈均勻分布。
性能:散列表的查找、插入、刪除在理想情況下均為常量時間O(1).在沖突很多的情況下,速度變慢,最差情況性能變化為線性時間O(n)。
6、廣度優先搜索
圖
圖由節點和邊組成。使用圖來創建問題模型,使用廣度優先搜索解決問題。
廣度優先搜索可回答兩類問題,從節點A出發,有前往節點B的路徑嗎;從節點A出發,前往節點B的哪條路徑最短。
隊列
隊列類似于棧,你不能隨機地訪問隊列中的元素。隊列是一種先進先出 (First In First Out,FIFO)的數據結構,而棧是一種后進先出的數據結構。隊列只支持兩種操作:入隊和出隊 。
在Python中,可使用函數deque()來創建一個雙端隊列。
廣度優先搜索算法
(1)建立圖模型,在這里,要將節點映射到其所有鄰居,如graph["you"] = ["alice", "bob", "claire"]以此類推;
(2)創建隊列,將所有一度關系對象加入隊列,取出隊列的第一個元素并檢查,符合要求結束,不符合則將這個節點的一度關系對象加入隊列;
(3)繼續按順序檢查隊列(否則找到的就不是最短路徑),直到隊列為空或找到需要搜索的對象。檢查隊列時同時將檢查過的對象放入數組中,防止二次檢查浪費時間。
性能:總運行時間O(V+E)O(V + E)O(V+E),其中V為頂點(vertice)數,E為邊數。
7、狄克斯特拉算法
廣度優先的算法來查找兩點之間的最短距離,那時的“最短距離”是指路徑最少。在狄克斯特拉算法中,你給每段都分配了一個數字或權重,因此狄克斯特拉算法找出的是總權重最小的路徑。
狄克斯特拉算法
(1) 找出最便宜的節點,即可在最短時間內前往的節點。
(2) 對于該節點的鄰居,檢查是否有前往它們的更短路徑,如果有,就更新其開銷。
(3) 重復這個過程,直到對圖中的每個節點都這樣做了。
(4) 計算最終路徑。
注意:僅當權重為正時使用狄克斯特拉算法;如果圖中包含負權邊,則使用貝爾曼-福德算法。
8、貪婪算法
對于NP完全問題來說,目前沒有算法能夠快速找到問題的最優解,最佳的做法是使用近似算法(貪婪算法)。
NP完全問題特征:元素較少時算法的運行速度非常快,但隨著元素數量的增加,速度會變得非常慢;不能將問題分成小問題,必須考慮各種可能的情況;問題涉及序列、集合、組合且難以解決。
NP完全問題更加科學的定義關于多項式時間,此處不展開。
貪婪算法
**貪婪算法:**在對問題進行求解時,在每一步選擇中都采取最好或者最優(即最有利)的選擇,從而希望能夠導致結果是最好或者最優的算法。貪婪算法所得到的結果往往不是最優的結果(有時候會是最優解),但是都是相對近似(接近)最優解的結果。
- 貪婪算法并沒有固定的算法解決框架,算法的關鍵是貪婪策略的選擇,根據不同的問題選擇不同的策略。
- 必須注意的是策略的選擇必須具備無后效性,即某個狀態的選擇不會影響到之前的狀態,只與當前狀態有關,所以對采用的貪婪的策略一定要仔細分析其是否滿足無后效性。
前面介紹的最短路徑問題,廣度優先、狄克斯特拉都屬于貪婪算法,只是在其問題策略的選擇上,剛好可以得到最優解。
9、動態規劃
動態規劃:在約束條件下,將問題劃分為若干子問題并對其求出最優解,同時將子問題的答案存儲起來,以減少重復計算相同子問題的次數,最終求出問題最優解的算法思想。
書中的例子背包問題,把裝4磅的背包分解為裝1、2、3、4磅的包,把每一步的答案儲存起來,最后的答案取決于前一步答案。這種方法降低了算法的時間復雜度。
應用動態規劃(三步走)
1、建立狀態轉移方程:建立如斐波那契數列的遞推方程作為狀態轉移方程,如f(n)=f(n?1)+f(n?2)f (n )=f (n-1)+f(n-2)f(n)=f(n?1)+f(n?2)
**2、緩存并復用以往結果:**記錄下f(1)f(1)f(1)、f(2)f(2)f(2)…f(99)f(99)f(99),則f(100)f(100)f(100)只需復用前面的子結果,進行一次加法運算即可得到結果。
**3、按順序從小往大算:**這里的“小”和“大”對應的是問題的規模,從小到大一步步遞推出最終的結果。
**例子:**斐波那契數列計算
簡單遞歸:時間復雜度$ O(2^{n})$
動態規劃:線性規劃通過緩存與復用機制將計算規模縮小到紅色部分,時間復雜度$ O(n)$
10、K最近鄰算法
特征提取、分類、回歸,分類時主義選擇合適的公式。(模式識別有詳細講解)
11、其他算法
ⅰ.二叉查找樹
對于其中的每個節點,左子節點的值都比它小 ,而右子節點的值都比它大 。
在二叉查找樹中查找節點時(類似有序數組二分查找操作),平均運行時間為$ O(\log n)$ (二分查找操作同樣為這個),但在最糟的情況下所需時間為$ O(n);插入和刪除操作平均運行時間同樣為;插入和刪除操作平均運行時間同樣為;插入和刪除操作平均運行時間同樣為 O(\log n)$。
二叉查找樹不能隨機訪問,如果樹處于不平衡狀態(左右的節點數顯著不等)會導致性能不佳。
ⅱ.反向索引
ⅲ.傅里葉變換
處理信號。
例如傅里葉變換能夠準確地指出各個音符對整個歌曲的貢獻,讓你能夠將不重要的音符刪除。這就是MP3格式的工作原理!
ⅳ.并行算法
排序算法的速度大致為$ O(n\log n),使用并行算法快速排序的所需的時間可以減少為,使用并行算法快速排序的所需的時間可以減少為,使用并行算法快速排序的所需的時間可以減少為 O(n)$。由于并行性管理開銷以及負載需要均衡的原因,并行算法提升速度并不是線性的。
Ⅴ.MapReduce
分布式算法MapReduce基于兩個簡單的理念:映射(map)函數和歸并(reduce)函數。
映射函數
接受一個數組,并對其中的每個元素執行同樣的處理。相當于將多個相同任務映射到多個服務器上去處理。
歸并函數
將很多項歸并為一項,例如吧所有服務器運算得到的結果相加。
ⅵ.布隆過濾器和HyperLogLog
概率型數據結構,不能給出準確的答案,但也較為接近,而占用的內存空間比起散列表卻小得多。
ⅶ.SHA算法
安全散列算法(SHA)函數,給定一個字符串,SHA返回其散列值。這種散列算法是單向的。你可根據字符串計算出散列值,但不能更具散列值計算出字符串。用于比較大型文件,檢查密碼等。
ⅷ.局部敏感的散列算法
SHA重要特征局部不敏感,修改其中的一個字符,再計算其散列值,結果將截然不同。
Simhash散列函數是局部敏感的,對字符串做細微的修改,Simhash生成的散
列值也只存在細微的差別,這能夠通過比較散列值來判斷兩個字符串的相似程度。
Ⅸ.Diffie-Hellman密鑰交換
Diffie-Hellman使用兩個密鑰:公鑰和私鑰。發送消息時使用公鑰對其進行加密。加密后的消息只有使用私鑰才能解密。
Ⅹ.線性規劃
總結
- 上一篇: linux进程通信发送方式,Linux服
- 下一篇: sed替换