面向基礎軟件工程師的算法實踐與分析

​轉載本文需註明出處:微信公衆號EAWorld,違者必究。前端

 

引言:算法

 

Google搜索的結果,新浪微博向你展現的話題,淘票票向你推薦的電影,都說明了算法無處不在。而編程從本質上來講就是算法加數據結構 ,算法是編程思想的核心部分,對於一名基礎軟件工程師而言,常見的一些算法也是必須重點掌握的內容。而常見的算法以及其應用場景有哪些呢?編程

 

目錄:數組

 

1. 算法概述微信

2. 經常使用算法的理論分析網絡

3. 經常使用算法的實際應用數據結構

 

1.  算法概述架構

 

算法(Algorithm)是指解題方案的準確而完整的描述,是一系列解決問題的清晰指令,算法表明着用系統的方法描述解決問題的策略機制。也就是說,可以對必定規範的輸入,在有限時間內得到所要求的輸出。函數

 

1.1 算法特徵微服務

 

  • 有窮性:算法的有窮性是指算法必須能在執行有限個步驟以後終止;

  • 確切性:算法的每一步驟必須有確切的定義;

  • 輸入項:一個算法有0個或多個輸入,以刻畫運算對象的初始狀況,所謂0個輸入是指算法自己定出了初始條件

  • 輸出項:一個算法有一個或多個輸出,以反映對輸入數據加工後的結果。沒有輸出的算法是毫無心義的;

  • 可行性:算法中執行的任何計算步驟都是能夠被分解爲基本的可執行的操做步驟,即每一個計算步驟均可以在有限時間內完成(也稱之爲有效性)。

 

1.2 算法衡量標準

 

同一問題可用不一樣算法解決,而一個算法的質量優劣將影響到算法乃至程序的效率。算法分析的目的在於選擇合適算法和改進算法。一個算法的評價主要從時間複雜度和空間複雜度來考慮。而算法的總體考量包含如下幾個內容:

 

  • 時間複雜度:算法的時間複雜度是指執行算法所須要的計算工做量。通常來講,計算機算法是問題規模n 的函數f(n),算法的時間複雜度也所以記作:T(n)=Ο(f(n))。所以,問題的規模n 越大,算法執行的時間的增加率與f(n) 的增加率正相關,稱做漸進時間複雜度(Asymptotic Time Complexity)。

  • 空間複雜度:算法的空間複雜度是指算法須要消耗的內存空間。其計算和表示方法與時間複雜度相似,通常都用複雜度的漸近性來表示。同時間複雜度相比,空間複雜度的分析要簡單得多。

  • 正確性:算法的正確性是評價一個算法優劣的最重要的標準。

  • 可讀性:算法的可讀性是指一個算法可供人們閱讀的容易程度。

  • 健壯性:健壯性是指一個算法對不合理數據輸入的反應能力和處理能力,也稱爲容錯性。

 

2. 經常使用算法的理論分析

 

算法包含的內容有不少,對於基礎軟件工程師而言,雖然不須要面面俱到,但對於經常使用的算法仍是要學習掌握。常見算法包括:分治法、遞歸法、貪心算法和回朔法。

 

2.1 分治法:

 

 

分治法是把一個複雜的問題分紅兩個或更多的相同或類似的子問題,再把子問題分紅更小的子問題……直到最後子問題能夠簡單的直接求解,原問題的解即子問題的解的合併。

 

能用分治法解決的問題,通常符合如下特徵:

 

  1. 該問題的規模縮小到必定的程度就能夠容易地解決;

  2. 該問題能夠分解爲若干個規模較小的相同問題,即該問題具備最優子結構性質;

  3. 利用該問題分解出的子問題的解能夠合併爲該問題的解;

  4. 該問題所分解出的各個子問題是相互獨立的,即子問題之間不包含公共的子子問題。

 

若是肯定一個問題能夠用分治法進行求解,能夠按照分治法的求解步驟處理。求解步驟以下:

 

  1. 分解:將原問題分解爲若干個規模較小,相互獨立,與原問題形式相同的子問題;

  2. 解決:若子問題規模較小而容易被解決則直接解,不然遞歸地解各個子問題

  3. 合併:將各個子問題的解合併爲原問題的解。

 

2.2 遞歸法

 

 

程序調用自身的編程技巧稱爲遞歸(recursion)。

 

一個過程或函數在其定義或說明中有直接或間接調用自身的一種方法,它一般把一個大型複雜的問題層層轉化爲一個與原問題類似的規模較小的問題來求解,遞歸策略只需少許的程序就可描述出解題過程所須要的屢次重複計算,大大地減小了程序的代碼量。

 

