事后統(tǒng)計方法
事后統(tǒng)計方法:這種方法主要是通過設(shè)計好的測試程序和數(shù)據(jù)缸废,利用計算機計時器對不同算法編制的程序的運行時間進行比較咙轩,從而確定算法效率的高低。
但這種方法顯然是有很大缺陷的:
必須依據(jù)算法事先編制好程序诀姚,這通常需要花費大量的時間和精力疮茄。如果編制出來發(fā)現(xiàn)它根本是很糟糕的算法吝梅,不是竹籃打水一場空嗎?
事前分析估算方法
事前分析估算方法:在計算機程序編寫前妆兑,依據(jù)統(tǒng)計方法對算法進行估算魂拦。
經(jīng)過分析,我們發(fā)現(xiàn)搁嗓,一個用高級程序語言編寫的程序在計算機上運行時所消耗的時間取決于下列因素:
1.編譯產(chǎn)生的代碼質(zhì)量芯勘。
2.算法采用的策略、方法谱姓。
3.問題的輸入規(guī)模借尿。
4.機器執(zhí)行指令的速度。
由此可見屉来,拋開這些與計算機路翻、軟件有關(guān)的因素,一個程序的運行時間依賴于算法的好壞和問題的輸入規(guī)模茄靠。
簡單算法比較
計算1+2+3+...+100的值
第一種算法:
int i, sum = 0,n = 100; /*執(zhí)行1次*/
for(i = 1; i < = n; i++) /*執(zhí)行了n+1次*/
{
sumsum = sum + i; /*執(zhí)行n次*/
}
printf("%d", sum); /*執(zhí)行1次*/
第二種算法:
int sum = 0,n = 100; /*執(zhí)行1次*/
sum = (1 + n) * n/2; /*執(zhí)行1次*/
printf("%d", sum); /*執(zhí)行1次*/
- 第一種算法執(zhí)行了1+(n+1)+n+1=2n+3次茂契。
- 第二種算法執(zhí)行了1+1+1=3次。
事實上兩個算法的第一條和最后一條語句是一樣的慨绳,所以我們關(guān)注的代碼其實是中間的那部分掉冶,我們把循環(huán)看作一個整體,忽略頭尾循環(huán)判斷的開銷脐雪,那么這兩個算法其實就是n次與1次的差距
為什么在這里我們要看成n次與1次的差距厌小,而不是精確到2n+1 與1次的差距?
我們再來延伸一下上面這個例子:
int i, j, x = 0,sum = 0,n = 100; /*執(zhí)行1次*/
for(i = 1; i < = n; i++)
{
for (j = 1; j < = n; j++)
{
x++; /*執(zhí)行n×n次*/
sumsum = sum + x;
}
}
printf("%d", sum); /*執(zhí)行1次*/
這個例子中战秋,i從1到100璧亚,每次都要讓j循環(huán)100次,而當(dāng)中的x++和sum = sum + x脂信;其實就是1+2+3+…+10000癣蟋,也就是1002次透硝,所以這個算法當(dāng)中,循環(huán)部分的代碼整體需要執(zhí)行n2(忽略循環(huán)體頭尾的開銷)次疯搅。顯然這個算法的執(zhí)行次數(shù)對于同樣的輸入規(guī)模n = 100濒生,要多于前面兩種算法,這個算法的執(zhí)行時間隨著n的增加也將遠遠多于前面兩個幔欧。
此時你會看到罪治,測定運行時間最可靠的方法就是計算對運行時間有消耗的基本操作的執(zhí)行次數(shù)。運行時間與這個計數(shù)成正比礁蔗。
我們不關(guān)心編寫程序所用的程序設(shè)計語言是什么规阀,也不關(guān)心這些程序?qū)⑴茉谑裁礃拥挠嬎銠C中,我們只關(guān)心它所實現(xiàn)的算法瘦麸。這樣,不計那些循環(huán)索引的遞增和循環(huán)終止條件歧胁、變量聲明滋饲、打印結(jié)果等操作,最終喊巍,在分析程序的運行時間時屠缭,最重要的是把程序看成是獨立于程序設(shè)計語言的算法或一系列步驟。
可以從問題描述中得到啟示崭参,同樣問題的輸入規(guī)模是n呵曹,求和算法的第一種,求1+2+…+n需要一段代碼運行n次何暮。那么這個問題的輸入規(guī)模使得操作數(shù)量是f(n) = n奄喂,顯然運行100次的同一段代碼規(guī)模是運算10次的10倍。而第二種海洼,無論n為多少跨新,運行次數(shù)都為1,即f(n) = 1坏逢;第三種域帐,運算100次是運算10次的100倍。因為它是f(n) = n2是整。
我們在分析一個算法的運行時間時肖揣,重要的是把基本操作的數(shù)量與輸入規(guī)模關(guān)聯(lián)起來,即基本操作的數(shù)量必須表示成輸入規(guī)模的函數(shù)浮入。
函數(shù)的漸近增長在說函數(shù)的漸近增長的例子前龙优,先說說概念,
函數(shù)的漸近增長:給定兩個函數(shù)f(n)和g(n)舵盈,如果存在一個整數(shù)N陋率,使得對于所有的n > N球化,f(n)總是比g(n)大,那么瓦糟,我們說f(n)的漸近增長快于g(n)筒愚。
文字說明,比較難理解菩浙,我們利用下面的表格來說明
注意:n^2代表n 的平方巢掺,n^3代表n的立方
數(shù)值\函數(shù) | n | 2n | 2n+1 | 3n+8 | n^2 | 2n^2 | 2n^2+2n+1 | n^3 |
---|---|---|---|---|---|---|---|---|
1 | 1 | 2 | 3 | 11 | 1 | 2 | 5 | 1 |
2 | 2 | 4 | 5 | 14 | 4 | 8 | 13 | 8 |
3 | 3 | 6 | 7 | 17 | 9 | 18 | 25 | 27 |
5 | 5 | 10 | 11 | 23 | 25 | 50 | 61 | 125 |
9 | 9 | 18 | 19 | 35 | 81 | 162 | 181 | 729 |
10 | 10 | 20 | 21 | 38 | 100 | 200 | 221 | 1000 |
100 | 100 | 200 | 201 | 308 | 10000 | 20000 | 20201 | 1000000 |
1000 | 1000 | 2000 | 2001 | 3008 | 1000000 | 2000000 | 2002001 | 1000000000 |
10000 | 10000 | 20000 | 20001 | 30008 | 100000000 | 200000000 | 200020001 | 1000000000000 |
100000 | 100000 | 200000 | 200001 | 300008 | 10000000000 | 20000000000 | 20000200001 | 1000000000000000 |
例如:f(n)=2n^2+1,g(n)=2n+1
當(dāng)n=1是f(n)=g(n)劲蜻,這個時候?qū)?yīng)上面的概念陆淀,N=1,當(dāng)n>N先嬉,也就是當(dāng)n>1時轧苫,f(n)>g(n),所以疫蔓,我們說f(n)的漸近增加快于g(n)
為了更好理解這些特點含懊,我做了一些圖表,以便更加清楚的知道為什么
當(dāng)輸入數(shù)值非常大的時候衅胀,兩條曲線基本重疊岔乔,或者可以說看作重疊,所以得出結(jié)論是滚躯,2n+1其中里面作為常數(shù)的1雏门,在輸入數(shù)值大到一定程度,他對于函數(shù)的影響可以忽略不計掸掏,這時候的1就被看作是次要項
同樣茁影,2n^2+2n+1
由于漸近增長是可以看作是一種抽象,所以他的對比具有一些特點:
1.注意關(guān)注函數(shù)最高次冪的變化
2.忽略次要項與乘數(shù)
特別感謝:
raylee2007的專欄