算法復雜度是我們來衡量一個算法執行效率的一個度量標准,算法復雜度通常主要有時間復雜度和空間復雜度兩種。時間復雜度就是指算法代碼在運行最終得到我們想要的結果時所消耗的時間,而空間復雜度則是指算法中用來存儲的數據結構所占用的空間。往往一個時間復雜度比較低的算法擁有着較高的空間復雜度,兩者是互相影響的,我們前面講解數據結構中的一些例子和代碼也足以說明這一點。本文會簡單介紹一下用於描述算法的性能和復雜程度的大O表示法。
我們先來看一段簡單的代碼,來幫助我們理解什么是大O表示法:
function increment(num) { return ++num; } console.log(increment(1));
上面的代碼聲明了一個函數,然后調用它。這樣的代碼無論我們傳入的參數是什么,它都會返回自增后的結果。也就是說該函數的執行時間跟我們傳入的參數沒有任何關系,執行的時間都是X。因此,我們稱該函數的復雜度是O(1),常數的。
我們再來看看前面講過的順序搜索算法,我們直接把代碼拿過來用就好了。
//順序搜索 function sequentialSearch(array,item) { for(var i = 0; i < array.length; i++) { if(item === array[i]) { return i; }; }; return -1; };
現在我們假設要搜索的數組是[1,2,3...9,10],然后我們搜索1這個元素,那么在第一次判斷時就能找到想要搜索的元素。那么我們這里先假設每執行一次循環的開銷是1。那么我們還想搜索11,數組中沒有這個元素,sequentialSearch 就會執行十次遍歷整個數組,發現沒有后返回-1。那么在最壞的情況下,數組的長度大小決定了算法的搜索時間。這樣的函數的時間復雜度就是O(n),線性的,這里的n就是數組的長度。
那么,我們來稍微修改一下sequentialSearch讓它可以計算開銷:
//順序搜索 function sequentialSearch(array,item) { var cost = 0; for(var i = 0; i < array.length; i++) { cost++; if(item === array[i]) { return i; }; }; console.log(array.length,cost); return -1; }; sequentialSearch([1,2,3,4,5,6,7,8,9,10],11);
很簡單,就是加上了一個cost變量來計數。那么我們下面再來看看冒泡排序的時間復雜度是怎樣的,這里我們不再浪費篇幅,直接在代碼中加入計數器:
function swap(array,index1,index2) { var aux = array[index1]; array[index1] = array[index2]; array[index2] = aux; } function bubbleSort(array) { var length = array.length; var cost = 0; for (var i = 0; i < length; i++) { cost++; for (var j = 0; j < length - 1; j++) { cost++; if(array[j] > array[j + 1]) { swap(array,j,j+1); } } } console.log(length,cost); } bubbleSort([2,3,4,1,8,7,9,10]);
代碼本身沒什么好說的,我們發現,如果數組的長度是8,那么我們排序所消耗的時間就是64,如果長度是10,消耗的時間就是100。換句話說,冒泡排序的時間復雜度就是數組長度的平方,也就是O(n2)。
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <style> body { background-color: #DDDDDD; font: 30px sans-serif; } </style> <script type="text/javascript" src="https://www.google.com/jsapi"></script> <script type="text/javascript"> google.load('visualization', '1.0', {'packages':['corechart']}); google.setOnLoadCallback(drawChart); function drawChart() { var data = new google.visualization.DataTable(); data.addColumn('string', 'n'); data.addColumn('number', 'O(1)'); data.addColumn('number', 'O(log n)'); data.addColumn('number', 'O(n)'); data.addColumn('number', 'O(n log n)'); data.addColumn('number', 'O(n^2)'); data.addColumn('number', 'O(2^n)'); for (var i = 0; i <= 30; i++) { data.addRow([i+'', 1, Math.log(i), i, Math.log(i)*i, Math.pow(i,2), Math.pow(2,i)]); } var options = {'title':'Big O Notation Complexity Chart', 'width':700, 'height':600, 'backgroundColor':{stroke:'#CCC',strokeWidth:1}, 'curveType':'function', 'hAxis':{ title:'Elements (n)', showTextEvery:5 }, 'vAxis':{ title:'Operations', viewWindowMode:'explicit', viewWindow:{min:0,max:450} } }; var chart = new google.visualization.LineChart(document.getElementById('chart_div')); chart.draw(data, options); } </script> </head> <body> <div id='chart_div'></div> </body> </html>
上面的代碼是用js畫的一幅圖,其中有一些常用的大O表示法所對應的時間復雜度,大家可以把代碼COPY到本地自行去看一下,這樣會才會對大O表示法有更好的理解,為了偷點懶,也為了大家可以確實的自己去看一下圖標。我這里不會把圖給大家貼上的。
下面給大家貼上幾張圖,來看看我們之前學習的一些數據結構和算法的時間復雜度是怎樣的。
1、常用數據結構的時間復雜度
2、圖的時間復雜度
表格中的V代表頂點,E代表邊。
3、排序算法
4、搜索算法的時間復雜度
終於,我們了解了幾乎我們前面學過的所有的數據結構和算法的時間復雜度,這樣我們在選擇算法的時候可以更確切地評估它的效率。
那么,我們本系列的文章也將告一段落。后面准備深入的學習一下CSS。可能會把其中一些比較有意思的地方貼出來與大家分享。
最后,由於本人水平有限,能力與大神仍相差甚遠,若有錯誤或不明之處,還望大家不吝賜教指正。非常感謝!
最后,感謝大家的閱讀。如果您覺得或許還有那么點用處,可以把我的主頁加入你的收藏夾中以便需要的時候可以快速的找到。