算法時間複雜度計算方式

【對於一個給定的算法,通常要評估其正確性和運行效率的高低。算法的正確性評估不在本文範圍之內,本文主要討論從算法的時間複雜度特性去評估算法的優劣。】

如何衡量一個算法的好壞呢?

顯然,選用的算法應該是正確的(算法的正確性不在此論述)。除此之外,通常有三個方面的考慮:

(1)算法在執行過程中所消耗的時間;

(2)算法在執行過程中所佔資源的大小,例如,佔用內存空間的大小;

(3)算法的易理解性、易實現性和易驗證性等等。

本文主要討論算法的時間特性,並給出算法在時間複雜度上的度量指標。

在各種不同的算法中,若算法語句的執行次數爲常數,則算法的時間複雜度爲O(1),按數量級遞增排列,常見的時間複雜度量有:

(1)O(1):常量階,運行時間爲常量

(2)O(logn):對數階,如二分搜索算法

(3)O(n):線性階,如n個數內找最大值

(4)O(nlogn):對數階,如快速排序算法

(5)O(n^2):平方階,如選擇排序,冒泡排序

(6)O(n^3):立方階,如兩個n階矩陣的乘法運算

(7)O(2^n):指數階,如n個元素集合的所有子集的算法

(8)O(n!):階乘階,如n個元素全部排列的算法

下圖給出了隨着n的變化,不同量級的時間複雜度變化曲線。

複雜度 10 20 50 100 1000 10000 100000
O(1)

<1s

<1s

<1s

<1s

<1s

<1s

<1s

O(log2(n))

<1s

<1s

<1s

<1s

<1s

<1s

<1s

O(n)

<1s

<1s

<1s

<1s

<1s

<1s

<1s

O(n*log2(n))

<1s

<1s

<1s

<1s

<1s

<1s

<1s

O(n2)

<1s

<1s

<1s

<1s

<1s

2s

3-4 min

O(n3)

<1s

<1s

<1s

<1s

20s

 5 hours 

 231 days 

O(2n)

<1s

<1s

 260 days 

 hangs 

 hangs 

hangs

hangs

O(n!)

<1s

 hangs 

hangs

 hangs 

hangs

hangs

hangs

O(nn)

 3-4 min 

hangs

hangs

 hangs 

hangs

hangs

hangs

評估算法時間複雜度的具體步驟是:

(1)找出算法中重複執行次數最多的語句的頻度來估算算法的時間複雜度;

(2)保留算法的最高次冪,忽略所有低次冪和高次冪的係數;

(3)將算法執行次數的數量級放入大Ο記號中。

以下對常見的算法時間複雜度度量進行舉例說明:

(1)O(1):常量階,操作的數量爲常數,與輸入的數據的規模無關。n = 1,000,000 -> 1-2 operations

temp=a;
a=b;
b=temp;

用常數1來取代運行時間中所有加法常數;
上面語句共三條操作,單條操作的頻度爲1,即使他有成千上萬條操作,也只是個較大常數,這一類的時間複雜度爲O(1);

(2)O(logn):對數階,如二分搜索算法。操作的數量與輸入數據的規模 n 的比例是 log2 (n)。n = 1,000,000 -> 30 operations

比如: 1,3,5,6,7,9;找出7
如果全部遍歷時間頻度爲n;
二分查找每次砍斷一半,即爲n/2;
隨着查詢次數的提升,頻度變化作表:
查詢次數     時間頻度
1     n/2
2     n/2^2
3     n/2^3
k     n/2^k

當最後找到7的時候時間頻度則是1;
也就是:
n/2^k = 1;
n = 2^k;
k則是以2爲底,n的對數,就是Log2N;
那麼二分查找的時間複雜度就是O(Log2N);
 

(3)O(n):線性階,如n個數內找最大值。操作的數量與輸入數據的規模 n 成正比。n = 10,000 -> 5000 operations

這一類算法中操作次數和n正比線性增長。

(4)O(nlogn):對數階,如快速排序算法

上面看了二分查找,是LogN的(LogN沒寫底數默認就是Log2N);
線性對數階就是在LogN的基礎上多了一個線性階;
比如這麼一個算法流程:
數組a和b,a的規模爲n,遍歷的同時對b進行二分查找,如下代碼:

for(int i =0;i<n;i++)
{
    binary_search(b);
}

(5)O(n^2):平方階,如選擇排序,冒泡排序。操作的數量與輸入數據的規模 n 的比例爲二次平方。n = 500 -> 250,000 operations

long SumMN(int n, int m)
    {
      long sum = 0;
      for (int x = 0; x < n; x++)
        for (int y = 0; y < m; y++)
          sum += x * y;
      return sum;
    }

 

(6)O(n^3):立方階,如兩個n階矩陣的乘法運算。操作的數量與輸入數據的規模 n 的比例爲三次方。n = 200 -> 8,000,000 operations

long SumMNK(int n, int m,int k)
    {
      long sum = 0;
      for (int x = 0; x < n; x++)
        for (int y = 0; y < m; y++)
          for(int z=0;z<k;z++)

           sum += x * y*z;
      return sum;
    }

(7)O(2^n):指數階,如n個元素集合的所有子集的算法。指數級的操作,快速的增長。n = 20 -> 1048576 operations

  • long long Fib(long long N)

  • {

  • return (N < 3) ? 1 : Fib(N - 1) + Fib(N - 2);

  • }

(8)O(n!):階乘階,如n個元素全部排列的算法

 

參考文獻:

https://blog.csdn.net/user11223344abc/article/details/81485842  

https://www.cnblogs.com/gaochundong/p/complexity_of_algorithms.html

https://baijiahao.baidu.com/s?id=1609024533531824968&wfr=spider&for=pc

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章