算法設計標準

1、基礎定義算法

算法定義:數據結構

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

算法的基本特色:測試

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

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

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

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

算法設計要求:排序

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

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

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

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

2、算法效率檢測

算法的執行效率大都指算法的執行時間,咱們如何衡量一個算法程序的執行效率吶,能夠經過過後統計和事前估算兩種方式來衡量。
(1)過後統計方法:這種方法主要是經過設計好的測試程序和數據,利用計算機計時器對不一樣算法編制的程序的運行時間進行比較,從而肯定算法效率的高低;該種方式有兩個特色,第一:必需要經過設計好的測試程序和數據進行效率檢測,可是經過少許的數據沒法很好的判斷算法的好壞,因此咱們須要創造大量的測試數據進行檢驗,對於這個這個數據大量,咱們很難進行評估和設計;第二:該種方式須要花費大量的時間和精力去編制好程序,若是最終結果發現這是一套很糟糕的算法,就前功盡棄;
(2)事前估算方法:在計算機程序編制前,依據統計方法對算法進行估算,咱們能夠發現,一個用高級程序語言編寫的程序在計算機上運行時所消耗的時間取決於下列因素:
一、編譯產生的代碼質量;
二、算法採用的策略、方法;
三、問題的輸入規模;
四、機器執行指令的速度;
這其中,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)。

一般, 咱們都使用"時間複雜度"來指運行時間的需求,使用"空間複雜度"指空間需求。當不用限定詞地使用"複雜度'時,一般都是指時間複雜度。

3、總結

不少夥伴說,如今 CPU 升級愈來愈快,根本不用考慮算法的優劣,實現功能便可,用戶感受不到算法好壞形成的快慢,可是作個假設:若是CPU在短短几年間,速度提升了 100 倍,這其實已經很誇張了。而咱們的某個算法本能夠寫出時間複雜度是O(n)的程序,卻寫出了O(n 2 )的程序,僅僅由於容易想到,也容易寫。即在O(n 2 )的時間複雜度算法程序下,速度其實只提升了 10 倍,而對於O(n) 複雜度的算法說,那纔是真的 100 倍。 也就是說,一臺老式CPU的計算機運行O(n)的程序和一臺速度提升 100 倍新式CPU運行O(n 2 )的程序。最終效率高的勝利方倒是老式CPU的計算機,緣由就在於算法的優劣直接決定了程序運行的效率,因此算法的重要性可想而知。
最後附上一張經常使用排序算法的效率比較圖:
 
 
參考內容:
《大話數據結構》
相關文章
相關標籤/搜索