算法復雜度分析

算法復雜度作用

  1. 數據結構和算法本身解決的是“快”和“省”的問題,即如何讓代碼運行得更快淫茵,如何讓代碼更省存儲空間。所以财破,執(zhí)行效率是算法一個非常重要的考量指標宗挥。

  2. 多項式階:隨著數據規(guī)模的增長乌庶,算法的執(zhí)行時間和空間占用,按照多項式的比例增長契耿。包括瞒大,
    O(1)(常數階)、O(logn)(對數階)搪桂、O(n)(線性階)透敌、O(nlogn)(線性對數階)、O(n^2 )(平方階)锅棕、O(n^3 )(立方階)

  1. 非多項式階:隨著數據規(guī)模的增長拙泽,算法的執(zhí)行時間和空間占用暴增,這類算法性能極差裸燎。包括顾瞻,O(2^n )(指數階)、O(n!)(階乘階
  1. 算法時間復雜度由小到大依次為:Ο(1)<Ο(logn)<Ο(n)<Ο( nlog^n )<Ο( n^2 ) <Ο( n^3 ) <…<Ο( 2^n ) <Ο(n!)
    [圖片上傳失敗...(image-516b81-1554175993123)]

空間復雜度

先說空間復雜度德绿,因為空間復雜度比較簡單

void print(int n) {
  int i = 0;
  int[] a = new int[n];
  for (i; i <n; ++i) {
    a[i] = i * i;
  }
  for (i = n-1; i >= 0; --i) {
    print out a[i]
  }
}

第 2 行代碼中荷荤,我們申請了一個空間存儲變量 i,但是它是常量階的移稳,跟數據規(guī)模 n 沒有關系蕴纳,所以我們可以忽略。第 3 行申請了一個大小為 n 的 int 類型數組个粱,除此之外古毛,剩下的代碼都沒有占用更多的空間,所以整段代碼的空間復雜度就是 O(n)都许。

我們常見的空間復雜度就是 O(1)稻薇、O(n)、O(n)胶征,像 O(logn)塞椎、O(nlogn) 這樣的對數階復雜度平時都用不到。而且睛低,空間復雜度分析比時間復雜度分析要簡單很多

時間復雜度

計算時間復雜度的3個方法


  1. 只關注循環(huán)或遞歸最多的一段代碼
  2. 加法法則:總復雜度等于量級最大的那段代碼的復雜度
  3. 乘法法則:嵌套代碼的復雜度等于嵌套內外代碼復雜度的乘積
    (1).對于一些簡單的輸入輸出語句或賦值語句,近似認為需要O(1)時間
    (2).對于順序結構,需要依次執(zhí)行一系列語句所用的時間可采用大O下"求和法則"
    (3).對于選擇結構,如if語句,它的主要時間耗費是在執(zhí)行then字句或else字句所用的時間,需注意的是檢驗條件也需要O(1)時間
    (4).對于循環(huán)結構,循環(huán)語句的運行時間主要體現在多次迭代中執(zhí)行循環(huán)體以及檢驗循環(huán)條件的時間耗費,一般可用大O下"乘法法則"
    (5)只需計算基本語句執(zhí)行次數的數量級案狠,只要保證基本語句執(zhí)行次數的函數中的最高次冪正確即可服傍,可以忽略所有低次冪和最高次冪的系數。這樣能夠簡化算法分析骂铁,并且使注意力集中在最重要的一點上:增長率吹零。

例1: O(1)

int cal(int n) {
    int sum = 0; //1次頻度
    int i = 1;//1次頻度
    for (; i <= n; ++i) {//n次頻度
        sum = sum + i;//n次頻度
    }
   return sum;
 }

時間復雜度 T(n) = O(2n+2)=O(n)

例2: O( n )

int a=0; //1次頻度 
int b=1; //1次頻度
for (i=1;i<=n;i++){  //n次頻度  
     s=a+b;//n次頻度       
     b=a; //n次頻度         
     a=s; //n次頻度      
}  

時間復雜度 T(n) = O(4+4n)=O(n)

例3: O( n^2 )

  int cal(int n) {
   int sum = 0;//1次頻度
   int i = 1;//1次頻度
   int j = 1;//1次頻度
   for (; i <= n; ++i) {//n次頻度
     j = 1;//n次頻度
     for (; j <= n; ++j) {//n*n次頻度
       sum = sum +  i * j;//n*n次頻度
     }
   }
 }

時間復雜度 T(n) = O(3+2n+2n*n)=O( n^2 )

例4: O( log^n )

for(i=0;i<n;){//f(n)次頻度
    i*=2;//f(n)次頻度
}

假設語句2的頻度是f(n),則:2^f(n) <=n; f(n)<=log^n ; 取最大值f(n)=log^n ;T(n)=O(log^n )

例5:

當有若干個循環(huán)語句時,算法的時間復雜度是由嵌套層數最多的循環(huán)語句中最內層語句的頻度f(n)決定的从铲。

int x=1; 
for(i=1;i<=n;i++) {
    for(j=1;j<=i;j++){
        for(k=1;k<=j;k++){
            x++; 
        }
    }  
}

該程序段中頻度最大的語句是行號5瘪校,內循環(huán)的執(zhí)行次數雖然與問題規(guī)模n沒有直接關系,但是卻與外層循環(huán)的變量取值有關名段,而最外層循環(huán)的次數直接與n有關阱扬,因此可以從內層循環(huán)向外層分析語句(5)的執(zhí)行次數:
則該程序段的時間復雜度為T(n)=O(n3/6+低次項)=O(n3)

最好、最壞情況時間復雜度

// n 表示數組 array 的長度
int find(int[] array, int n, int x) {
  int i = 0;
  int pos = -1;
  for (; i < n; ++i) {
    if (array[i] == x) {
       pos = i;
       break;
    }
  }
  return pos;
}

因為伸辟,要查找的變量 x 可能出現在數組的任意位置麻惶。如果數組中第一個元素正好是要查找的變量 x,那就不需要繼續(xù)遍歷剩下的 n-1 個數據了信夫,那時間復雜度就是 O(1)窃蹋。

但如果數組中不存在變量 x,那我們就需要把整個數組都遍歷一遍静稻,時間復雜度就成了 O(n)警没。所以,不同的情況下振湾,這段代碼的時間復雜度是不一樣的杀迹。

平均情況時間復雜度(加權平均時間復雜度 或 期望時間復雜度)

在數組的 0~n-1 位置中要查找的變量 x 在數組中的位置,有 n+1 種情況:不在數組中押搪。我們把每種情況下树酪,查找需要遍歷的元素個數累加起來,然后再除以 n+1大州,就可以得到需要遍歷的元素個數的平均值续语,即:
[圖片上傳失敗...(image-f1905f-1554175993123)]

前面的推導過程中存在的最大問題就是,沒有將各種情況發(fā)生的概率考慮進去厦画。如果我們把每種情況發(fā)生的概率也考慮進去疮茄,那平均時間復雜度的計算過程就變成了這樣:
[圖片上傳失敗...(image-976878-1554175993123)]

引入概率之后,前面那段代碼的加權平均值為 (3n+1)/4根暑。用大 O 表示法來表示娃豹,去掉系數和常量,這段代碼的加權平均時間復雜度仍然是 O(n)购裙。

均攤時間復雜度

 // array 表示一個長度為 n 的數組
 // 代碼中的 array.length 就等于 n
 int[] array = new int[n];
 int count = 0;
 
 void insert(int val) {
    if (count == array.length) {
       int sum = 0;
       for (int i = 0; i < array.length; ++i) {
          sum = sum + array[i];
       }
       array[0] = sum;
       count = 1;
    }

    array[count] = val;
    ++count;
 }

最理想的情況下,數組中有空閑空間鹃栽,我們只需要將數據插入到數組下標為 count 的位置就可以了躏率,所以最好情況時間復雜度為 O(1)躯畴。最壞的情況下,數組中沒有空閑空間了薇芝,我們需要先做一次數組的遍歷求和蓬抄,然后再將數據插入,所以最壞情況時間復雜度為 O(n)夯到。

假設數組的長度是 n嚷缭,根據數據插入的位置的不同,我們可以分為 n 種情況耍贾,每種情況的時間復雜度是 O(1)阅爽。除此之外,還有一種“額外”的情況荐开,就是在數組沒有空閑空間時插入一個數據付翁,這個時候的時間復雜度是 O(n)。而且晃听,這 n+1 種情況發(fā)生的概率一樣百侧,都是 1/(n+1)。所以能扒,根據加權平均的計算方法佣渴,我們求得的平均時間復雜度就是:平均時間復雜度是O(1)
[圖片上傳失敗...(image-2a5a12-1554175993123)]

我們還是繼續(xù)看在數組中插入數據的這個例子。每一次 O(n) 的插入操作初斑,都會跟著 n-1 次 O(1) 的插入操作辛润,所以把耗時多的那次操作均攤到接下來的 n-1 次耗時少的操作上,均攤下來越平,這一組連續(xù)的操作的均攤時間復雜度就是 O(1)

分析

// 全局變量频蛔,大小為 10 的數組 array,長度 len秦叛,下標 i晦溪。
int array[] = new int[10]; 
int len = 10;
int i = 0;

// 往數組中添加一個元素
void add(int element) {
   if (i >= len) { // 數組空間不夠了
     // 重新申請一個 2 倍大小的數組空間
     int new_array[] = new int[len*2];
     // 把原來 array 數組中的數據依次 copy 到 new_array
     for (int j = 0; j < len; ++j) {
       new_array[j] = array[j];
     }
     // new_array 復制給 array,array 現在大小就是 2 倍 len 了
     array = new_array;
     len = 2 * len;
   }
   // 將 element 放到下標為 i 的位置挣跋,下標 i 加一
   array[i] = element;
   ++i;
}


1. 最好情況時間復雜度為 O(1)
2. 最壞情況分析: 
最壞情況代碼執(zhí)行的次數跟每次數組的長度有關
第1次調用insert的執(zhí)行的次數為 n ,
第2次調用insert的執(zhí)行的次數為 2n ,
第3次調用insert的執(zhí)行的次數為 2^2 * n 
第k次調用insert的執(zhí)行的次數為 2^(k-1) * n 
最壞時間復雜度為 O(n)三圆。
3. 平均情況分析
當每次遇到最壞情況時數組會進行2倍擴容,原數組被導入新數組避咆,雖然數組的長度變大了舟肉,但是插入操作落在的區(qū)間的長度是一樣的,分別是0~len-1, len~(2len-1),....查库;
插入的情況仍是len+1種:0~len-1和插滿之后的O(len)路媚;所以每次插入的概率是:p= 1/len+1,
最后求出加權平均時間復雜度為 1*p + 2*p+ ??? + len*p + len * p = O(1) ; 
4. 均攤時間復雜度 O(1)
而均攤復雜度由于每次O(len)的出現都跟著len次O(1)樊销,是前后連貫的整慎,因而將O(len)平攤到前l(fā)en次上脏款,得出平攤復雜度是O(1)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市裤园,隨后出現的幾起案子撤师,更是在濱河造成了極大的恐慌,老刑警劉巖拧揽,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剃盾,死亡現場離奇詭異,居然都是意外死亡淤袜,警方通過查閱死者的電腦和手機痒谴,發(fā)現死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饮怯,“玉大人闰歪,你說我怎么就攤上這事”褪” “怎么了库倘?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長论矾。 經常有香客問我教翩,道長,這世上最難降的妖魔是什么贪壳? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任饱亿,我火速辦了婚禮,結果婚禮上闰靴,老公的妹妹穿的比我還像新娘彪笼。我一直安慰自己,他們只是感情好蚂且,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布配猫。 她就那樣靜靜地躺著,像睡著了一般杏死。 火紅的嫁衣襯著肌膚如雪泵肄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天淑翼,我揣著相機與錄音腐巢,去河邊找鬼。 笑死玄括,一個胖子當著我的面吹牛冯丙,可吹牛的內容都是我干的。 我是一名探鬼主播遭京,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼银还,長吁一口氣:“原來是場噩夢啊……” “哼风宁!你這毒婦竟也來了?” 一聲冷哼從身側響起蛹疯,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎热监,沒想到半個月后捺弦,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡孝扛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年列吼,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苦始。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡寞钥,死狀恐怖,靈堂內的尸體忽然破棺而出陌选,到底是詐尸還是另有隱情理郑,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布咨油,位于F島的核電站您炉,受9級特大地震影響,放射性物質發(fā)生泄漏役电。R本人自食惡果不足惜赚爵,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望法瑟。 院中可真熱鬧冀膝,春花似錦、人聲如沸霎挟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽氓扛。三九已至枯芬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間采郎,已是汗流浹背千所。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蒜埋,地道東北人淫痰。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像整份,于是被迫代替她去往敵國和親待错。 傳聞我的和親對象是個殘疾皇子籽孙,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354