1. 程式人生 > >算法初步

算法初步

hmm HERE asi 5.4 需要 idl dig mda cm4

0. 從1加到100?

先寫一個從1加到100的程序,如何寫呢?
記剛學程序時的寫法:

 int i, sum = 0, n = 100;

 for(i = 0; i < 100; i++)
 {    
     sum += i;
 }
 printf("%d", sum);

大神高斯小學時的解法用程序實現:

 int sum = 0, n = 100;
 sum = (1 + n) * n / 2;
 printf("%d", sum);

我們看到的這兩種解決從1加到100的解決方法,就是算法。

1. 算法定義

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

2. 算法的特性

  • 輸入輸出:算法具有零個或者多個輸入。對於多數算法來說,輸入參數是必要的,但是對於打印“hello world!”這樣的代碼,就不需要參數。算法至少有一個或多個輸出。倘若一個算法沒有輸出,那我們要它何用?當然輸出方式可以是打印輸出或者返回一個或多個值等。
  • 有窮性:指算法在執行有限步驟後,自動結束而不是無限循環,並且每一個步驟在可以接受的時間內執行完成。這裏的有窮也是有邊界的,並不是說執行一個算法需要二三十年也是能完成的,那樣黃瓜菜都涼了,意義不大了。
  • 確定性:算法的每一個步驟都有確定意義的,不會出現二義性。
  • 可行性:算法的每一步驟都必須是可行的,也就是說,每一個步驟都能執行有限次數後完成。

3. 算法效率的度量方法

3.1 事後統計法

通過設計好的測試程序和數據,利用計算機計時器對不同的算法編制的程序的運行時間進行比較,從而確定算法的效率高低。

3.2 事前分析估算法

在算法編制前,根據統計方法對算法進行估算。

算法效率的度量也就是對算法運行時間的度量,而一個程序的運行時間,主要依賴於算法的好壞和輸入規模。
輸入規模即輸入量的多少。
看栗子:

第一種求和算法:

 int i, sum = 0, n = 100;    //執行1次

 for(i = 0; i < 100; i++)    //執行年n+1次
 {    
     sum += i;                //執行n次
 }
 printf("%d", sum);            //執行1次

第二種求和算法:

 int sum = 0, n = 100;    //執行1次
 sum = (1 + n) * n / 2;    //執行1次
 printf("%d", sum);        //執行1次

顯然,第一種算法執行了2n+3次,第二種算法執行了3次,兩種算法的好壞顯而易見。

4. 函數的漸進增長

舉個例子:
相同的輸入規模n,算法A做2n+3次操作,算法B做3n+1次操作。兩個算法誰更快呢?

顯然,答案不確定,當n=1時,算法B快些;當n=2時,兩者相等;當n>2時,算法A快。

此時給出這樣的定義,輸入規模n在沒有限制的情況下,只要超過一個數值N,這個函數就總是大於另一個函數,我們就稱函數是漸進增長的。

函數的漸進增長:給定兩個函數f(n)和g(n),如果存在一個整數N,
使得對於所有的n>N,f(n)總是比g(n)大,那麽,我們說f(n)的增長漸進快於g(n)。

根據函數的漸進增長性我們可以得出:某個算法,隨著n的增大,它會越來越優於另一個算法,或者越來越差於另一個算法。

5. 算法的時間復雜度

5.1算法時間復雜度定義

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

5.2 大O階的推導

大O階的推導:
1.用常數1取代運行時間中的所有加法常數。
2.在修改後的運行次數函數中,只保留最高階項。
3.如果最高階項存在且不是1,則去除與這個項相乘的常數。
得到的結果就是大O階。

5.3 常數階O(1)

 int sum = 0, n = 100;    //執行1次
 sum = (1 + n) * n / 2;    //執行1次
 printf("%d", sum);        //執行1次

5.4 線性階O(n)

 int i;
 for(i = 0; i < n; i++)
 {
 //時間復雜度為O(1)的程序步驟序列
 }

5.5 對數階O(logn)

 int count = 1;
 while(count < n)
 {
     count = count * 2;
 //時間復雜度為O(1)的程序步驟序列
 }

5.6 平方階O(n2)

 int i, j;
 for(i = 0; i < n; i++)
 {
     for(j = 0; j < n; j++)
     {
     //時間復雜度為O(1)的程序步驟序列
     }
 }

計算如下程序的時間復雜度:

 int i, j;
 for(i = 0; i < n; i++)
 {
     for(j = i; j < n; j++)
     {
     //時間復雜度為O(1)的程序步驟序列
     }
 }

當i=1時,內循環執行了n-1次;當i=n-1時,內循環執行了1次,我們可以推算出總的執行次數為:
n+(n-1)+(n-2)+(n-3)+……+1=n(n+1)/2=n2/2+n/2
用大O推導法,可得這段代碼的時間復雜度為O(n2)

5.7 常見時間復雜度

 O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2?)<O(n!)
?

算法初步