4
前端也要懂算法,阅《算法图解》有所得。

一、 简单的算法:二分查找

假设要在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!次操作。


Nero
3.2k 声望2.5k 粉丝

前端搬砖者。