爲何要學數據結構和算法:算法
解決問題方法的效率,和數據的組織方式有關:數據結構
例子:如何在書架上擺放圖書?
題眼:
操做一:新書怎麼插入?
操做二:怎麼找到某本指定的書?
方法一:隨便放
操做一:哪裏有空放哪裏
操做二:找書就比較頭疼了
方法二:按照書名的拼音字母順序放
操做一:須要挨個位置移動
操做二:二分查找
方法三:把書架按類別分區,每一個類別內按照字母順序放
操做一:搜索類別,二分查找肯定位置,挪出空位
操做二:搜索類別,二分查找肯定位置
思考:空間怎麼分配,類別怎麼分配
解決問題方法的效率,和空間的利用效率有關:數據結構和算法
例子:寫方法,順序打印從1到n的所有正整數 方法一:循環 function print(n){ for(var i=0;i<n;i++){ console.log(i); } return; } //數量級多大都能正常輸出 方法二:遞歸 function print(n){ if(n){ print(n-1); console.log(n); } return; } //數量級到必定程度直接崩潰,由於遞歸很是耗費空間
解決問題方法的效率,和算法的巧妙程度有關:函數
例子:i*x的i次方 ,i取值從0~9,在x=1.1時計算他們的和 方法一:老老實實翻譯成代碼 function compute(n,a,x){ var result = a[0]; for(var i=1;i<=n;i++){ result += (a[i] * Math.pow(x,i)); } return result; } 方法二:提取公因數 function compute(n,a,x){ var result = a[n]; for(var i=n;i>0;i--){ result = a[i-1] + x*result; } return result; } 結果:這兩種方法在分別屢次運行累加的時間,方法二比方法一快一個數量級
數據結構和算法的概念:ui
//什麼是數據結構 數據對象:數據在計算機中的組織方式,包括邏輯結構和物理存儲結構。 數據對象集的相關操做:數據對象一定與一系列加在其上的操做相關,完成這些操做所用的方法就是算法。 數據結構就描述了數據對象集及與其相關的操做集。
//什麼是算法 算法是一個有限的指令集,接收一些輸入,在有限步驟以後終止,產生輸出。 算法的每一條指令都要有明確的目標、在計算機處理範圍內、不依賴於任何一種語言及具體實現手段。
算法分析:spa
//空間複雜度S(n) 根據算法寫成的程序在執行時佔用存儲單元的長度。 這個長度每每與輸入數據的規模有關,空間複雜度太高可能致使內存超限,形成程序非正常中斷。 //時間複雜度T(n) 根據算法寫成的程序在執行是耗費時間的長度。 這個長度一般與輸入數據的規模有關,時間複雜度太高的算法可能致使咱們有生之年都等不到運行結果。
時間複雜度的計算:翻譯
一般狀況下咱們關注:最壞狀況複雜度和平均複雜度。 //複雜度的漸進表示法(空間複雜度也同樣,這裏省略) T(n) = O(f(n)) 表示算法時間複雜度的上界 T(n) = Ω(g(n))表示算法時間複雜度的下界 T(n) = θ(h(n))表示上界和下界同時適用 //時間複雜度函數優劣排序(從左到右,愈來愈慢) 1 < log n < n < n*log n < n^2 < n^3 < 2^n < n! //幾個時間複雜度的計算要點 相加取大值:T1(n) + T2(n) = max(O(f1(n)),O(f2(n))) 相乘取乘積:T1(n) * T2(n) = O(f1(n) * f2(n)) n的k階多項式:T(n) = θ(n^k) for循環:T(n) = 循環次數 * 循環體代碼的複雜度 if-else:T(n) = max(if判斷複雜度,if分支複雜度,else複雜度)
正常循環的時間複雜度:O(1)、O(n)、O(n^2) ……code
首先明確:常數項對時間增加影響不大,因此被忽略 function test1(){ console.log("hello"); } //T(n) = 1 → O(1) function test2(n){ for(var i=0;i<n;i++){ console.log("hello"); } } //T(n) = (n*1) → O(n) function test3(n){ for(var i=0;i<n;i++){ for(var j=0;j<n;j++){ console.log("hello"); } } } //T(n) = (n*n*1) → O(n^2) function test4(n){ //第一部分 T1(n) = (n*n*1) → O(n^2) for(var i=0;i<n;i++){ for(var j=0;j<n;j++){ console.log("hello"); } } //第二部分 T2(n) = (n*1) → O(n) for(var x=0;x<n;x++){ console.log("world"); } } //T(n) = max(T1(n^2),T2(n)) → O(n^2) function test5(n){ if(n>=0){ //第一部分 T1(n) = (n*n*1) → O(n^2) for(var i=0;i<n;i++){ for(var j=0;j<n;j++){ console.log("hello"); } } }else{ //第二部分 T2(n) = (n*1) → O(n) for(var x=0;x<n;x++){ console.log("world"); } } } //T(n) = max(T1(n^2),T2(n)) → O(n^2)
二分法的時間複雜度:logn對象
//在有序數列中查找target,利用二分法實現 function test(arr,target){ var left=0; var right = arr.length-1; while(left<=right){ var middle = Math.floor((left + right)/2); if(arr[middle]>target){ //中間值比target大,target在左邊,序列變動爲 left~middle-1 right = middle-1; }else if(arr[middle]<target){ //中間值比target小,target在右邊,序列變動爲 middle+1~right left = middle+1; }else{ //不大不小就是找到了 return middle; } } return -1; } //時間複雜度: //n + n/2 + n/4 + …… + n/(2^k) //令 n/(2^k) = 1,可得 k = log2n //T(n) = O(logn)