前端也要懂算法,阅《算法图解》有所得。
一、 简单的算法:二分查找
假设要在100个数组里面查找一个元素,最简单的方法就是每次去取出一个元素,那么最糟糕的情况就是我们需要操作100次才能找到这个元素:
var list = [1,2,3,4.....,100];
function search(arr, target){
for(var i =0 ; i<arr.length ; i++) {
if(arr[i] === target){
return i
}
}
return 'none'
}
二分查找即是每次都猜测目标数是中间的那个元素,比较猜测的数跟目标树的大小,再从符合的那一半取中间数:
function search(arr,target){
var low = 0;
var hight = arr.length;
while(low <=hight){
var mid = parseInt((low+hight)/2);
if(arr[mid] === target) return mid;
if(arr[mid] > target){
low = mid + 1 ;
}else{
hight = mid -1 ;
}
}
return 'none'
}
从上面可以看出,在数组是有序的前提下,如果在100个数中查找一个数,那么最坏的情况需要执行100次操作,而使用2分查找,则最多需要执行7次操作:
100->50->25->13->6->3->1 //7次
由此可以知道,使用2分查找n个数需要执行的次数:
2 = log2^4 // 4个数需要2次
3 = log2^8 // 8个数需要3次
...
n = log2n
因此我们可以得出的结论:
- 二分查找法的运行速度是O(log^n)
- 简单查找的运行速度是O(n)
二、 算法的速度:大O表示法
1. 概念
大O表示法指出了算法的速度有多快,但指的并不仅是程序的运行速度,而是在情况越发复杂下,算法所需时间的增量。
举个栗子:
同样是上面的查找问题,如果每执行一次操作需要1ms 那么:
16 256 1024
简单查找 16ms 256ms 1024ms
二分查找 4ms 8ms 10ms
由此可见,当需要查找的数据变得越大,二分查找算法所需时间的增量很小,而简单查找算法的增量则很大。这就提现了二分查找在性能上的优越性。
2. 常见的大O运行时间:
- O(log^n),对数运行时间,如二分查找。
- O(n),线性运行时间,如简单查找。
- O(n*log^n),如快速排序。
- O(n^2),如选择排序。
- O(n!),如旅行商问题的解决方案
在上面的问题中,假设每秒能执行10次操作,那么这些大O的运行时间如下:
O(n) O(log^n) O(n*log^n) O(n^2) O(n!)
16 0.4s 1.6s 6.4s 25.6s 66301 year
256 0.8s 25.6s 3.4min 1.8h 2.7X10^498 year
1024 1.0s 102.4s 17min 1.2d 1.72X10^2631 year
3. 旅行商问题:
这个问题大致是,如果一个商人要去6个城市,那么如何规划路线可以让行程最短?
很明显,如果要知道最短行程,则需要把条路线都计算一遍,那么6个城市有720种组合,则需要执行720次。
那么如果要去n个城市,则需要执行n!次操作。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。