前端算法总结

80 阅读7分钟

选择排序

  • 选择一个最小的数,插在数组第一个位置;然后选择第二小的数,插在数组第二个位置...

  • 先假设第一个数是数组中最小的数,然后从头开始遍历;查找第一个数之后的元素,看是否有比最小数还小的最小数,如果有,就把索引值记录下来;如果找到后,就将该元素与最小值的位置进行交换;找完后再从第二个数开始往后找(因为第一个数已经是最小值了),寻找方法跟之前一样,如此往复

    var arr = [ 4, 8, 5, 2, 9, 7, 3, 1, 6 ];
    
    for(var i = 0; i < arr.length - 1; i++){
        var minIndex = i;
        for(var j = i + 1; j < arr.length; j++){
            if(arr[j] < arr[minIndex]) minIndex = j;
        }
        if(minIndex !== i){
            var tmp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = tmp;
        }
    }
    
    console.log(arr);
    

冒泡排序

  • 冒泡顾名思义,即像泡泡一样,轻的升到上面

  • 我们需要将数组中的数进行两两比较,若前一个数比后一个数大,则进行交换;一轮比较换后,最后一个数就是最大的数;然后再从头开始再次进行两两比较,将大数往后进行交换。所以一共需要两重循环,第一重循环用于控制一共进行多少次两两比较,第二重循环用于控制两两比较。第一重一共需要循环 length - 1 次,第二重一共需要 length - 1 - i 次,因为每循环完一次,就会多一个数不需要参与比较,即被沉到右边的数

    var arr = [ 4, 8, 5, 1, 9, 7, 2, 3, 6 ];
    
    /*
    两两进行比较,若前面的大于后面的,则进行交换,这样大数就会沉到底部
    一共有 length 个元素,两两进行比较,所以只需要进行 length - 1 次循环
    */
    for(var i = 0; i < arr.length - 1; i++){
        /*
        用于标记是否交换过数组,若交换过 flag 的值为真,说明现在的数组可能还是乱序的,需要继	 续循环比较交换;若没有交换过 flag 的值为假,说明此时的数组已经是有序的了,不需要再循	  环比较了。也就是假如一共需要循环 7 次,当在第五次的时候数组已经是有序的了,此时便可以     不再循环了,因为不需要再进行交换数组了,接着循环也没有意义
        */
        var flag = false;
        /*
        从第一个数开始比较,若比后面的大,则进行交换
        第一轮循环结束后,最后一位就是数组中最大的数,
        下一次循环的时候不需要参与比较
        所以第二层循环的次数为 arr.length - 1 - i
        */
        for(var j = 0; j < arr.length - 1 - i; j++){
            if(arr[j] > arr[j + 1]){
                var tmp = arr[j];
                arr[j] = arr[j +1];
                arr[j + 1] = tmp;
                flag = true;
            }
        }
        if(!flag) break;
    }
    
    console.log(arr);
    

计数排序

  • 将数组中的数进行统计,看某个数一共有多少个,将其装入一个新的数组,将原数组清空,然后再重新填回原来的数组

  • 计算某个数有多少个时,将该数作为新数组的下标,判断新数组中该位置的数是否为0,若为0,将该位置置一;否则进行自增操作,表示有 n 个该数(原数组中有重复元素)

  • 回填时,从头开始遍历新数组,下标就是需要回填的数,即回填的回去的数一定是有序的,因为是按下标依次回填(新数组的下标就是要回填的数);若该下标所在的位置存放的数为0,说明原数组中没有该数,跳过;否则将其填回原数组,有多少个填多少个,即看新数组该位置存放的是几

    var arr = [ 10, 20, 10, 11, 3, 5, 7, 4, 3, 2, 1, 3, 4, 5, 6, 11 ];
    var temp = []; //用 temp 数组的值表示该数有多少个
    
    for(var i = 0; i < arr.length; i++){
        //把数组中的值作为 temp 数组的索引值
        var index = arr[i];
        //查找该索引位置,若该数已经存在在 temp 中,则将数组值加一,否则将值置一
        temp[index] ? temp[index]++ : temp[index] = 1;
    }
    
    arr.length = 0; //清空数组可直接将数组长度置为0
    
    for(var i = 0; i < temp.length; i++){
        //若该位置没有数,也就是说原数组中没有 i 这个数,就跳过,看下一个数有没有
        if(!temp[i]) continue;
        
        //将某个数的总个数记录下来
        var count = temp[i];
        //将要回填的数记录下来,要回填的数就是 i
        var data = i;
        
        for(var j = 0; j < count; j++){
            arr[arr.length] = data; 
            //下标等于数组长度等于在数组末尾添加元素,因为数组中最后一个数的下标是 length - 1
        }
    }
    
    console.log(arr);
    

快速排序

  • 找到数组中中间的数字(称其 center),然后和数组中其他元素进行比较,若比它小,就放到一个数组中(称为左数组,将其放在 center 左面),否则放到另一个数组中(称为右数组,将其放在 center 右边),即 center 左边的都是比它小的数,右边都是比它大的数;然后再对左右数组进行重复操作,直到只剩一个元素或者没有元素的时候停止;此时将数组的合并起来,该数组就是升序的

    var arr = [ 4, 7, 5, 2, 6, 3, 9, 1, 8 ];
    
    function quick_sort(a){
        //如果数组的长度小于等于 1,就可以停止递归了
        if(a.length <= 0) return a;
        
        //取出数组中间的数字
        var center = a.splice(parseInt(a.length / 2), 1)[0];
        
        //left 数组用于存放比 center 小的数,right 数组用于存放比 center 大的数
        var left = [], right = [];
        
        for(var i = 0; i < arr.length; i++){
            //将比 center 小的数放到 left 数组中,大的放到 right 数组中
            a[i] < center ? left.push(a[i]) : right.push(a[i]);
        }
        
        /*
        此时 left 数组,center,right 数组整体是有序,但 left 和 right 数组内
        是无序的,所以需要对 left 和 right 数组进行刚才的重复操作,可以使用递归来
        实现,当数组中的元素个数小于等于 1 的时候,就是递归结束的时候。因为此时只剩
        一个或零个元素,不需要再划分 left 和 right 数组了。将值进行返回然后进行拼接
        */
        
        
        return [...quick_sort(left), center, ...quick_sort(right)];
    }
    

插入排序

  • 对于数 a ,从后往前扫描数组,找到相应的顺序插入
  • 遍历整个数组,从第 1 个位置开始,记作 a 往前开始比较,若前面的数比他大就继续往前比较(没有走到最开始的位置并且也没有发现比他小的数),当找到比他小的数时停止,记作b,此时 b < a ,也就是说把 b 放在 a 的后面数组会趋向于有序;将之前比较过的数依次向后移一位,将 b 后面的位置空出来用于将 a 插入进去
var arr = [ 4, 5, 2, 7, 6, 3, 9, 1, 8 ];

for(var i = 0; i < arr.length; i++){
    //将数组中的某个值记录下来,后面用于插入
    var temp = arr[i];
    //将 temp 前面的数的下标记录下来,用于循环比较,因为是向前比较
    var j = i - 1;
    
    //没有发现比 temp 小的数且也没有找到数组最开始的位置,就继续向前比较
    while(j >= 0 && temp < arr[j]){
        //将 temp 前面的数依次向后移
        arr[j + 1] = arr[j];
        //没移完一次就将 j 减一,用于下一次比较
        j--;
    }
    
    //循环结束时,多减了一次,需要加回来
    arr[j + 1] = temp;
}

console.log(arr);