日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

大话数据结构之算法 时间复杂度

發(fā)布時間:2024/4/17 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 大话数据结构之算法 时间复杂度 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

http://www.cnblogs.com/danyingjie/archive/2011/11/17/2252466.html

時間復(fù)雜度用O()來體現(xiàn),我們稱之為大O記法。記做:T(n)=O(f(n))

一般情況下隨著n的增大,Tn)增長最慢的算法為最優(yōu)算法。

O1)叫常數(shù)階 On)叫線性階 On2)叫平方階

?

推倒大O

1.?????? 用常數(shù)1取代運(yùn)行時間中的所有加法常數(shù)

2.?????? 在修改后的運(yùn)行次數(shù)函數(shù)中,只保留最高階項。

3.?????? 如果最高階項存在且不是1,則去除與這個項相乘的常數(shù)。

得到的結(jié)果就是大O階。

?

對于高斯算法而言,這個算法的運(yùn)行次數(shù)函數(shù)是f(n)=3,根據(jù)我們推導(dǎo)大O階的方法,第一步就是把常數(shù)項3改為1。在保留最高階項時發(fā)現(xiàn),它根本沒有最高階項,所以這個算法的時間復(fù)雜度為O(1)

?

對于分支結(jié)構(gòu)而言,無論是真,還是假,執(zhí)行的次數(shù)都是恒定的,不會隨著n的變大而發(fā)生變化,所以單純的分支結(jié)構(gòu)(不包含在循環(huán)結(jié)構(gòu)中),其時間復(fù)雜度也是O1)。

?

線性階:

Int I;

For(i=0;i<n;i++)

{

?

}

因為循環(huán)體中的代碼要執(zhí)行N次,所以它的循環(huán)的時間復(fù)雜度為O(n)

?

對數(shù)階:

Int count=1;

While (count<n)

{

?? Count=count*2;

}

由于每次count乘以2以后,就距離n更近了一分。也就是,有多少個2相乘以后大于n,則會退出循環(huán)。由 2x=n 得到x=log2n。所以這個循環(huán)的時間復(fù)雜度為O(logn)

?

?

最壞情況運(yùn)行時間是一種保證,那就是運(yùn)行時間將不會再壞了。在應(yīng)用中,這是一種最重要的需求,通常,除非特別指定,我們提到的運(yùn)行時間都是最壞情況的運(yùn)行時間。

?

?

算法空間復(fù)雜度通過計算算法所需的存儲空間實現(xiàn),算法空間復(fù)雜度的計算公式記做:S(n)=O(f(n)),其中n為問題的規(guī)模,f(n)為語句關(guān)于n所占存儲空間的函數(shù)。

常見的時間復(fù)雜度所耗時間的大小排列

O(1)<O(logn)<O(n)<O(nlogn)<O(n2)

?

http://blog.csdn.net/hitwhylz/article/details/12374407

算法的時間復(fù)雜度定義為:

在進(jìn)行算法分析時,語句總的執(zhí)行次數(shù)T(n)是關(guān)于問題規(guī)模n的函數(shù),進(jìn)而分析T(n)隨n的變化情況并確定T(n)的數(shù)量級。算法的時間復(fù)雜度,也就是算法的時間量度,記作:T(n}=0(f(n))。它表示隨問題規(guī)模n的增大,算法執(zhí)行時間的埔長率和 f(n)的埔長率相同,稱作算法的漸近時間復(fù)雜度,簡稱為時間復(fù)雜度。其中f( n)是問題規(guī)橫n的某個函數(shù)。

根據(jù)定義,求解算法的時間復(fù)雜度的具體步驟是:

  ⑴ 找出算法中的基本語句;
  算法中執(zhí)行次數(shù)最多的那條語句就是基本語句,通常是最內(nèi)層循環(huán)的循環(huán)體。
  ⑵ 計算基本語句的執(zhí)行次數(shù)的數(shù)量級;
  只需計算基本語句執(zhí)行次數(shù)的數(shù)量級,這就意味著只要保證基本語句執(zhí)行次數(shù)的函數(shù)中的最高次冪正確即可,可以忽略所有低次冪和最高次冪的系數(shù)。這樣能夠簡化算法分析,并且使注意力集中在最重要的一點上:增長率。
  ⑶ 用大Ο記號表示算法的時間性能。
  將基本語句執(zhí)行次數(shù)的數(shù)量級放入大Ο記號中。


