演算法的定義是這樣的:解題方****而完善的描述,是一系列解決問題的清晰指令。巴拉巴拉的,雖然是一小句但還是不想看(題外話:有時候吧專業名詞記下來面試的時候還是挺有用的),其實就是解決乙個問題的完整性描述。只不過這個描述就可能是用不同的方式或者說是「語言」了。
演算法的效率
既然演算法是解決問題的描述,那麼就像一千個人眼中有一千個阿姆雷特他大姨夫一樣,解決同乙個問題的辦法也是多種多樣的,只是在這過程中我們所使用/消耗的時間或者時間以外的代價(計算機消耗的則為記憶體了)不一樣。為了更快、更好、更強的發揚奧利奧…哦不,提高演算法的效率。所以很多時候乙個優秀的演算法就在於它與其他實現同乙個問題的演算法相比,在時間或空間(記憶體)或者時間和空間(記憶體)上都得到明顯的降低。
所以呢,演算法的效率主要由以下兩個複雜度來評估:
時間複雜度:評估執行程式所需的時間。可以估算出程式對處理器的使用程度。
空間複雜度:評估執行程式所需的儲存空間。可以估算出程式對計算機記憶體的使用程度。
設計演算法時,時間複雜度要比空間複雜度更容易出問題,所以一般情況一下我們只對時間複雜度進行研究。一般面試或者工作的時候沒有特別說明的話,複雜度就是指時間複雜度。
~~乙個程式的空間複雜度是指執行完乙個程式所需記憶體的大小。利用程式的空間複雜度,可以對程式的執行所需要的記憶體多少有個預先估計。乙個程式執行時除了需要儲存空間和儲存本身所使用的指令、常數、變數和輸入資料外,還需要一些對資料進行操作的工作單元和儲存一些為現實計算所需資訊的輔助空間。程式執行時所需儲存空間包括以下兩部分。
(1)固定部分。這部分空間的大小與輸入/輸出的資料的個數多少、數值無關。主要包括指令空間(即**空間)、資料空間(常量、簡單變數)等所佔的空間。這部分屬於靜態空間。
(2)可變空間,這部分空間的主要包括動態分配的空間,以及遞迴棧所需的空間等。這部分的空間大小與演算法有關。
乙個演算法所需的儲存空間用f(n)表示。s(n)=o(f(n)) 其中n為問題的規模,s(n)表示空間複雜度。
接下來我們還需要知道另乙個概念:時間頻度。這個時候你可能會說:「不是說好一起學演算法嗎,這些東東是什麼?贈品嗎?」。非也非也,這是非賣品。
因為乙個演算法執行所消耗的時間理論上是不能算出來的,沒錯正是理論上,so我們任然可以在程式中測試獲得。但是我們不可能又沒必要對每個演算法進行測試,只需要知道大概的哪個演算法執行所花費的時間多,哪個花費的時間少就行了。如果乙個演算法所花費的時間與演算法中**語句執行次數成正比,那麼那個演算法執行語句越多,它的花費時間也就越多。我們把乙個演算法中的語句執行次數稱為時間頻度。通常(ps:很想知道通常是誰)用t(n)表示。
在時間頻度t(n)中,n又代表著問題的規模,當n不斷變化時,t(n)也會不斷地隨之變化。為了了解這個變化的規律,時間複雜度這一概念就被引入了。一般情況下演算法基礎本操作的重複執行次數為問題規模n的某個函式,用也就是時間頻度t(n)。如果有某個輔助函式f(n),當趨於無窮大的時候,t(n)/f(n)的極限值是不為零的某個常數,那麼f(n)是t(n)的同數量級函式,記作t(n)=o(f(n)),被稱為演算法的漸進時間複雜度,又簡稱為時間複雜度。
2.1 - 大o表示法
用o(n)來體現演算法時間複雜度的記法被稱作大o表示法
一般我們我們評估乙個演算法都是直接評估它的最壞的複雜度。
大o表示法o(f(n))中的f(n)的值可以為1、n、logn、n^2 等,所以我們將o(1)、o(n)、o(logn)、o( n^2 )分別稱為常數階、線性階、對數階和平方階。下面我們來看看推導大o階的方法:
推導大o階
推導大o階有一下三種規則:
用常數1取代執行時間中的所有加法常數
只保留最高端項
去除最高端的常數
舉好多栗子
常數階
let sum = 0, n = 10; // 語句執行一次
let sum = (1+n)*n/2; // 語句執行一次
console.log(`the sum is : $`) //語句執行一次
這樣的一段**它的執行次數為 3 ,然後我們套用規則1,則這個演算法的時間複雜度為o(1),也就是常數階。
再例如:如果演算法的執行時間不隨著問題規模n的增加而增長,即使演算法中有上千條語句,其執行時間也不過是乙個較大的常數。此類演算法的時間複雜度是o(1)。
x=91; y=100;
while(y>0) if(x>100) else x++;
解答: t(n)=o(1),
這個程式看起來有點嚇人,總共迴圈執行了1000次,但是我們看到n沒有?這段程式的執行是和n無關的,就算它再迴圈一萬年,我們也不管他,只是乙個常數階的函式
線性階
let i =0; // 語句執行一次
while (i < n) `); //語句執行n次
i++; // 語句執行n次
}
這個演算法中**總共執行了 3n + 1次,根據規則 2->3,因此該演算法的時間複雜度是o(n)。
對數階
let number = 1; // 語句執行一次
while (number < n)
上面的演算法中,number每次都放大兩倍,我們假設這個迴圈體執行了m次,那麼2^m = n即m = logn,所以整段**執行次數為1 + 2*logn,則f(n) = logn,時間複雜度為o(logn)。
平方階
for (let i = 0; i < n; i++)
}
上面的巢狀迴圈中,**共執行 2*n^2 + n,則f(n) = n2。所以該演算法的時間複雜度為o(n2 )
例如:當有若干個迴圈語句時,演算法的時間複雜度是由巢狀層數最多的迴圈語句中最內層語句的頻度f(n)決定的。
x=1;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++)
for(k=1;k<=j;k++)
x++;
該程式段中頻度最大的語句是(5),內迴圈的執行次數雖然與問題規模n沒有直接關係,但是卻與外層迴圈的變數取值有關,而最外層迴圈的次數直接與n有關,因此可以從內層迴圈向外層分析語句(5)的執行次數: 則該程式段的時間複雜度為t(n)=o(n3/6+低次項)=o(n3)
常見時間複雜度的比較
o(1)總結:不隨n的變化而變化的時間複雜度都是線性的!
時間複雜度和空間複雜度計算
時間複雜度 首先要說的是,時間複雜度的計算並不是計算程式具體執行的時間,而是演算法執行語句的次數。當我們面前有多個演算法時,我們可以通過計算時間複雜度,判斷出哪乙個演算法在具體執行時花費時間最多和最少。常見的時間複雜度有 常數階o 1 對數階o log2 n 線性階o n 線性對數階o n log2...
時間複雜度和空間複雜度的計算
時間複雜度 1.一般情況下,演算法的基本操作重複執行的次數是模組n的某乙個函式f n 因此,演算法的時間複雜度記做 t n o f n 分析 隨著模組n的增大,演算法執行的時間的增長率和 f n 的增長率成正比,所以 f n 越小,演算法的時間複雜度越低,演算法的效率越高。2.在計算時間複雜度的時候...
時間複雜度和空間複雜度的計算
時間複雜度 執行乙個演算法,執行的次數和問題規模之間的函式關係,用o 表示。o 1 常數項,和問題的規模無關。時間複雜度計算規則 1.只保留最高端項 2.不要係數 空間複雜度 執行乙個演算法,需要額外的輔助空間和問題規模之間的函式關係,用o 表示。簡單來說,時間複雜度指的是執行次數,空間複雜度指的是...