演算法的基本概念

Galois發表於2020-09-05

演算法

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

上面這句話是官方定義,太複雜了,簡單來說就是:解題的技巧和方式。

演算法的特點包括:

  • 輸出
    • 至少有一個或多個輸出。
  • 輸入
    • 至少有一個或多個輸入。
  • 有窮性
    • 指演算法在執行有限的步驟之後,自動結束而不會出現無限迴圈,並且每一個步驟在可接受的時間內完成。
  • 確定性
    • 演算法的每一個步驟都具有確定的含義,不會出現二義性。
      演算法在一定條件下,只有一條執行路徑,相同的輸入只有一條執行路徑,相同的輸入只能由唯一的輸出結果。
  • 可行性
    • 演算法的每一步都必須是可行的,也就是說,每一步都能透過執行有限次數完成。

演算法設計的要求包括正確性、健壯性、可讀性。

演算法效率

事後統計法
透過設計好的測試程式和資料,利用計算機計時器對不同演算法編制的程式的執行時間進行比較,從而確定演算法效率的高低。

事後統計法的缺陷:

  1. 要依據演算法,之前先編好程式。
  2. 時間的比較依賴計算機的硬體和軟體,還有環境因素。
  3. 測試資料設計困難。

事前分析評估方法
在計算機程式編制前,依據統計方法對演算法進行估算。
演算法效率的高低因素來自以下幾點:

  1. 演算法採用的策略、方法
    • 演算法好壞的根本。
  2. 編譯產生的程式碼質量
    • 由軟體來支援。
  3. 問題的輸入規模
  4. 計算機執行指令的速度
    • 看硬體的效能。

拋開硬體軟體的因素,可以這樣總結:
一個程式在執行時間上是依賴於演算法的好壞和問題的輸入規模。

演算法時間複雜度

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

時間複雜度的記法:
大O記法:O(\ \ )
一般情況下,隨著輸入規模n的增大,T(n)增長最慢的演算法為最優演算法。

分析一個演算法的時間複雜度的方法:

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

線性階

線性階的迴圈結構會複雜很多。要確定某個演算法的階次,我們常常需要確定某個特定語句或某個語句集執行的次數。因此,我們要分析演算法的複雜度,關鍵就是要分析迴圈結構的執行情況。
C 語言例:

int i, n=100, sum=0;
for(i=0; i<n; i++)
{
    sum = sum + i;
}

該例時間複雜度為 O(n),因為迴圈體中的程式碼需要執行 n 次。

平方階

如果是巢狀呢?

迴圈的時間複雜度等於迴圈體的複雜度乘以該迴圈執行的次數。

C 語言例:

int i,j,n=100;
for(i=0; i<n; i++)
{
    for(j=0; j<n; j++)
    {
        printf("I love learnku.com\n");
    }
}

該例時間複雜度為 O(n2)。
如果由三個這樣的巢狀迴圈,時間複雜度將會是 O(n3)。

對數階

C 語言例:

int i=1, n=100;
while(i<n)
{
    i = i * 2;
}

每次 i * 2 之後,就距離 n 更近一步,假設有 x 個 2 相乘後大於或等於 n,則會退出迴圈。

2x=n 得到 x=log(2)n,所以這個迴圈的時間複雜度為 O(logn)

常見的時間複雜度所消耗時間的大小排列:

O(1)< O(\log n)< O(n)< O(n\log n)< O(n^2)< O(2n)< O(n!)< O(n^n)

最壞情況和平均情況

查詢一個有 n 個隨機數字陣列中的某個數字,最好的情況是第一個陣列就是,那麼演算法的時間複雜度為 O(1),但也有可能這個數字就在最後一個位置上待著,那麼演算法的時間複雜度就是 O(n),這是最壞的一種情況了。
A H U J I L O P
H U J I L O P A

最壞情況執行時間是一種保證,執行時間=最壞情況的執行時間。
平均執行時間是期望的執行時間。平均的查詢時間=n/2 次後發現目標元素。

對演算法的分析
平均時間複雜度:計算所有情況的平均值
最壞時間複雜度:計算最壞情況下的時間複雜度

在沒有特殊說明的情況下,都是指最壞時間複雜度。

空間複雜度

空間複雜度表示的是儲存空間的複雜度,而不是演算法的時間複雜度。
案例問題:
給出一個年費,計算出該年份是否是閏年。
這個問題可以設計一個演算法,輸入一個年份,透過演算法的執行,之後得到是否是閏年的結果。
這個問題也可以事先給出一張年份表,每個年份有對應值 0 或者 1,1 代表該年是閏年,0 代表不是閏年。
這樣的話就把問題巧妙的轉化成了一個查詢問題,直接查詢輸入年份的對應值就能得到結果。這樣的做法最佳化了時間複雜度,但增加了空間複雜度,因為需要開闢一塊空間來儲存這張年份表。

當不用限定詞的時候,直接說複雜度的時候,通常都指的是時間複雜度。

本作品採用《CC 協議》,轉載必須註明作者和本文連結
不要試圖用百米衝刺的方法完成馬拉松比賽。

相關文章