1. 程式人生 > >老王帶你理解演算法複雜度O(1),O(N),O(N^2)

老王帶你理解演算法複雜度O(1),O(N),O(N^2)

上圖對應的是演算法複雜度的圖片,X軸對應的是n(問題規模),Y軸對應的是執行的執行時間。

 

我們先從簡單的複雜度解讀O(1)

從上面的圖片我們可以看到O(1)的複雜度是恆定的,一點波瀾都沒有,什麼是O(1)呢,就比如你是一個酒店的管理員,你負責管理酒店的鑰匙,你很聰明,你把酒店的100把鑰匙放在了100個格子裡面存著,並且把格子從1~100進行了編號,有一天有客人來了,酒店老闆說,給我拿10號房間的鑰匙給我,你迅速從10號格子裡面拿出鑰匙給老闆,速度非常快,這時候你就是一個電腦了,老闆跟你說拿幾號房房間的鑰匙,你只需要看一眼就能知道鑰匙在哪裡。

存放鑰匙的格子

對應程式碼裡面可以是這樣的語句

#include <stdio.h>
void main(void)
{
    int i = 0;
    i = 1;
    i = 3;
}

 

然後我們說一下O(n)

突然,有一天,你的老闆給你說,老王啊,你用100個箱子存100把鑰匙,太浪費空間了,你能補能把鑰匙上編號一下,然後把鑰匙要用繩子穿起來,這樣我們可以把這個放箱子的地方再裝修一個房間出來。你想了一下,是啊,現在房價這麼貴,這樣能多賺點錢。

所以你就不能通過上面的方法來找到鑰匙了,老闆跟你說,老王啊,給我拿45號房間的鑰匙出來,你就需要從100個鑰匙裡面挨個找45個房間的鑰匙。

O(n)

是隨著樣本數增加複雜度按指數增加的,如果你的酒店老闆把酒店的房間增加到一萬個,然後有一天,老外不小心把穿鑰匙的繩子弄斷了,我了個叉叉叉,這時候老闆說,老王快把98號房間的鑰匙給我,老王慘爆了~~~我們假設如果老王的老闆酒店有兩萬個房間呢?

for(int i = 1; i<=100: i++)
{
    if(i == 45) 
         printf("Find it\n");
}

 

繼續說一下O(n^2)

隨著經濟發展越來越好,你的老闆把酒店擴大了,有100層每一層有100個房間,當然,你還是你,老王還是老王,工資並沒有漲,你因為關注了公眾號嵌入式Linux,

知道怎麼把鑰匙排序更好了,你把每一層的鑰匙穿在一起,然後一共就有100個用繩子穿起來的鑰匙串。

然後老闆叫你找鑰匙的時候,你先要找到樓層的編號,再對應找到房間的編號,所以大概對應的是這樣的程式碼。

#include <stdio.h>
int main ()
{
    int key;
	int array[100][100];
	
	for(int i=1;i<100;i++)
		for(int j=1;j<100;j++)
			array[i][j] = i*100 +j;
	scanf("%d",&key);
	for(int i=1;i<100;i++)
		for(int j=1;j<100;j++)
			if(array[i][j] == key)
				printf("FIND KEY\n");
    return 0;
}

這個可以看是O(N^2) +O(N^2) = O(2*N^2) 把常數去掉變成O(N^2)

 

最後我們解讀一下O(log^n)

這個就像是有一百把鑰匙,老王在關注公眾號後學了不少東西,老王突然覺得,我從頭找是不是太慢了,我從中間找,比如我要找到23號的房間鑰匙,我從中間切開,找到50編號的位置,然後23在1~50裡面,我再把從中間切開變成25,然後23在1~25之間,我再切開變成12.5,然後23在12.5~25之間,依次找下去,直到找到鑰匙。這種查詢鑰匙的方法的複雜度就是O(log^n)

#include <stdio.h>
/**
 *  折半查詢函式
 *
 *  @param arr   陣列
 *  @param len   陣列長度
 *  @param value 查詢元素
 *
 *  @return 返回查詢元素的位置
 */
int searchItem(int arr[],int len, int value){
    int low = 0,high = len-1,mid;
    while (low <= high) {
        mid = (low + high)/2;
        if (value > arr[mid]) {
            low = mid+1;
        }else if (value < arr[mid]){
            high = mid - 1;
        }else{
            return mid;
        }
    }
    return -1;
}
 
int main(int argc, const char * argv[]) {
    //陣列必須是有序陣列
   int a[10] = {1,2,31,45,52,62,73,86,90,100};
    //查詢86元素
    int l = searchItem(a,10,86);
    printf("loc = %d\n",l);
    return 0;
}

我們知道了O(log^n)可以類推出O(nlog^n)

後話

隨著工作時間的推移,發現掌握一種思維遠遠勝過掌握一種單純的技能,就比如C語言知識一種工具,C++也是一種工具,不要沉迷於一種工具或者“武功”不能自拔,要修煉自己的思維,以無招勝有招,舉個栗子,下雨天的時候,我喜歡開瑪莎拉蒂去上班能擋風遮雨,不下雨的時候我喜歡開我的小毛驢去上班不堵車更快,這樣更方便,各有各的專長和不足,當然對於某些公司把某種程式語言看得非常重要的,我覺得也是值得商榷的。人無完人,我們不可能把所有武功都學會了再去打天下,而是有了自己的專長,對問題有了自己的見解,就可以去做很多事情了。

不足之處,後面再補充

歡迎關注微信公眾號-嵌入式Linux

覺得不錯,請幫忙轉發,點贊,您的每一次支援,我都將銘記於心