在進行演算法分析時,語句總的執行次數t(n)是關於問題規模n的函式,進而分析t(n)隨n的變化情況並確定t(n)的數量級。演算法的時間複雜度,也就是演算法的時間量度,記作:t(n)= o(f(n))。它表示隨問題規模n的增大,演算法執行時間的增長率和f(n)的增長率相同,稱作演算法的漸近時間複雜度,簡稱為時間複雜度,是一種「漸進表示法」。其中f(n)是問題規模n的某個函式。
用大寫o()來體現演算法時間複雜度的記法,我們稱之為大o記法。
一般情況下,隨著輸入規模n的增大,t(n)增長最慢的演算法為最優演算法。
顯然,由此演算法時間複雜度的定義可知,我們的三個求和演算法的時間複雜度分別為o(1),o(n),o(n^2)。
分析乙個演算法的時間複雜度步驟:
①常數階
例:段**的大o是多少?
int sum = 0, n = 100;
printf(「i love you.com\n」);
printf(「i love you.com\n」);
printf(「i love you.com\n」);
printf(「i love you.com\n」);
printf(「i love you.com\n」);
printf(「i love you.com\n」);
sum = (1+n)*n/2;
第一條就說明了所有加法常數給他個o(1)即可
②線性階:一般含有非巢狀迴圈涉及線性階,線性階就是隨著問題規模n的擴大,對應計算次數呈直線增長。
int i , n = 100, sum = 0;
for( i=0; i < n; i++ )
上面這段**,它的迴圈的時間複雜度為o(n),因為迴圈體中的**需要執行n次。
③平方階
int i, j, n = 100;
for( i=0; i < n; i++ )
}
n等於100,也就是說外層迴圈每執行一次,內層迴圈就執行100次,那總共程式想要從這兩個迴圈出來,需要執行100*100次,也就是n的平方。所以這段**的時間複雜度為o(n^2)。
總結:如果有三個這樣的巢狀迴圈就是n^3。所以總結得出,迴圈的時間複雜度等於迴圈體的複雜度乘以該迴圈執行的次數。
int i, j, n = 100;
for( i=0; i < n; i++ )
}
由於當i=0時,內迴圈執行了n次,當i=1時,內迴圈則執行n-1次……當i=n-1時,內迴圈執行1次,所以總的執行次數應該是:
n+(n-1)+(n-2)+…+1 = n(n+1)/2
n(n+1)/2 = n^2/2+n/2
用我們推導大o的攻略,第一條忽略,因為沒有常數相加。第二條只保留最高項,所以n/2這項去掉。第三條,去除與最高項相乘的常數,最終得o(n^2)。
④對數階
int i = 1, n = 100;
while( i < n )
由於每次i*2之後,就距離n更近一步,假設有x個2相乘後大於或等於n,則會退出迴圈。
於是由2^x = n得到x = log(2)n,所以這個迴圈的時間複雜度為o(logn)。
int i, j;
for(i=0; i < n; i++)
void function(int count)
函式體是列印這個引數,這很好理解。function函式的時間複雜度是o(1),所以整體的時間複雜度就是迴圈的次數o(n)。
假如function是下面這樣:
void function(int count)
}
事實上,這和之前平方階的時候舉的第二個例子一樣:function內部的迴圈次數隨count的增加(接近n)而減少,所以根據遊戲攻略演算法的時間複雜度為o(n^2)。
n++; //1
function(n); //1
for(i=0; i < n; i++)
for(i=0; i < n; i++)
}void function(int count)
為:1+1+n+n2,所以最後是o(n2)
常用的時間複雜度所耗費的時間從小到大依次是:
o(1) < o(logn) < (n) < o(nlogn) < o(n^2) < o(n^3) < o(2^n) < o(n!) < o(n^n)
我們查詢乙個有n個隨機數字陣列中的某個數字,最好的情況是第乙個數字就是,那麼演算法的時間複雜度為o(1),但也有可能這個數字就在最後乙個位置,那麼時間複雜度為o(n)。
平均執行時間是期望的執行時間。
最壞執行時間是一種保證。在應用中,這是一種最重要的需求,通常除非特別指定,我們提到的執行時間都是最壞情況的執行時間。
我們在寫**時,完全可以用空間來換去時間。
舉個例子說,要判斷某年是不是閏年,你可能會花一點心思來寫乙個演算法,每給乙個年份,就可以通過這個演算法計算得到是否閏年的結果。
另外一種方法是,事先建立乙個有2050個元素的陣列,然後把所有的年份按下標的數字對應,如果是閏年,則此陣列元素的值是1,如果不是元素的值則為0。這樣,所謂的判斷某一年是否為閏年就變成了查詢這個陣列某乙個元素的值的問題。
第一種方法相比起第二種來說很明顯非常節省空間,但每一次查詢都需要經過一系列的計算才能知道是否為閏年。第二種方法雖然需要在記憶體裡儲存2050個元素的陣列,但是每次查詢只需要一次索引判斷即可。
這就是通過一筆空間上的開銷來換取計算時間開銷的小技巧。到底哪一種方法好?其實還是要看你用在什麼地方。
演算法的空間複雜度通過計算演算法所需的儲存空間實現,演算法的空間複雜度的計算公式記作:s(n)=o(f(n)),其中,n為問題的規模,f(n)為語句關於n所佔儲存空間的函式,也是一種「漸進表示法」,這些所需要的記憶體空間通常分為「固定空間記憶體」(包括基本程式**、常數、變數等)和「變動空間記憶體」(隨程式執行時而改變大小的使用空間)
通常,我們都是用「時間複雜度」來指執行時間的需求,是用「空間複雜度」指空間需求。
當直接要讓我們求「複雜度」時,通常指的是時間複雜度。
a = 0
b = 0
print(a,b
它的空間複雜度o(n)=o(1);
def fun(n):
k = 10
if n == k:
return n
else:
return fun(++n)
遞迴實現,呼叫fun函式,每次都建立1個變數k。呼叫n次,空間複雜度o(n*1)=o(n)。
for(i=0;i變數的記憶體分配發生在定義的時候,因為temp的定義是迴圈裡邊,所以是n*o(1)
temp=0;
for(i=0;itemp定義在迴圈外邊,所以是1*o(1)
參考:
演算法複雜度 時間複雜度和空間複雜度
1 時間複雜度 1 時間頻度 乙個演算法執行所耗費的時間,從理論上是不能算出來的,必須上機執行測試才能知道。但我們不可能也沒有必要對每個演算法都上機測試,只需知道哪個演算法花費的時間多,哪個演算法花費的時間少就可以了。並且乙個演算法花費的時間與演算法中語句的執行次數成正比例,哪個演算法中語句執行次數...
演算法複雜度 時間複雜度和空間複雜度
演算法複雜度 時間複雜度和空間複雜度 關鍵字 演算法複雜度 時間複雜度 空間複雜度 1 時間複雜度 1 時間頻度 乙個演算法執行所耗費的時間,從理論上是不能算出來的,必須上機執行測試才能知道。但我們不可能也沒有必要對每個演算法都上機測試,只需知道哪個演算法花費的時 間多,哪個演算法花費的時間少就可以...
演算法複雜度 時間複雜度和空間複雜度
演算法的時間複雜度是指執行演算法所需要的計算工作量。n稱為問題的規模,當n不斷變化時,時間頻度t n 也會不斷變化。但有時我們想知道它變化時呈現什麼規律。為此,我們引入時間複雜度概念。一般情況下,演算法中基本操作重複執行的次數是問題規模n的某個函式,用t n 表示,若有某個輔助函式f n 存在乙個正...