算法設計標准


一、基礎定義

算法定義:

算法是解決特定問題求解步驟的描述,在計算機中表現為指令的有限序列,並且每條指令表示一個或多個操作,每一個操作都有特定的功能

算法的基本特點:

(1)輸入輸出:算法具有0個或多個輸入,至少有一個或多個輸出;

(2)有窮性:指算法在執行有限的步驟之后,自動結束而不會出現無限循環,並且每一個步驟在可接受的時間內完成;

(3)確定性:算法的每一步驟都具有確定的含義,不會出現二義性。

(4)可行性:算法的每一步都必須是可行的,也就是說,每一步都能夠通過執行有限次數完成;

算法設計要求:

(1)正確性:算法的正確性是指算法至少應該具有輸入、輸出和加工處理無歧義性、能正確反映問題的需求、能夠得到問題的正確答案;

(2)可讀性:算法設計的另一目的是為了便於閱讀、理解和交流

(3)健壯性:當輸入數據不合法時,算法也能做出相關處理,而不是產生異常或莫名其妙的結果;

(4)時間效率高存儲量低:時間效率指的是算法的執行時間,對於同一個問題,如果有多個算法能夠解決,執行時間短的算法效率高,執行時間長的效率低。存儲量需求指的是算法在執行過程中需要的最大存儲空間,主要指算法程序運行時所占用的內存或外部硬盤存儲空間。設計算法應該盡量滿足時間效率高和存儲量低的需求。

二、算法效率檢測

算法的執行效率大都指算法的執行時間,我們如何衡量一個算法程序的執行效率吶,可以通過事后統計和事前估算兩種方式來衡量。
(1)事后統計方法:這種方法主要是通過設計好的測試程序和數據,利用計算機計時器對不同算法編制的程序的運行時間進行比較,從而確定算法效率的高低;該種方式有兩個特點,第一:必須要通過設計好的測試程序和數據進行效率檢測,但是通過少量的數據無法很好的判斷算法的好壞,所以我們需要創造大量的測試數據進行檢驗,對於這個這個數據大量,我們很難進行評估和設計;第二:該種方式需要花費大量的時間和精力去編制好程序,如果最終結果發現這是一套很糟糕的算法,就前功盡棄;
(2)事前估算方法:在計算機程序編制前,依據統計方法對算法進行估算,我們可以發現,一個用高級程序語言編寫的程序在計算機上運行時所消耗的時間取決於下列因素:
1、編譯產生的代碼質量;
2、算法采用的策略、方法;
3、問題的輸入規模;
4、機器執行指令的速度;
這其中,1和4 分別由軟件和計算機硬件因素有關,所以我們只能從算法的策略和輸入規模進行衡量,根據數據的輸入規模和計算方式,我們有以下兩個指標可以估算算法的執行效率:

  時間復雜度:

  在進行算法分析時,語句總的執行次數 T(n)是關於問題規模 n的函數,進而分析 T(n)隨 n 的變化情況並確定 T(n)的數量級。算法的時間復雜度,也就是算法的時間量度,記作:T(n)=O(f(n))。它表示隨問題規模 n 的增大,算法執行時間的增長率和f(n)的增長率相同,稱作算法的漸近時間復雜度,簡稱為時間復雜度。其中 f(n)是問題規模 n 的某個函數。

