評價(jià)算法性能的指標(biāo)-時(shí)間復(fù)雜度

目錄:

1.如何評價(jià)算法性能恬叹?

2.大O表示法

3.常見時(shí)間復(fù)雜度大小及其比較

4.一些較為復(fù)雜的實(shí)例

如何評價(jià)算法性能勺疼?

數(shù)據(jù)結(jié)構(gòu)和算法李请,本質(zhì)上是解決現(xiàn)實(shí)存在的問題,即如何讓解決指定問題的代碼運(yùn)行得更快蛙酪?一個(gè)算法如果能在所要求的資源限制(resource constraint)內(nèi)將問題解決好,則稱這個(gè)算法是有效率的(effient)助币。

限制可分為空間限制和時(shí)間限制猴蹂。

而算法的速度,算法需求多少空間如何衡量呢窒所?

你可能會(huì)說鹉勒,我可以通過如下代碼來測試代碼的運(yùn)行時(shí)間:

//JAVA CODE
  void calcDuration(){
  long begin = System.currentTimeMillis();
  function(n);
  long end = System.currentTimeMillis();
}

我們可以通過end-begin來計(jì)算出function()的執(zhí)行時(shí)間。這類“事后統(tǒng)計(jì)”的方法用來評估算法執(zhí)行效率是正確的吵取,但是它也有它的局限性:

受不同機(jī)器配置的影響禽额,結(jié)果差異不同,甚至同一段算法皮官,在不同機(jī)器上跑出來的結(jié)果差異很大脯倒。

算法的測試結(jié)果受輸入的規(guī)模影響很大,也就是說捺氢,輸入不同規(guī)模的數(shù)據(jù)藻丢,結(jié)果差別非常大。

能不能事先“算”出算法的執(zhí)行效率呢摄乒?這就引出了以下兩個(gè)概念:時(shí)間復(fù)雜度悠反,空間復(fù)雜度。

大O表示法
首先看一個(gè)簡單的例子:

void foo(){
   for(int i =0;i<n;i++){//執(zhí)行了n次
      System.out.println("Hello world");//執(zhí)行了n次
   }
   System.out.println("function over");//執(zhí)行了1次
}

在上述例子中馍佑,第1行的代碼總共執(zhí)行了n次斋否,第2行的代碼總共執(zhí)行n次,第4行代碼會(huì)執(zhí)行1次拭荤。

這里假設(shè)計(jì)算機(jī)處理語句代價(jià)(如:賦值如叼,自增,輸出等)都為c穷劈;(當(dāng)然笼恰,可以擬定一個(gè)最小單位踊沸,讓所有語句的代價(jià)與c成正比)。

假設(shè)算法總執(zhí)行時(shí)間為T(n)社证,其中n為問題的規(guī)模逼龟;

那么上述代碼的總執(zhí)行時(shí)間:T(n) = (2n +1)c

可以看出,T(n)與代碼的總執(zhí)行次數(shù)總是成正比的追葡,即與(2*n+1)成正比腺律;

我們將代碼執(zhí)行次數(shù)用f(n)來表示,即f(n) = 2*n+1宜肉。

我們算出了代碼的執(zhí)行次數(shù)后匀钧,如何表示算法的復(fù)雜度呢?

在計(jì)算機(jī)中谬返,我們一般采用大O漸進(jìn)表示法來表示算法的復(fù)雜度之斯。即

T(n) = O(f(n))

將上述f(n)帶入,我們得出T(n) = O(n),因此遣铝,上述算法的時(shí)間復(fù)雜度為O(n),細(xì)心的同學(xué)發(fā)現(xiàn)了佑刷,f(n)不是等于2*n+1嗎?酿炸,為什么到里面就沒有了呢瘫絮?

其實(shí)大O并不是表示代碼真正的執(zhí)行時(shí)間,而是代碼執(zhí)行時(shí)間隨著數(shù)據(jù)規(guī)模增長的變化趨勢填硕。具有以下特點(diǎn):

1.不保留系數(shù)麦萤;

2.且只保留最高階的項(xiàng)。

這里稍微解釋下第二條扁眯,低階項(xiàng)在問題規(guī)模n慢慢增大的時(shí)候壮莹,對結(jié)果影響慢慢變小,所以在計(jì)算時(shí)間復(fù)雜度的時(shí)候恋拍,可以省去垛孔。可以把大O符號想象成一個(gè)過濾形的一個(gè)漏斗施敢,過濾那些系數(shù)以及低階的項(xiàng)周荐。

比如:f(n) = 2n^2+5n+1; 則時(shí)間復(fù)雜度記為O(n^2)

常見算法復(fù)雜度大小及其比較

O(1)<O(logn)<O(n)<O(nlogn)<O(n)<O(n^2) <O(2^n)<O(n!)

log函數(shù)統(tǒng)一以2為底。

以上是算法復(fù)雜度大小與比較僵娃,需要注意的是除開O(2^n)與O(n!)外其他的被稱為多項(xiàng)式時(shí)間概作,這個(gè)概念后續(xù)會(huì)再次提及(NP問題)現(xiàn)在你只需要知道多項(xiàng)式是什么概念就行了。

