javascript中常见的简单算法题

1、斐波那契数列(1,1,2,3,5,8,13,21...)

最简单的实现

function f1(n){
    // i++;     //判断递归次数
    if(n <= 2) return 1;
    return f1(n-1) + f1(n-2);
}

这是最简单的实现,但我们知道递归次数多了非常耗内存,对性能总是不好的。所以可以用其他方法实现

function f2(n){
    var cache = [1,1,1];
    function _fn(n){
        // i++;     //判断递归次数
        if(cache[n]) return cache[n];
        cache[n-1] = _fn(n-1);
        cache[n-2] = _fn(n-2);
        return cache[n-1] + cache[n-2];
    }
    return _fn(n);
}

该方法主要是将取过的值缓存(这里是用一个数组)起来,这样再读取该值时直接从缓存中拿到就可以了,从而省去了一部分递归。以上两种方法在传入的n数值小的时候还好,如果n的值稍大一点,第一种方法会直接崩溃。下面是两者的一些执行性能上的差异,当n=40时

console.log(f1(40), i, Date.now()-t)    //值为102334155,递归次数204668309,耗时2112ms
console.log(f2(40), i, Date.now()-t)    //值为102334155,递归次数77,耗时7ms

 

2、二分法查找

原理是从一段范围内取出中间位置的值与要查找的值对比,然后再逐渐缩小范围。前提条件是数组是按顺序排列的。

下面代码,默认数组是正序的。

/**
 * @param {[]} arr 数组
 * @param {number} x 要查找的值
 * @method 二分法查找数组中某一个值的索引(数组正序)
 */
function bsearch(arr, x){
    var l = 0;              //左边临界
    var r = arr.length - 1;     //右边临界
    var guess = 0;          //猜测位置

    while(l <= r){
        //猜测中间位置
        guess = Math.floor((r + l) / 2);
        //如果猜对了就返回出去
        if(arr[guess] === x) return guess;
        //如果猜测的值大于要查找的值,则改变右边临界
        else if(arr[guess] > x) r = guess - 1;
        //如果猜测的值小于要查找的值,则改变左边临界
        else l = guess + 1;
    }
    //如果没找到
    return -1;
}

var arr = [1,2,3,34,55,56,89,102,233,345,699,785];
console.log(bsearch(arr, 11))       //-1
console.log(bsearch(arr, 111))      //-1
console.log(bsearch(arr, 345))      //9
console.log(bsearch(arr, 102))      //7

 

3、数组排序

冒泡排序

思路:这里举例正序排列,数组中相邻的两个值进行比较,如果前一个比后一个大,那么交换位置,一轮比下来能得到一个最大值在最后面,然后剩余的在如此循环比较。

/**
 * @param {array} arr 要排序的数组
 * @method 数组冒泡排序
 * @return {array} 排好序的数组
 */
function bubbleSort(arr){
    //外循环控制比较的轮数
    for(var i=0; i arr[j+1]){
                var temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    return arr;
}

var arr = [1,3,23,54,-9,6,10,99];
console.log(bubbleSort(arr))    //[ -9, 1, 3, 6, 10, 23, 54, 99 ]

选择排序

原理:其实跟冒泡排序差不多,只不过冒泡排序是两两比较互换,而选择排序是在当前数组未排序部分选出那个最大值然后移至该部分的最后一位。比如,当前数组长度为5,第一次从这5个中找出最大值移至最后一位,然后剩下的4个再找出最大值移至这4个的最后一位,如此循环,直到数组只剩最后1个为排序的就是数组排序后的第一位。

/**
 * @param {array} arr 数组
 * @param {number} length 数组长度
 * @method 查找数组中是最大值的索引
 * @return 数组中最大值的索引
 */
function findMax(arr, length){
    var max = arr[0], index = 0;
    for(var i=1; i= max) {
            max = arr[i];
            index = i;
        }
    }
    return index;
}

/**
 * @param {array} arr 要排序的数组
 * @param {number} length 数组length
 * @method 选择排序
 * @return {array} 排序后的原数组
 */
function selectSort(arr, length){
    // 数组中还没排序的长度,至少要两个才可以比较
    while(length > 1){
        // 从数组中还没排序的部分找出最大值
        var index = findMax(arr, length);
        var temp = arr[index];
        // 将该最大值移至该数组部分的最后一位
        arr[index] = arr[length-1];
        arr[length-1] = temp;
        length--;
    }
    return arr;
}

var arr = [11,22,23,-9,-23,11,16,23,-9,11,23,56,22];
console.log(selectSort(arr, arr.length));       //[ -23, -9, -9, 11, 11, 11, 16, 22, 22, 23, 23, 23, 56 ]

快速排序

思路:创建两个空数组 l 和 r,从要排序的数组中取出中间位置的值centerValue,然后遍历数组,如果当前值小于等于centerValue,则添加进 l 数组,否则添加进 r 数组,最后数组合并 l 、centerValue、r返回出去。然后进行函数递归。

/**
 * @param {array} arr 要排序的数组
 * @method 数组快速排序
 * @return {array} 排序好的数组
 */
function quickSort(arr){
    // 当数组已经细分到length=1了,就不用再分了
    if(arr.length < 2) return arr;
    var l = [], r = [];
    // 中间位置
    var centerIndex = Math.floor((arr.length - 1)/2);
    // 数组中间位置的值
    var centerValue = arr.splice(centerIndex, 1)[0];
    for(var i=0; i

几种排序效率比较

选择排序与冒泡排序相当。

先随机生成一个length为100的数值数组,冒泡排序、快速排序、原生sort相差无几,5~7ms左右。

length为1000的数值数组,原生sort稍块一点,冒泡和快速排序相差无几。

length为10000的数值数组,原生sort和快速排序相差无几,大概20~30ms,冒泡排序最慢,需要一百多ms。

length为100000的数值数组,原生sort最快,100ms左右;快速排序次之,200多ms;冒泡排序最慢,要10s左右(差距好大)。

变态的来了,最后length来到1000000还是原生最快,800ms左右;快速排序次之,3s左右;冒泡排序直接蹦了。

以上具体时间数值可能受机器环境影响较大,只可用作比较,并不代表实际数值。

你可能感兴趣的:(算法)