資料結構與演算法篇 之複雜度分析(上)
一直以來都想把資料結構和演算法學好,可是老是學到一半就放棄了,哈哈這次買了一個課程王爭老師學習
這次要用部落格把這個過程記錄下來
第一步先來普及一下資料結構的概念。。。。。。
資料結構是計算機儲存、組織資料的方式。資料結構是指相互之間存在一種或多種特定關係的資料元素的集合。
資料結構是指相互之間存在著一種或多種關係的資料元素的集合和該集合中資料元素之間的關係組成。記為:
Data_Structure=(D,R)
其中D是資料元素的集合,R是該集合中所有元素之間的關係的有限集合。
演算法(Algorithm)是指解題方案的準確而完整的描述,就是說,能夠對一定規範的輸入,在有限時間內獲得所要求的輸出。
一個演算法的優劣可以用空間複雜度與時間複雜度來衡量。
對於資料結構和演算法來說,時間複雜度和空間複雜度就是對應著“快“和”省“
大O複雜度表示法使我們最常用的的分析方法:
我們來看一下下面這一段程式碼
1 int cal(int n) { 2 int sum = 0; 1 unit time 3 int i = 1; 1+1 unit time 4 for (; i <= n; ++i) { 1+1+n unit time 5 sum = sum + i; 1+1+n+n unit time 6 } 7 return sum; 8 }
其中這裡用到的是 (2n+2) unit time
1 int cal(int n) { 2 int sum = 0; 1 3 int i = 1; 1 4 int j = 1; 1 5 for (; i <= n; ++i) { 6 j = 1; 2n 7 for (; j <= n; ++j) { 8 sum = sum + i * j; 2n*n 9 } 10 } 11 }
所以這裡用到了 (2n*n+2n+3)uint time
T(n) = O(f(n)) T表示的是程式碼執行的時間,然後f表示是上面的哪條公式
第一條 T(n)= O(2n+2) = O(n)
第二條 T(n)= O(2n*n+2n+3)=O(n*n)
這就是大O的時間複雜度,為什麼係數和常熟會被去掉?
當n很大,公式裡的低階和常量和係數對增長趨勢影響並不大,所以我們只需要記錄一個最大的量級
上面大概的講清楚了大O的複雜度表示方法
接下來就來介紹三種最常用的分析方法:
1 只關心迴圈執行次數最多的一段程式碼
根據上面的程式碼我們一眼就可以看出,第一段程式碼是O(n),因為它只有一段
然後到了第二段程式碼呢?就是兩層迴圈兩個n,那麼很自然就是O(n*n)
2 加法法則:總複雜度等於量級最大的那段程式碼
int cal(int n) { int sum_1 = 0; int p = 1; for (; p < 100; ++p) { sum_1 = sum_1 + p; }
int sum_2 = 0; int q = 1; for (; q < n; ++q) { sum_2 = sum_2 + q; } int sum_3 = 0; int i = 1; int j = 1; for (; i <= n; ++i) { j = 1; for (; j <= n; ++j) { sum_3 = sum_3 + i * j; } } return sum_1 + sum_2 + sum_3; }
第一段程式碼的時間複雜度是100(無論這個常數是多少,10000還是1000000跟n都沒關係,所以被忽略),
第二段程式碼的時間複雜度是O(n),第三段程式碼是O(n*n)
所以答案是O(n*n)
3 乘法法則:巢狀程式碼的複雜度等於巢狀內外程式碼複雜度的乘積
1int cal(int n) { 2 int ret = 0; 3 int i = 1; 4 for (; i < n; ++i) { 5 ret = ret + f(i); 6 } 7 } 8 9 int f(int n) { 10 int sum = 0; 11 int i = 1; 12 for (; i < n; ++i) { 13 sum = sum + i; 14 } 15 return sum; 16 }
第一段程式碼的時間複雜度是O(n),第二段程式碼的時間複雜度也是O(n)
所以時間複雜度等於O(n*n)
是不是覺得你所有程式碼都知道了,時間複雜度就是這麼簡單。。。。。。
時間複雜度可不只是這些喔
複雜度量級
一般分成兩種,第一種是多項式和非多項式量級
非多項式量級只有O(2^n)和O(n!),當n的規模越大,演算法時間會急劇增加,所以是非常低效的演算法
看圖就知道了
O(1) 常量級的時間複雜度,無亂常量是但是,1000?100000?都是1,謝謝
O(logn)和O(nlogn)
這是我最討厭的分析的,真的,當初就是搞不懂這個
哈哈現在嘛
1 i=1; 2 while (i <= n) { 3 i = i * 2; 4 }
什麼意思也就是 求2^x = n
也就是 x=log2n
1 i=1; 2 while (i <= n) { 3 i = i * 3; 4 }
什麼意思也就是 求3^x = n
也就是 x=log3n
log3n = log3 2 * log2 n哈哈記憶中高中還是大學是有這麼一條公式的
log3 2是常數,所以選擇忽略。。。。。。悽慘啊
所以啊。。。最後連數字都忽略掉了。。。更加慘無人道了
O(logn),那嗎另外一個O(nlogn)呢,執行n次O(logn)就有了
O(m+n)
int cal(int m, int n) { int sum_1 = 0; int i = 1; for (; i < m; ++i) { sum_1 = sum_1 + i; }
int sum_2 = 0; int j = 1; for (; j < n; ++j) { sum_2 = sum_2 + j; }
return sum_1 + sum_2; }
還有。。。這程式碼一看怎麼這麼熟悉。。。當初面試的時候考過。。。。。。O(m+n)謝謝。。。哈哈
這個跟上面有點不一樣,不是兩個n+n,m和n的值誰大並不知道,所以啊就是O(m+n)
好了講了一大堆的時間複雜度,總該講一下空間複雜度吧,不然也太不公平了。。。。。。
int i;
int j;
int a[n];......這樣好像不對的。。。。。。。
好的,不管了,那麼它的空間複雜度是多少呢?O(n+2)常量去掉,那麼就是O(n)
常用的空間複雜度有O(1),O(n),O(n*n)
好了,空間複雜度講完了。。。。。。。就是這麼不公平了。。。