演算法分析(時間複雜度和空間複雜度)
演算法分析(時間複雜度和空間複雜度)
對於一個給定的演算法需要做兩項分析,第一就是證明演算法的正確性,第二就是計算演算法的複雜度。演算法的複雜度包括時間複雜度和空間複雜度。
1 度量演算法效率的方法
共存在兩種方法:事後統計法和事前分析估計演算法。
事後統計法:先將演算法實現,然後輸入適當的資料執行,計算演算法的時間複雜度和空間複雜度。
事前分析估演算法(漸進複雜度):對演算法所消耗資源的一種估算方法。比較常用。
本文主要是漸進複雜度的解釋。
2 演算法的時間複雜度
影響演算法時間複雜度的主要因素是問題規模。
問題規模:是指輸入量的多少。規模大的輸入量需要的執行時間更長。所以執行演算法所需要的時間T的問題是問題規模n的函式,記作T(n)。
為了客觀的表示一個演算法的執行時間,可以用基本語句的執行次數來度量演算法的工作量。
定義:一般情況下,演算法中基本操作重複執行的次數是問題規模n的某個函式,用T(n)表示,若有某個輔助函式f(n),使得當n趨近於無窮大時,T(n)/f(n)的極限值為不等於零的常數,則稱f(n)是T(n)的同數量級函式。記作T(n)=O(f(n)),稱O(f(n)) 為演算法的漸進時間複雜度,簡稱時間複雜度。
通常採用大O記號表示。
時間複雜度分析的基本策略是:從內向外分析,從最深層開始分析。如果遇到函式呼叫,要深入函式進行分析。
3 求解時間複雜度的步驟
(1)找出演算法的基本語句,一般是迴圈體。
(2)計算基本語句執行次數的數量級,也就是基本語句執行次數函式的最高次冪。可忽略低次冪和係數。
(3)用大O記號表示時間複雜度。
4 計算時間複雜度常用性質
(1)一些簡單的輸入輸出賦值語句,近似為O(1)。
(2)對於順序結構需要求和法則。
求和法則:若T1(n)=O(f(n))、 T2(n)=O(g(n)),則 T1(n)+T2(n)=O(max(f(n), g(n)))。
(3)對於選擇結構(if判斷),需要看執行語句。
(4)對於迴圈結構採用乘法法則。
乘法法則:若T1(n)=O(f(n))、 T2(n)=O(g(n)),則 T1*T2=O(f(n)*g(n))。
如果演算法中包含巢狀的迴圈,則基本語句通常是最內層的迴圈體,如果演算法中包含並列的迴圈,則將並列迴圈的時間複雜度相加。
5 常用時間複雜度示例
常見的時間複雜度有:常數階O(1),對數階O(log2n),線性階O(n), 線性對數階O(nlog2n),平方階O(n2),立方階O(n3)。由小到大依次為:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<Ο(2n)<Ο(n!)。
(1)Ο(log2n)(二分查表)
decimal Factorial(int n)
{
if (n == 0)
return 1;
else
return n * Factorial(n - 1);
}
(2)O(n)(一次for迴圈)
decimal Factorial(int n)
{
if (n == 0)
return 1;
else
return n * Factorial(n - 1);
}
(3)Ο(nlog2n)(快排)
void quickSort(int arr[], int left, int right)
{
if (left < right)
{
int key = arr[left];
int i = left, j = right;
while (i < j)
{
while (arr[j] > key && j > i)
j--;
if (i < j)
arr[i++] = arr[j];
while (arr[i] < key && i < j)
i++;
if (i < j)
arr[j--] = arr[i];
}
arr[i] = key;
quickSort(arr, left, i - 1);
quickSort(arr, i + 1, right);
}
}
(4)O(n2)(氣泡排序)
void BubbleSort(int arr[],int num)
{
int i,j;
int temp=0;
for(i=0;i<num-1;i++)
{
for(j=0;j<num-i-1;j++)
{
if(arr[j]>arr[j+1])
{
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
6 演算法的空間複雜度
空間複雜度定義了為演算法所消耗的儲存空間。是演算法執行是所佔用儲存空間大小的量度。