javaScript中常见的排序方法

江枫思渺然 提交于 2019-11-26 19:31:21

  之前把常见的那几种算法看了好几次,看的时候也手写了一遍,可是等到过了

好几天又给忘了,所以决定记录下来分享一下,也方便自己以后查看😁

冒泡排序

  冒泡排序是属于交换排序的一种,通过比较相邻的两个数据然后进行交

换,冒泡排序的时间复杂度为o(n^2)。

function BubbleSort(arr) { 
     for(let i=0;i<arr.length;i++){
         for(let j=0;j<arr.length-i-1;j++){
             if(arr[j]>arr[j+1]){
                 [arr[j],arr[j+1]]=[arr[j+1],arr[j]];  //交换值
             }
         }
     }
     return arr;
  }

选择排序

  选择排序是通过记录下标的方式进行比较的,定义变量(index)等于当前

下标(i),循环当前下标后面的元素,如果后面的元素比当前元素大(或者小),先不着急

交换元素,只替换下标(下标交换),一次循环过后最小元素下标的位置可以确定,最

终交换当前元素(arr[i])值和最小(或最大)下标(arr[index])的值。选择排序的时间复杂度为o(n^2)

	// 选择
    function chooseSort(arr){
        for(let i = 0;i<arr.length;i++){
           let index = i;  //记录当前元素下标
            for(let j =i+1;j<arr.length;j++){
                if(arr[j]<arr[index]){
                    index = j;  //只交换下标
                }
            }
            [arr[i],arr[index]] = [arr[index],arr[i]]  //一次循环之后再进行交换
        }
        return arr
    }

插入排序

  插入排序默认数组第一个元素有序,从第二个元素开始从后向前进行

比较,插入排序的时间复杂度为o(n^2)。

   //插入排序
    function insert(arr) {
        for (let i = 1; i < arr.length; i++) {
            let current = arr[i];  //记录当前值
            let pre_index = i - 1;  //得到上一个元素下标
            while (current <= arr[pre_index] && pre_index >= 0) {  //如果下标小于0,已经到达数组开头
                arr[pre_index + 1] = arr[pre_index];    //交换元素
                pre_index--;   //再比较下一位元素
            }
            arr[pre_index + 1] = current;
        }
        return arr;
    }

  以上这几种的时间复杂度都是o(n^2),也比较耗费性能。下面介绍两种时间复

杂度为o(nlogn)的排序算法。

快速排序

  我选择了这种方式的快排,比较好理解。还有一种 “刨坑式”的快排,那种在理

解上有点难度,它通过左右两个指针(或变量)对应的值进行比较,然后进行交换。

  以下代码的原理是通过数组进行排序的,递归的去排序左右数组。

    //快排
    function quickSort(arr) {
        if (arr.length <= 1) return arr;
        let left = [],
            middle = [arr[0]],
            right = [];
        for (let index = 1; index < arr.length; index++) {
            if (arr[index] < middle[0]) {
                left.push(arr[index])  //比它小的放到左边
            }else {
                right.push(arr[index])  //本身一样大的元素也放入右边
            }
        }
          // 递归并连接,这一步很重要
        return quickSort(left).concat(middle, quickSort(right))
    }

归并排序

  归并排序主要是利用分治算法的思想,将大问题化解成小问题,最终得到

原问题的解。递归地把数组分割成前后两个子数组直到数组中只有1个元素。同

时,递归地从两个数组中挨个取元素,比较大小并合并。

  // 分割成只有一个元素的数组
function Split(arr){
    if(arr.length<2) return arr;
    let mid = Math.floor(arr.length/2);  //取中间位置
    let left = arr.slice(0,mid);  //得到左边数组
    let right = arr.slice(mid);  //得到右边数组
    return Merge(Split(left),Split(right));
}
function Merge(left,right){
    // 合并+排序
    let result = [];
    while(left.length && right.length){
        if(left[0]<right[0]) result.push(left.shift());  //shift()删除数组头部元素
        else result.push(right.shift());
    }
    //当两个数组比较值不一一对应的时候,可能数组中还有未进行比较的元素,直接concat
    if(left.length) result = result.concat(left);  //若左边数组还有值,直接连接起来
    if(right.length) result = result.concat(right);  //同上
    return result;
}

基数排序

function radixSort(arr) {
    let max_num = Math.max(...arr);
    max_len = getLengthOfNum(max_num);
    //根据最大数进行循环(确定循环次数)
    for (let digit = 1; digit <= max_len; digit++) {
        let buckets = [];
        for (let i = 0; i < 10; i++) buckets[i] = [];  //定义“桶”
        for (let i = 0; i < arr.length; i++) {
            let value= arr[i];
            let pos = getSpecifiedValue(value, digit);
            buckets[pos ].push(value);
        }
         let result = [];
         buckets.toString().split(',').forEach((val) => {
            if (val) result.push(parseInt(val))
        })
        arr = result;  //改变原数组,再次排序  重要
    }
  return arr;
}
function getLengthOfNum(num) { return (num += '').length }  //得到最大数的长度
//根据对应位置的数,如果不存在,返回0
function getSpecifiedValue(num, position) { return (num += '').split('').reverse().join('')[position - 1] || 0 }

对于基数排序可以参考基数排序详解这篇博客,讲解的比较清晰。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!