1. 程式人生 > >演算法的時間複雜度解釋

演算法的時間複雜度解釋

演算法的時間複雜度分析有兩種方式。
一種方式是計算演算法具體的執行時間,最終根據這個時間的長短評價演算法的優劣。這種估計方法比較簡單易
於操作,但是這種方法有一個缺點:估計時間會隨著計算機的不同而產生變化(不同計算機的配置、同一個
計算機所處環境不同都會影響)。
另一種方式是隻記錄演算法的關鍵操作。


例如這個程式:
--------------------------------------------
for (int a = 0; a < num1; a++)
{
for (int b = 0; b < num2; b++)
{
num[a][b] = b;
}
}
--------------------------------------------
其程式碼段中出現了迴圈語句的巢狀。應該使用乘法法則,所以O(T(n))=O(num1*num2)。


迴圈語句的迴圈條件會對我們計算演算法時間複雜度產生一定的迷惑作用。很多初學者認為迴圈次數越少的
演算法在時間開銷方面越小。從原理上說這是對的但不要忘記,大O表示法只是演算法在時間開銷方面的數量
級,若數量級相同,即使兩個演算法執行關鍵操作的步數實際上並不相同,那麼也把它們看做是時間複雜度
相等的兩個演算法。
舉例下面的程式:
--------------------------------------------
for (int a = 0; a < num1/2; a++)
{
for (int b = 0; b < num2/2; b++)
{
num[a][b] = b;
}
}
---------------------------------------------
這段程式碼與前面的例子在結構上一模一樣,唯一不同之處在於兩重迴圈的次數減少為原來的一半。用公式
計算這段程式碼的時間複雜度可知O(T(n))=O(num1*num2/4),顯然num1*num2與num1*num2/4具有相同的數量級
兩者均為n的平方,所以這段程式碼與上面的程式碼具有相同的時間複雜度。


例:
---------------------------------------------
Node* Find(const Type& X, Node* ptr)
{
if (ptr == NULL)
{
return NULL;
}
else
if (X < ptr->data)
return Find(X, ptr->leftChild);
else
if (X > ptr->data)
return Find(X, ptr->rightChild);
else
return ptr;
}
--------------------------------------------
上述程式碼定義了函式Find。但在實現部分函式又呼叫了Find自身。
像這種自身定義自身的情況就叫做遞迴。
函式Find的作用是在指標ptr指向的連結串列中尋找變數X,並返回指向X所在結點的指標。這裡連結串列中的數是有
序存放的,現假定它為從小到大的順序。Find的執行過程是:首先令X與連結串列中間的數值進行比較,若相等
,返回結點指標;若小於,則在中間結點左側的連結串列中尋找變數X,尋找方式與上面相同;若大於,則在中
間結點的右側鏈表中尋找變數X,尋找方式與上面相同。如此遞迴下去直到演算法結束為止。(折半查詢法)
這是一種常用的查詢法。
若連結串列的長度為n,則平均查詢的時間為log以2為底n的對數,所以演算法的時間複雜度為O(
[email protected]
)。




通常程式的時間複雜度有(按照從小到大的順序排列):c, [email protected], n, [email protected], n^2, n^3, 2^n, 
3^n, n!。(@表示以2為底,n^2表示n的2次方)
若c表示常數,即演算法的執行時間是固定不變的,不隨程式中其他變數狀態的改變而發生變化。但要注意,
語句a=1;與語句a=(a+b)*c+(d+e)*f+g/h;的時間複雜度同為c。不可認為後面的賦值語句較長就認為它有更
高的時間複雜度。