計算時間復雜度(大O階)三條法則:
1.用常數 1 取代運行時間中的所有加法常數。 2.在修改后的運行次數函數中,只保留最高階項。 3.如果最高階項存在且不是 1,則去除與這個項相乘的常數。得到的結果就是大 O 階。
我們對以下幾類代碼進行分析:
(1)常數階:
int sum = 0,n = 100; /*執行一次*/
sum = (1+n)*n/2; /*執行一次*/
printf("%d", sum); /* 執行一次*/
可以看出算法的函數執行次數函數為f(n)= 3;按照我們計算大O階的三條法則的第一條,所有常數項使用1來代替,所以該代碼的時間復雜度為O(1) 而不是O(3); 如果 我們將中間的 sum = (1+n)*n/2; 執行10次,那么我們的執行次數函數為 f(n)=12,結果依舊是常數,它的時間復雜度依舊為O(1),對於這種分支結構而言,執行次數始終是恆定的,不會隨着n 變化而變化,所以他們的時間復雜度始終未O(1)
(2)線性階:
for(int i=0; i<n ;i++){
    print(""+i);
}
它的循環的時間復雜度為 O(n),因為循環體中的代碼須要執行 n次
(3)對數階:
int count = 1;
while (count < n){
    count = count * 2; /*時間復雜度為 O(1)的程序步驟序列*/
}
由於每次count乘以 2 之后,就距離n更近了一分。也就是說,有多少個 2 相乘后大於n,則會退出循環。由 2 x =n得到x=log 2 n。所以這個循環的時間復雜度為O(logn)
(4)平方階:
for(int i=0; i<n ;i++){
  for(int j=0; j<n ;j++){
    print(""+i+j);
  }
}
對於外層的循環,不過是內部這個時間復雜度為O(n)的語句,再循環n次。所以這段代碼的時間復雜度為O(n^2)。
注意以下代碼片段:
int i,j;
  for(i = 0; i < n; i++){
    for (j = i; j < n; j++) /*注意 int j = i 而不是 0*/
    {
      print("結果"+i+j);
   }
}
由於當 i = 0 時,內循環執行了 n 次,當 i = 1 時,執行了 n-1 次,……當 i = n-1 時,內循環執行了 1 次。所以總的執行次數:
n+(n-1)+(n-2)+(n-3)..........+1= n^2 /2 +n/2(等差數列求和)
按照我們推斷大O階的第二條和第三條,只保留最高階,並且去掉最高階的常數,最終得到結果為O(n^2);
常用的時間復雜度所耗費的時間從小到大依次是:
O(1)<O(log n)<O(n)<O(n*logn)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n);
 空間復雜度

  算法的空間復雜度通過計算算法所需的存儲空間實現,算法空間復雜度的計算公式記作:S(n)= O(f(n)),其中,n為問題的規模,f(n)為語句關於n所占存儲空間的函數。一般情況下,一個程序在機器上執行時,除了需要存儲程序本身的指令、常數、變量和輸入數據外,還需要存儲對數據操作的存儲單元,若輸入數據所占空間只取決於問題本身,和算法無關,這樣只需要分析該算法在實現時所需的輔助單元即可。若算法執行時所需的輔助空間相對於輸入數據量而言是個常數,則稱此算法為原地工作,空間復雜度為0(1)。

通常, 我們都使用"時間復雜度"來指運行時間的需求,使用"空間復雜度"指空間需求。當不用限定詞地使用"復雜度'時,通常都是指時間復雜度。

三、總結

很多伙伴說,現在 CPU 升級越來越快,根本不用考慮算法的優劣,實現功能即可,用戶感覺不到算法好壞造成的快慢,但是做個假設:如果CPU在短短幾年間,速度提高了 100 倍,這其實已經很誇張了。而我們的某個算法本可以寫出時間復雜度是O(n)的程序,卻寫出了O(n 2 )的程序,僅僅因為容易想到,也容易寫。即在O(n 2 )的時間復雜度算法程序下,速度其實只提高了 10 倍,而對於O(n) 復雜度的算法說,那才是真的 100 倍。 也就是說,一台老式CPU的計算機運行O(n)的程序和一台速度提高 100 倍新式CPU運行O(n 2 )的程序。最終效率高的勝利方卻是老式CPU的計算機,原因就在於算法的優劣直接決定了程序運行的效率,所以算法的重要性可想而知。
最后附上一張常用排序算法的效率比較圖:
 
 
參考內容:
《大話數據結構》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM