前端工程师算法(一)
算法是指解題方案的準確而完整的描述,是一系列解決問題的清晰指定,算法代表著用系統的方法描述解決問題的策略機制。這個解釋來源于百度,對于入門來說這個解釋等于白說了,你的一臉懵逼我懂,大神略過。
- 說人話
- 算法
- 你需要了解的算法是什么?
開始了解算法就應該對程序有一些認識和理解了,其實我們所有的程序可以理解為算法加數據結構。撇開數據結構不談,我們日常寫的代碼如if-else、for(...)等就是算法。在數學里加減乘除是算法,方程公式,幾何公式,乃至高數也都是算法,而我們的if-else、for(...)就相當于數學中的加減乘除這種級別的算法,當然在程序里也有加減乘除,同樣也是算法。
但是我們日常所表達的算法和算法通常的說法有一些區別,我們日常表達的算法基本上都是特指一些特殊的算法,這些特殊的算法就相當于數學中的高數級別(不是指難度)。這些算法的特殊性并非其難度,而是具備通用性、高效(空間和時間)、解決特定問題的程序。
前端常用算法之數組查重算法
?在前端編程中查重是比較常見的應用,以數組查重為例,通常的思路是通過嵌套循環,讓每個值與其他每個值進行逐個對比。思路有了,我們就來實現以下:
var arr = [8,4,79,38,2,67,4,19,8,13,47,68,37,13,48,2]; var cont = 0;//記錄比較次數 for(var i = 0; i < arr.length; i++){for(var j = 0; j < arr.length; j++){if(arr[i] == arr[j] && i != j){//'i != j'-->排除與自己比較 console.log(arr[i]);}cont ++;//累計 } } console.log(cont);//256這個查重算法可以說基本就實現了,因為解決了特定問題:找到重復的元素。但是這個算法并不是我們真正需要的算法,因為這樣對比出現了很多重復,浪費很多計算資源和時間,所以這個算法需要改進。
改進的目的就是消除重復對比,從數組的有序性我們可以知道,每一次內部循環不需要從頭開始對比,因為前面已經對比過了,所以改進代碼如下:
for(var i = 0; i < arr.length; i++){for(var j = i + 1; j < arr.length ; j++){//i+1表示自身和自身之前的元素都不需要比較了if(arr[i] == arr[j]){console.log(arr[i]);}cont ++;//累計 } } console.log(cont);//120這樣改進后的查重效率可以從對比次數看到,減少了一半多,也就說明了改進后的查重算法效率提高了一倍多。在算法中,不存在對錯的概念,而是在保證實現功能的最優方案是什么。這些最優方案就是我們需要的算法,這些算法可以提高用戶的體驗,減少硬件資源的消耗。
用這樣的思路我們來實現以下數組去重算法:(這段代碼折疊,大家可以先嘗試自己寫)
function unique(arr){var obj = {};var result = [];for(var i in arr){if(!obj[arr[i]]){obj[arr[i]] = true;result.push(arr[i]);}}return result; } 數組去重算法入門之經典的排序算法詳解
- 冒泡排序
- 選擇排序
這里暫時介紹兩種排序算法,就這兩種排序算法介紹一些關于排序的應用場景解析,在前面的查重和去重算法中我們主要考慮到了效率。接著我們用這兩個排序算法來將算法的解決特定問題引述出來,這兩個算法并不能全面說明什么是特定的問題,它們僅僅只能告訴我們不同的算法存在其優點和缺點,適應的場景也就會隨之發生變化,而這些場景往往來自不同的業務和功能的需求,需求來源不同,但可以根據其不同特性歸類從而選擇不同的算法,這就是算法的通用性。
1.冒泡排序(升序):
for(var j = 0; j < arr.length - 1; j++){for(var i = 0; i < arr.length - j - 1; i++){if(arr[i] > arr[i + 1]){var temp = arr[i];arr[i] = arr[i + 1];arr[i + 1] = temp;}} }首先我們就這這個升序的冒泡排序算法做一個圖解,來理解冒泡排序的邏輯及其原理:
假設有數組:var arr = [5,3,7,2,8,6,1,9,4];
當外層循環第一次時:j == 0, i == 0。
通過一次外層循環,圖解內部完全循環,可以看到冒泡循環就是通過兩個相鄰元素兩兩比較,升序就是將大值交換到后面的邏輯,每一次外層循環都可以獲得對應循環終點的最大值。既然是兩兩比較,那么最一個單獨的元素就不需要在循環比較了,所以外層循環也可以減去一次。
2.選擇排序(升序):
for(var j = 0; j < arr.length - 1; j ++){var max = 0;for(var i = 0; i < arr.length - j - 1; i++){if (arr[i + 1] > arr[max]) {max = i + 1;}}var temp = arr[arr.length - j -1];arr[arr.length - j - 1] = arr[max];arr[max] = temp; }選擇排序的邏輯就是外層負責交換,內層負責找到對應一次外層循環終點內的最大值的索引,然后在一次外層循環結束時,將最大值與該次循環終點的元素進行交換位置。下面提供選擇排序的圖解:
假設有數組:var arr = [5,3,7,2,8,6,1,9,4];
-
第一輪外層循環
i? [i+1]>[max]??max
0 3>5 =>false ? 0 ?
1 7>5 =>true??? 2? ?
2 2>7 =>false? 2 ?
3 8>7 =>true??? 4? ?
4 6>8 =>false? 4? ?
5 1>8 =>false? 4? ?
6 9>8 =>true??? 7? ?
7 4>9 =>false ? 7? ?
max=7;終點=8; ?
-
第二輪外層循環
i??[i+1]>[max]??max
0 3>5 =>false?? 0??
1? 7>5 =>true??? 2 ??
2 2>7 =>false? 2 ?
3 8>7 =>true??? 4? ?
4 6>8 =>false?? 4? ?
5 1>8 =>false?? 4? ?
6 4>8 =>false?? 4? ?
max=4;終點=7; ?
-
第三輪外層循環
i??[i+1]>[max]??max
0 3>5 =>false?? 0??
1? 7>5 =>true??? 2 ??
2 2>7 =>false? 2 ?
3 4>7 =>false ?? 2 ?
4 6>7 =>false?? 2 ?
5 1>7 =>false?? 2 ?
max=2;終點=6; ?
-
第四輪外層循環
i??[i+1]>[max]??max
0 3>5 =>false?? 0??
1? 1>5 =>false ? 0 ?
2? 2>5 =>false? 0?
3?? 4>5 =>false ? 0? ?
4?? 6>5 =>true ?? 5?
max=5;終點=5; ?
-
第五輪外層循環
i??[i+1]>[max]??max
0 3>5 =>false?? 0??
1 1>5 =>false ? 0 ?
2 2>5 =>false ? 0?
3 4>5 =>false ?? 0 ?
max=0;終點=4; ?
-
第六輪外層循環
i??[i+1]>[max]??max
0 3>4 =>false?? 0??
1? 1>4 =>false ? 0 ?
2 2>4 =>false?? 0
max=0;終點=3; ?
-
第七輪外層循環
i??[i+1]>[max]??max
0? 3>2 =>true?? 1 ?
1? 1>3 =>false ? 1 ?
max=1;終點=2; ?
-
第八輪外層循環
i??[i+1]>[max]??max
0 1>2 =>false?? 0?
max=0;終點=1; ?
?
?
?
?
?
?
?
?
?
?
?
?
通過上圖將選擇排序的處理邏輯可視化展示后,可以看到交換次數明顯少于冒泡排序,但是借助了一個最大值索引變量來完成,這個變量會在每次外層循環時被創建,從這個角度來說對于空間的需求比冒泡排序要大。從效率的角度來講選擇排序的空間效率是肯定弱于冒泡排序,但是時間效率會如何呢?這個問題需要考慮更多的因素才能得到結果,由于這篇博客是基于入門級別的角度來闡述,所以暫時不探討太深入的問題。
通過兩個排序算法我們可以了解到解決同一個問題有多種方案,但是不同方案會有不同的優勢和劣勢,怎么在實際問題中應用這兩個算法,需要對它們的優勢和劣勢進行深入的分析,這不在入門的范圍內,后期會有博客更新算法知識點的深入理解部分。這篇博客旨在介紹算法是什么?我們如何對具體問題進行分析及編寫算法,所以上面的兩個排序算法還并不是我們能拿來解決具體問題的工具,我們還需要對其進一步邏輯分析和封裝,修改成可以在需要是隨時使用的函數。
- 排序算法需要做的核心工作是什么?
- 排序算法都有什么共同的特點?
?這兩個問題其實是一個問題,排序算法的核心工作就是【比較+交換】,這也是排序算法的共同特點,所以根據這個核心工作原理,上面兩個排序算法可以封裝成以下具體方法:
//比較 function compare(a,b){if (a > b) {return true;}else{return false;} } //交換 function exchange(arr,m,n){var temp = arr[m];arr[m] = arr[n];arr[n] = temp; } //封裝冒泡排序 function bubbleSort(arr){for(var j = 0; j < arr.length - 1; j++){for(var i = 0; i < arr.length - j - 1 ; i++){if(compare(arr[i] , arr[i + 1])){exchange(arr,i,i+1)}}} } //封裝選擇排序 function selectionSort(arr){for(var j = 0; j < arr.length - 1; j ++){var max = 0;for(var i = 0; i < arr.length - j - 1; i++){if(compare(arr[i +1] , arr[max])){max = i + 1;}}exchange(arr,arr.length - j -1,max);} }了解到這里,我們應該可以大概的理解算法的定義了:算法是指解題方案的準確而完整的描述,是一系列解決問題的清晰指定,算法代表著用系統的方法描述解決問題的策略機制。對于同一個問題我們又會有不同的策略機制,就拿排序算法來說,我們分析的就有兩種了,但是并不止這兩種,常見的排序算法還有快速排序、直接插入排序、希爾排序、堆排序、歸并排序、基數排序。不同的排序算法有不同的應用場景,有時間再來更新深入分析算法的內容了,今天是大年初四,在這里祝福大家豬年好運,身體健康,豬定幸福!
想深入了解算法的話可以先參考這兩個博客:
排序算法的穩定性
算法的復雜度
轉載于:https://www.cnblogs.com/ZheOneAndOnly/p/10355397.html
總結
以上是生活随笔為你收集整理的前端工程师算法(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python多线程的两种写法
- 下一篇: (译)删除未使用的前端代码