如何推導(dǎo)大o階呢?我們給出了下面 的推導(dǎo)方法:

1.用常數(shù)1取代運(yùn)行時間中的所有加法常數(shù)。
2.在修改后的運(yùn)行次數(shù)函數(shù)中,只保留最髙階項。
3.如果最高階項存在且不是1,則去除與這個項相乘的常數(shù)。

簡單的說,就是保留求出次數(shù)的最高次冪,并且把系數(shù)去掉。 ?如T(n)=2n^2+n+1 =O(n^2)

舉個例子。

[cpp] view plaincopyprint?
  • #include?"stdio.h" ??
  • ??
  • int?main()??
  • {??
  • ????int?i,?j,?x?=?0,?sum?=?0,?n?=?100;??/*?執(zhí)行1次?*/??
  • ????for(?i?=?1;?i?<=?n;?i++)????/*?執(zhí)行n+1次?*/??
  • ????{??
  • ????????sum?=?sum?+?i;???????????????/*?執(zhí)行n次?*/?????
  • ????????for(?j?=?1;?j?<=?n;?j++)????/*?執(zhí)行n*(n+1)次?*/??
  • ????????{??
  • ????????????x++;????????????????/*?執(zhí)行n*n次?*/??
  • ????????????sum?=?sum?+?x;??????/*?執(zhí)行n*n次?*/??
  • ????????}??
  • ????}??
  • ????printf("%d",?sum);??????????/*?執(zhí)行1次?*/??
  • }??
  • #include "stdio.h"int main() {int i, j, x = 0, sum = 0, n = 100; /* 執(zhí)行1次 */for( i = 1; i <= n; i++) /* 執(zhí)行n+1次 */{sum = sum + i; /* 執(zhí)行n次 */ for( j = 1; j <= n; j++) /* 執(zhí)行n*(n+1)次 */{x++; /* 執(zhí)行n*n次 */sum = sum + x; /* 執(zhí)行n*n次 */}}printf("%d", sum); /* 執(zhí)行1次 */ }



    ?

    按照上面推導(dǎo)“大O階”的步驟,我們來看

    第一步:“用常數(shù) 1 取代運(yùn)行時間中的所有加法常數(shù)”,

    則上面的算式變?yōu)?#xff1a;執(zhí)行總次數(shù) =3n^2 + 3n + 1

    (直接相加的話,應(yīng)該是T(n) = 1 + n+1 + n + n*(n+1) + n*n + n*n + 1 = 3n^2 + 3n + 3。現(xiàn)在用常數(shù) 1 取代運(yùn)行時間中的所有加法常數(shù),就是把T(n) = 3n^2 + 3n + 3中的最后一個3改為1. 就得到了 T(n) = 3n^2 + 3n + 1)


    ?

    第二步:“在修改后的運(yùn)行次數(shù)函數(shù)中,只保留最高階項”。

    這里的最高階是 n 的二次方,所以算式變?yōu)?#xff1a;執(zhí)行總次數(shù) = 3n^2


    ?

    第三步:“如果最高階項存在且不是 1 ,則去除與這個項相乘的常數(shù)”。

    這里 n 的二次方不是 1 所以要去除這個項的相乘常數(shù),算式變?yōu)?#xff1a;執(zhí)行總次數(shù) = n^2


    因此最后我們得到上面那段代碼的算法時間復(fù)雜度表示為: O( n^2 )


    下面我把常見的算法時間復(fù)雜度以及他們在效率上的高低順序記錄在這里,使大家對算法的效率有個直觀的認(rèn)識。

    O(1) 常數(shù)階 < O(logn) 對數(shù)階 < O(n) 線性階 < O(nlogn) < O(n^2) 平方階 < O(n^3) < { O(2^n) < O(n!) < O(n^n) }

    最后三項用大括號把他們括起來是想要告訴大家,如果日后大家設(shè)計的算法推導(dǎo)出的“大O階”是大括號中的這幾位,那么趁早放棄這個算法,在去研究新的算法出來吧。因為大括號中的這幾位即便是在 n 的規(guī)模比較小的情況下仍然要耗費(fèi)大量的時間,算法的時間復(fù)雜度大的離譜,基本上就是“不可用狀態(tài)”。



    好了,原理就介紹到這里了。下面通過幾個例子具體分析下時間復(fù)雜度計算過程。

    一。計算 1 + 2 + 3 + 4 + ...... + 100。

    常規(guī)算法,代碼如下:

    [cpp] view plaincopyprint?
  • #include?"stdio.h" ??
  • ??
  • int?main()??
  • {??
  • ????int?i,?sum?=?0,?n?=?100;????/*?執(zhí)行1次?*/??
  • ????for(?i?=?1;?i?<=?n;?i++)?/*?執(zhí)行?n+1?次?*/??
  • ????{??
  • ????????sum?=?sum?+?i;??????????/*?執(zhí)行n次?*/??
  • ????????//printf("%d?\n",?sum); ??
  • ????}??
  • ????printf("%d",?sum);??????????/*?執(zhí)行1次?*/??
  • }??
  • #include "stdio.h"int main() {int i, sum = 0, n = 100; /* 執(zhí)行1次 */for( i = 1; i <= n; i++) /* 執(zhí)行 n+1 次 */{sum = sum + i; /* 執(zhí)行n次 *///printf("%d \n", sum);}printf("%d", sum); /* 執(zhí)行1次 */ }


    從代碼附加的注釋可以看到所有代碼都執(zhí)行了多少次。那么這寫代碼語句執(zhí)行次數(shù)的總和就可以理解為是該算法計算出結(jié)果所需要的時間。該算法所用的時間(算法語句執(zhí)行的總次數(shù))為: 1 + ( n + 1 ) + n + 1 = 2n + 3

    而當(dāng) n 不斷增大,比如我們這次所要計算的不是 1 + 2 + 3 + 4 + ...... + 100 = ? 而是 1 + 2 + 3 + 4 + ...... + n = ?其中 n 是一個十分大的數(shù)字,那么由此可見,上述算法的執(zhí)行總次數(shù)(所需時間)會隨著 n 的增大而增加,但是在 for 循環(huán)以外的語句并不受 n 的規(guī)模影響(永遠(yuǎn)都只執(zhí)行一次)。所以我們可以將上述算法的執(zhí)行總次數(shù)簡單的記做: 2n 或者簡記 n

    這樣我們就得到了我們設(shè)計的算法的時間復(fù)雜度,我們把它記作: O(n)


    再來看看高斯的算法,代碼如下:

    [cpp] view plaincopyprint?
  • #include?"stdio.h" ??
  • ??
  • int?main()??
  • {??
  • ????int?sum?=?0,?n?=?100;???/*?執(zhí)行1次?*/??
  • ????sum?=?(1?+?n)?*?n/2;????/*?執(zhí)行1次?*/??
  • ??
  • ????printf("%d",?sum);??????/*?執(zhí)行1次?*/??
  • }??
  • #include "stdio.h"int main() {int sum = 0, n = 100; /* 執(zhí)行1次 */sum = (1 + n) * n/2; /* 執(zhí)行1次 */printf("%d", sum); /* 執(zhí)行1次 */ }


    這個算法的時間復(fù)雜度: O(3),但一般記作 O(1)。

    從感官上我們就不難看出,從算法的效率上看,O(1) < O(n) 的,所以高斯的算法更快,更優(yōu)秀。

    這也就難怪為什么每本算法書開篇都是拿高斯的這個例子來舉例了(至少我看的都是)...人家也確實有那個資本。



    二。求兩個n階方陣C=A*B的乘積其算法如下:

    [cpp] view plaincopyprint?
  • //右邊列為語句執(zhí)行的頻度 ??
  • ??
  • ???void?MatrixMultiply(int?A[n][n],int?B?[n][n],int?C[n][n])??
  • ??
  • ???{??
  • ??
  • (1)?for(int?i=0;?i?<n;?i++)???????????????????????//n+1 ??
  • ??
  • ??????{??
  • ??
  • (2)??????for?(j=0;j?<?n;?j++)???????????????????????//n*(n+1) ??
  • ??
  • ???????????{??
  • ??
  • (3)???????????C[i][j]=0;??????????????????????????????????//n^2 ??
  • ??
  • (4)???????????for?(k=0;?k<n;?k++)?????????????????//n^2*(n+1) ??
  • ??
  • ???????????????{??
  • ??
  • (5)??????????????C[i][j]=C[i][j]+A[i][k]*B[k][j];?//n^3 ??
  • ??
  • ??????????????}??
  • ??
  • ??????????}??
  • ??
  • ??????}??
  • ??
  • ??}??
  • //右邊列為語句執(zhí)行的頻度void MatrixMultiply(int A[n][n],int B [n][n],int C[n][n]){(1) for(int i=0; i <n; i++) //n+1{(2) for (j=0;j < n; j++) //n*(n+1){(3) C[i][j]=0; //n^2(4) for (k=0; k<n; k++) //n^2*(n+1){(5) C[i][j]=C[i][j]+A[i][k]*B[k][j]; //n^3}}}}

    則該算法所有語句的頻度之和為:

    T(n) = 2n^3+3n^2+2n+1; ?利用大O表示法,該算法的時間復(fù)雜度為O(n^3)。


    三。分析下列時間復(fù)雜度

    [cpp] view plaincopyprint?
  • void?test_(int?n)??
  • {??
  • ????i?=?1,?k?=?100;??
  • ????while?(i<n)??
  • ????{??
  • ????????k?=?k?+?1;??
  • ????????i?+=?2;??
  • ????}??
  • }??
  • void test_(int n) {i = 1, k = 100;while (i<n){k = k + 1;i += 2;} }


    設(shè)for循環(huán)語句執(zhí)行次數(shù)為T(n),則 i = 2T(n) + 1 <= n - 1, ?即T(n) <= n/2 - 1 = O(n)


    四。分析下列時間復(fù)雜度

    [cpp] view plaincopyprint?
  • void?test_2(int?b[],?int?n)??
  • {??
  • ????int?i,?j,?k;??
  • ????for?(i=0;?i<n-1;?i++)??
  • ????{??
  • ????????k?=?i;??
  • ????????for?(j=i+1;?j<n;?j++)??
  • ????????{??
  • ????????????if?(b[k]?>?b[j])??
  • ????????????{??
  • ????????????????k?=?j;??
  • ????????????}??
  • ????????}??
  • ????????x?=?b[i];??
  • ????????b[i]?=?b[k];??
  • ????????b[k]?=?x;??
  • ????}??
  • }??
  • void test_2(int b[], int n) {int i, j, k;for (i=0; i<n-1; i++){k = i;for (j=i+1; j<n; j++){if (b[k] > b[j]){k = j;}}x = b[i];b[i] = b[k];b[k] = x;} }


    其中,算法的基本運(yùn)算語句是

    if (b[k] > b[j])

    {

    ? ?k = j;

    }

    其執(zhí)行次數(shù)T(n)為:



    五。分析下列時間復(fù)雜度

    [cpp] view plaincopyprint?
  • void?test_3(int?n)??
  • {??
  • ????int?i?=?0,?s?=?0;??
  • ????while?(s<n)??
  • ????{??
  • ????????i++;??
  • ????????s?=?s?+?i;??
  • ????}??
  • }??
  • void test_3(int n) {int i = 0, s = 0;while (s<n){i++;s = s + i;} }



    ?

    其中,算法的基本運(yùn)算語句即while循環(huán)內(nèi)部分,

    設(shè)while循環(huán)語句執(zhí)行次數(shù)為T(n),則



    六。Hanoi(遞歸算法)時間復(fù)雜度分析

    [cpp] view plaincopyprint?
  • void?hanoi(int?n,?char?a,?char?b,?char?c)??
  • {??
  • ????if?(n==1)??
  • ????{??
  • ????????printf("move?%d?disk?from?%c?to?%c?\n",?n,?a,?c);??//執(zhí)行一次 ??
  • ????}??
  • ????else??
  • ????{??
  • ????????hanoi(n-1,?a,?c,?b);????//遞歸n-1次 ??
  • ????????printf("move?%d?disk?from?%c?to?%c?\n",?n,?a,?c);??//執(zhí)行一次 ??
  • ????????hanoi(n-1,?b,?a,?c);????//遞歸n-1次 ??
  • ????}??
  • }??
  • void hanoi(int n, char a, char b, char c) {if (n==1){printf("move %d disk from %c to %c \n", n, a, c); //執(zhí)行一次}else{hanoi(n-1, a, c, b); //遞歸n-1次printf("move %d disk from %c to %c \n", n, a, c); //執(zhí)行一次hanoi(n-1, b, a, c); //遞歸n-1次} }


    對于遞歸函數(shù)的分析,跟設(shè)計遞歸函數(shù)一樣,要先考慮基情況(比如hanoi中n==1時候),這樣把一個大問題劃分為多個子問題的求解。

    故此上述算法的時間復(fù)雜度的遞歸關(guān)系如下:











    ?

    總結(jié)

    以上是生活随笔為你收集整理的大话数据结构之算法 时间复杂度的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。