遞歸的能力在於用有限的語句來定義對象的無限集合。而可以使用遞歸處理的問題通常具有如下特徵:

 

  1. 能夠經過遞歸調用來縮小問題規模,且新問題與原問題有着相同的形式。

  2. 存在一種簡單情境,可使遞歸在簡單情境下退出。

 

若是肯定一個問題能夠用遞歸法進行求解,能夠按照遞歸法的求解步驟處理。求解步驟以下:

 

  1. 肯定邊界條件

  2. 肯定不知足邊界條件時的遞歸前進段

  3. 肯定知足條件時遞歸返回段

 

2.3 回朔法

 

 

回溯法(探索與回溯法)是一種選優搜索法,按選優條件向前搜索,以達到目標。

 

探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步從新選擇,這種走不通就退回再走的技術爲回溯法,而知足回溯條件的某個狀態的點稱爲「回溯點」。遞歸的能力在於用有限的語句來定義對象的無限集合。

 

若是肯定一個問題能夠用回溯法進行求解,能夠按照回溯法的求解步驟處理。求解步驟以下:

 

  1. 針對所給問題,定義問題的解空間。

  2. 肯定易於搜索得解空間結構。

  3. 以深度優先方式搜索解空間,並在搜索過程當中用剪枝函數避免無效搜索。

 

2.4 貪心算法

 

 

貪心算法(又稱貪婪算法)是指,在對問題求解時,老是作出在當前看來是最好的選擇。也就是說,不從總體最優上加以考慮,他所作出的是在某種意義上的局部最優解。

 

貪心算法不是對全部問題都能獲得總體最優解,關鍵是貪心策略的選擇,選擇的貪心策略必須具有無後效性,即某個狀態之前的過程不會影響之後的狀態,只與當前狀態有關。

 

能用貪心算法處理的問題,一般具備如下特色:

 

  1. 可行的:即它必須知足問題的約束。

  2. 局部最優:他是當前步驟中全部可行選擇中最佳的局部選擇。

  3. 不可取消:即選擇一旦作出,在算法的後面步驟就不可改變了。

 

一旦問題肯定能夠用貪心算法處理,咱們能夠按照貪心算法經常使用的步驟,進行解答。步驟以下:

 

  1. 創建數學模型來描述問題;

  2. 把求解的問題分紅若干個子問題;

  3. 對每一子問題求解,獲得子問題的局部最優解;

  4. 把子問題的解局部最優解合成原來解問題的一個解。

 

3.經常使用算法的實際應用

 

每種算法都有不少應用場景,但算法的思想倒是一致,所以咱們選取算法衆多應用場景中的一個,來分析該算法的使用形式。基於上面講解的四種算法,咱們分別選擇一個實例做爲分析,依次以下:

 

  • 分治法:二分查找問題

  • 遞歸法:文件夾刪除問題

  • 貪心算法:貨幣找零問題

  • 回朔法:旅行售貨員問題

 

而針對這些問題,咱們經過分析問題特徵,根據算法特徵提取算法執行時要素,一步步完成問題的解答。

 

3.1 分治法實例

 

問題:

 

有一個包含10000個數據的有序數組,給定一個數n, 肯定該數在數組中的位置。

 

問題分析:

 

想要查找數在數組中的位置,最容易想到的是遍歷數組,在數組長度小的時候,可能很容易實現,但數組很大時,再經過遍歷,會嚴重影響算法的效率。所以須要考慮其餘方式。

 

既然數據有序,那麼能夠先取出,數組中中間數據,判斷所找數據是否符合要求,若不符合,就判斷是大於中間值,仍是小於中間值。肯定好範圍,此時如果再次遍歷,能夠節省一半的時間開銷。基於這種思想,咱們能夠再次取中間值,不用遍歷,能夠大大提升算法效率。

 

提取算法要素:

 

1. 先肯定中間位置

根據數組長度,肯定中間位置,找到中間位置數據

2. 根據判斷結果,選定查找範圍

將待查找的數據與數組中間位置數據值相比較。若相等,則查找成功並返回該位置,不然須肯定新的查找區間,繼續二分查找。

 

關鍵代碼:

 

上述例子只是分治法衆多經典應用場景之一,而分治法還有其餘不少經典應用場景,你們有興趣能夠本身去學習一下。分治法其餘經典實例:

 

  1. 漢諾塔

  2. 大整數乘法

  3. Strassen矩陣乘法

  4. 棋盤覆蓋

  5. 合併排序

  6. 快速排序

  7. 線性時間選擇

  8. 最接近點對問題

  9. 循環賽日程表 

 

3.2 遞歸法實例

 

問題:

 

刪除指定路徑文件夾。

 

問題分析:

 

文件或者空文件夾能夠刪除,可是若文件夾中包含有子文件或文件夾,則沒法直接刪除。

 