另外我在初學(xué)的時(shí)候經(jīng)常分不清2^n與n!的大小比較

其實(shí)你把他展開來看就好了默怨。

2 *2 *2 *2.....(n個(gè)2)

1 *2 *3 *4.....(n個(gè)數(shù))

這樣是不是就清楚了呢讯榕?

圖片來自維基百科

一些較為復(fù)雜的實(shí)例

實(shí)例1

for(int i =0;i<n;i++){
  for(int j = 0;j<m;j++){
    System.out.println("sth");/*運(yùn)行m*n次*/
  }
}

在做時(shí)間復(fù)雜度題目的時(shí)候,我們往往只需要注意哪些語句頻度最高的語句,比如上例中的第三行愚屁,總計(jì)會(huì)運(yùn)行m*n次济竹,所以上例的時(shí)間復(fù)雜度為O(mn)。注意:一般問題規(guī)模我們會(huì)用n來表示霎槐,但是經(jīng)常會(huì)有多個(gè)影響問題規(guī)模的參數(shù)出現(xiàn)送浊,比如上例。

實(shí)例2

int i =1;
while(i<=n){
  i = i*2;
}

很多初學(xué)者看到上面的代碼就頭大丘跌,不知道分析袭景,實(shí)際上這道題就是問:

i = i*2會(huì)運(yùn)行多少次? 等價(jià)于

1 * 2 * 2 * 2.....*2 = n,有多少個(gè)乘2? 等價(jià)于

2^k = n闭树,求k

所以k = logn 耸棒,所以,時(shí)間復(fù)雜度為O(logn)

稍微變形下报辱,如果替換成語句i = i*3或者其他的呢与殃??

不以2為底的log函數(shù)對換

我們可以根據(jù)上述公式捏肢,把任意不以2為低的log函數(shù)奈籽,換成以2為低饥侵,而大O符號又是省略系數(shù)的鸵赫,所以不管是i = i*3,i = i * 4躏升,i = i * 5辩棒,...都統(tǒng)一記為O(logn)。

實(shí)例3

void foo(int m){
  for(int i = 0;i<m;i++)
    System.out.println("sth");
  }
void koo(int n){
   for(int i =0;i<n;i++)
     foo(n);//第7行
 }

我們要求koo函數(shù)的時(shí)間復(fù)雜度膨疏,由于koo函數(shù)的內(nèi)部又調(diào)用了foo一睁,所以將koo的內(nèi)部看成一個(gè)雙層for循環(huán),所以koo的時(shí)間復(fù)雜度為O(n^2)佃却。

思考:如果將第7行的調(diào)用改成foo(i)呢者吁?

實(shí)例4

int Fib(int n){//斐波那契數(shù)列
  if(n<3) return 1;
  else return Fib(n-1)+Fib(n-2);
}

上述實(shí)例是求斐波那契數(shù)列的遞歸形式,遞歸算法的時(shí)間復(fù)雜度往往更難求得饲帅,畫出調(diào)用過程為下圖:

Fib(5)調(diào)用過程

遞歸算法的復(fù)雜度复凳,為這顆二叉樹的節(jié)點(diǎn)數(shù)。
我們知道滿二叉樹的節(jié)點(diǎn)數(shù)為2^h -1,其中h為樹的高度灶泵,那樹的高度怎么求呢育八?
我們可以看紅線部分表示這棵樹每一層最左邊的節(jié)點(diǎn),它的特征很明顯赦邻,等于n-1(n是輸入規(guī)模)髓棋。所以這個(gè)算法的最終復(fù)雜度為O(2^n)。

值得一提的是,這是一種非常不好的寫法按声。有很多求斐波那契數(shù)列好的算法膳犹,暫時(shí)就不再贅述了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末签则,一起剝皮案震驚了整個(gè)濱河市镣奋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌怀愧,老刑警劉巖侨颈,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異芯义,居然都是意外死亡哈垢,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門扛拨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耘分,“玉大人,你說我怎么就攤上這事绑警∏筇” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵计盒,是天一觀的道長渴频。 經(jīng)常有香客問我,道長北启,這世上最難降的妖魔是什么卜朗? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮咕村,結(jié)果婚禮上场钉,老公的妹妹穿的比我還像新娘。我一直安慰自己懈涛,他們只是感情好逛万,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著批钠,像睡著了一般宇植。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上价匠,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天当纱,我揣著相機(jī)與錄音,去河邊找鬼踩窖。 笑死坡氯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播箫柳,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼手形,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了悯恍?” 一聲冷哼從身側(cè)響起库糠,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎涮毫,沒想到半個(gè)月后瞬欧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡罢防,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年艘虎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咒吐。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡野建,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出恬叹,到底是詐尸還是另有隱情候生,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布绽昼,位于F島的核電站唯鸭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏绪励。R本人自食惡果不足惜肿孵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一唠粥、第九天 我趴在偏房一處隱蔽的房頂上張望疏魏。 院中可真熱鬧,春花似錦晤愧、人聲如沸大莫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽只厘。三九已至,卻和暖如春舅巷,著一層夾襖步出監(jiān)牢的瞬間羔味,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工钠右, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赋元,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像搁凸,于是被迫代替她去往敵國和親媚值。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容