時間復雜度的表示、分析、計算方法……一文帶你看懂時間復雜度!

如果你還在發愁究竟怎么計算時間復雜度和空間復雜度,那你是來對地方了!

名詞解釋:

在計算機科學中,時間復雜性,又稱時間復雜度,算法的時間復雜度是一個函數,它定性描述該算法的運行時間。這是一個代表算法輸入值的字符串的長度的函數。時間復雜度常用大O符號表述,不包括這個函數的低階項和首項系數。使用這種方式時,時間復雜度可被稱為是漸近的,亦即考察輸入值大小趨近無窮時的情況。

時間復雜度的表示方法

其實就是算法(代碼)的執行效率,算法代碼的執行時間。我們來看下面一個簡單的代碼:

int??sumFunc (int? n) {??int??num? =? 0;

//執行一次

for??(in? ti =1; i? <= n; ++i)? {

//執行n次? ?

?num = num + i;

//執行n次?

?}

return??num ;

}

假設,每行代碼的執行時間為t,那么這塊代碼的時間就是(2n+2)*t

由此得出:?代碼執行時間T(n)與代碼的執行次數是成正比的!

那么我們來看下一個例子:

int??sumFunc? (int??n)? {??int??num? =? 0;

//執行一次

for??(int??i =1; i <= n; ++i)? {

//執行n次

for?(int??j =1; j <= n; ++j)? {

//執行n*n次? ? ?

?num =? num + i * j;

//執行n*n次

? ? }??

}

}

同理,該代碼執行時間為(2n*n+n+1)*t,沒意見吧?繼續往后看!

注意:?在數據結構/算法中,通常使用T(n)表示代碼執行時間,n表示數據規模大小,f(n)表示代碼執行次數綜合,所以上面這個例子可以表示為?f(n)=(2n*n+n+1)*t?,其實就是一個求總和的式子,?O?(大寫O)表示代碼執行時間與?f(n)?成正比例。

根據上面兩個例子得出結論:?代碼的執行時間 T(n)與每行代碼的執行次數 n 成正比?,人們把這個規律總結成這么一個公式:?T(n) = O(f(n))

所以呢,第一個例子中的 T(n)=O(2n+1),第二個例子中的 T(n)=O(2n*n+n+1),這就是時間復雜度表示法,也叫大O時間復雜度表示法。

但是,?大O時間復雜度?并不具體表示代碼?真正的執行時間?,而是表示?代碼執行時間隨數據規模增長的變化趨勢?,所以,也叫作?漸進時間復雜度?,簡稱?時間復雜度?。

與泰勒公式相反的是,算了,扯哪去了…

當n變得越來越大時,公式中的低階,常量,系數三部分影響不了其增長趨勢,所以可以直接忽略他們,只記錄一個最大的量級就可以了,所以上述兩個例子實際他們的時間復雜度應該記為:T(n)=O(n) ,T(n)=O(n*n)

我想你應該明白大致是怎么回事了,那么我們來看看如何去計算它?

時間復雜度的分析與計算方法

(1)循環次數最多原則

我們上面說過了,當n變得越來越大時,公式中的低階,常量,系數三部分影響不了其增長趨勢,可以直接忽略他們,只記錄一個最大的量級就可以了。因此我們在計算時間復雜度時,?只需關注循環次數最多的那段代碼即可。

int sumFunc (int n) {

int sum =0 ;? ? ?//執行1次,忽略不計

for (int i =0; i? <? n; i++)? {

sum += i;? ? ? ?// 循環內執行次數最多,執行次數為n次,因此時間復雜度記為O(n)

}

return sum;? ? //執行1次,忽略不計

}

(2)加法原則

int sumFunc (int n) {

int sum = 0;? ? ?//常量級,忽略

for (int i = 0; i < 99; i++)? {

sum += i;? ? ? //執行100次,還是常量級,忽略

}

for (int i = 0; i < n; i++)? {

sum += i;? ? ?//執行n次

}

for? (int? i =? 0; i? <? n; i++)? {

for? (int? j = 0; j < n; j++)? {

sum += i;? ? //執行n*n次

}

}

return? sum;

}

上述例子中,最大的兩塊代碼時間復雜度分別為 O(n)和O(n*n),其結果本應該是:T(n)=O(n)+O(n*n),我們取其中最大的量級,因此整段代碼的復雜度為:O(n * n)

所以得出結論:?量級最大的那段代碼時間復雜度=總的時間復雜度

(3)乘法原則

嵌套代碼的復雜度等于嵌套內外代碼復雜度的乘積

void? Func1 (int? n)? {

for? (int? i = 0; i? <? n; i++)? ?{

?Func2(n);? ? ?//執行n次,每次都會調用Func2函數執行n次

? ? ?}

}

void? Func2 (int? n)? {

int? sum = 0;

for? (int? i = 0; i < n; i++)

?{

?sum +=1;? ??//執行n次

}

}

因此這段代碼時間復雜度為?O(n) * O(n) = O(n*n) = O(n*n)

同理,如果將其中一個n換成m,那么它的時間復雜度就是?O(n*m)

常見的幾種時間復雜度

(1)O(1)常量級時間復雜度

void??Func?(void)? {

for??(int??i =? 0; i? ?<? 100; i++)? {

printf("hello");? ? ?//執行一百次,也是常量級,記為O(1)

}

}

void??Func?(void)? {

printf("hello");

printf("hello");

printf("hello");

//各執行一次,還是記為O(1)

}

相信你也看明白了,O(1)不是說代碼只有一行,這個1它代表的是一個常量,即使它有以前一萬行這樣的也是O(1),因為它是固定的不會變化(也就是常量),?所以凡是常量級復雜度代碼,均記為O(1)

(2)常見的O(n)復雜度

void??Func?(int??n)? {??

for??(int??i =0; i < n; i++)? ?{

printf("hello");??

}

}

不用多說了吧!繼續!

(3)O(logn),O(nlogn) ,這就有點難度了!

首先我們來回憶以下換底公式:

記住公式啊,來看例子:

void? Func (int? n)? {

for? (int? i = 1; i < n; i++)? ?{?

?i = i *2;

?}

}

可以看出,i = i * 2這行代碼執行次數是最多的,那么到底執行了多少次呢?

第一次 i=2,執行第二次 i=4,執行第三次 i=8…

假設它執行了x次,那么x的取值為:

當上述代碼的2改成3的時候,x的取值也就是:

當然不管log的底數是幾,是e也好,是10也罷,統統記為:

這是為啥子念?由換底公式可以計算出:

換底之后,可以看出log3(2)其實就是一個常數,忽略它!而在這場游戲中,log默認就是以2為底的,所以統統記為?O(logn)?。

void? Func (int? n)? {

for (int? i =? 0; i < n; i++)? ?{? ?

?Func2(n);? ? ?//執行n次,嵌套調用,每次調用執行logn次

}

}

void? Func2 ( int n)? {

for (int? i =0; i < n; i++)? ?{??

? i = i *2;? ? ?//執行logn次

}

}

所以這個O(nlogn)也很好理解了吧!

上面都是自己整理好的!我就把資料貢獻出來給有需要的人!順便求一波關注.

哈哈~各位小伙伴關注我后點擊:? ?java架構交流群

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容