所以須要把文件夾裏面的文件依次所有刪除,再回退刪除該文件夾,若文件夾裏面包含子文件夾,則需先進入子文件夾,刪除子文件夾裏面的文件。若還包含文件夾,則重複以上步驟,直到文件夾裏面爲空或者只有文件時,刪除文件,依次回退刪除上一級。最終完成要求。

 

提取遞歸三要素:

 

1. 肯定遞歸中止條件

當前是文件或者空文件夾

2. 肯定遞歸前進

當前不是文件也不是空文件夾,則遞歸

3. 肯定遞歸後退

當前是文件或者空文件夾,刪除當前文件或文件夾,結束遞歸

 

關鍵代碼:

 

 

上述例子只是遞歸法衆多經典應用場景之一,而遞歸法還有其餘不少經典應用場景,你們有興趣能夠本身去學習一下。遞歸法其餘經典實例:

 

  1. 斐波那契數列

  2. 漢諾塔問題

 

3.3 貪心算法實例

 

問題:

 

一臺自動販賣機,能夠自動找零,找零金額有1元、2元、5元、10元、20元和50元這些面值。而每種面值的紙幣分別有c0, c1, c2, c3, c4, c5, c6張。如今要用這些錢來找零K元,至少要用多少張紙幣?

 

問題分析:

 

找零K元,有不少種方式,能夠所有用1元支付,若不夠,用兩元補充。但用這種方式,存在兩個弊端:

 

  1. 小面額金額用太多,不利於後續其餘顧客找零;

  2. 一次找零太多,影響找零效率

 

鑑於上述兩個問題,咱們能夠先 找零最大面額,而後依次使用次大面額的,這樣能夠少消耗小面額紙幣,也能提升自動販賣機的找零效率。

 

提取算法要素:

 

1. 把問題分解成多步

每次找零都爲一步,直到找零結束

2. 求解每一步的最優解

每次找零都用符合條件的最大的面額

 

關鍵代碼:

 

 

貪心算法有不少經典的使用場景,你們有興趣能夠本身去了解一下,這裏列舉出了常見的一些實例:

 

  1. 活動選擇問題

  2. 多機調度問題

  3. 小船過河問題

  4. 區間覆蓋問題

  5. Huffman編碼

  6. Dijkstra算法

  7. 最小生成樹

 

3.4 回朔法實例

 

問題:

 

某售貨員要到若干城市去推銷商品,已知各城市之間的路程(或旅費),且每一個城市之間都互通。他要選定一條從駐地出發,通過每一個城市一次,最後回到駐地的路線,使總的路程(或總旅費)最小。

 

問題分析:

 

最終要回到起點,而且每一個城市都互通,所以從那一點出發,都不影響最終的結果。倘若選定一個城市,那麼前往的第二個城市,有n-1個選擇;選定第二個城市有n-2個選擇。。。直到最後一個城市只有一種選擇,從最後一個城市返回起點也只有一種選擇。

 

從上述分析可知,每選擇一個城市,後面的選擇可能有1到多種,所以要求解最合適的路線,能夠計算全部可能的狀況,從中選擇最優的結果。

 

所以決定一個起點,而後隨便選擇一個城市,直到回到原點,計算結果。而後回到有選擇的城市,選擇其餘的城市,計算結果。若結果優於前面的結果,則認爲當前最優。而後依次回退,直到全部可能的路徑都走一遍,獲得最優結果爲止。

 

提取算法要素:

 

1.定義問題的解空間

定義一棵排列樹,存儲節點,以及節點權重

2. 肯定搜索方式

經過深度優先搜索方式,依次回溯求解結果

 

關鍵代碼:

 

 

回朔法有不少經典的使用場景,你們有興趣能夠本身去了解一下,這裏列舉出了常見的一些實例:

 

  1. 八皇后問題

  2. 0-1揹包問題

 

雖然每一個算法的思想都不相同,而且每一個問題可以使用的算法也不惟一,但算法最終仍是爲程序服務。對於軟件工程師而言,熟悉掌握常見的算法,在遇到問題時,你能夠有更多的選擇;而且能夠在衆多選擇中找到效率更高、更簡潔的處理方式。

 

推薦閱讀

強化學習中的好奇心驅動學習算法:隨機網絡精餾探索技術

人工智能與軟件架構

我對敏捷軟件測試的理解與實踐

 

關於做者:哆啦貓,普元移動端開發工程師,擅長Java,專一於Andriod開發。目前參與Mobile 8.0項目的開發,主要接觸RN技術的應用,黏合前端代碼 與Android底層之間的交互。

關於EAWorld:微服務,DevOps,數據治理,移動架構原創技術分享

相關文章
相關標籤/搜索