JS算法-十大排序算法(上)

思想小剧场

如果我的相对论被证明是正确的,德国人就会说我是德国人,法国人会说我是一个世界公民;如果我的相对论被否定了,法国佬就会骂我是德国鬼子,而德国人就会把我归为犹太人。—爱因斯坦

以下案例都是升序

const arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48];

冒泡排序

一个一个数进行处理,第i个数,需要与后续的len-i-1个数进行逐个比较

// 1、冒泡排序
const bubbleSort = (arr) => {
    const len = arr.length;
    for (let i = 0; i < len - 1; i++) {
        for (let j = 0; j < len - i - 1; j++) { // 相邻元素两两比较
            if (arr[j] > arr[j+1]) {
                [arr[j], arr[j+1]] = [arr[j+1], arr[j]]; // 元素交换
            }
        }
    }
    return arr;
}
console.log("冒泡排序 => ", bubbleSort(arr))

快速排序(冒泡)

通过选定一个数字作为比较值,将要排序的其他数字,分为 >比较值 和 <比较值 两个部分。并不断重复这个步骤,直到只剩要排序的数字只有本身,则排序完成

// 2、快速排序 - 分治法
const quickSort = (arr) => {

    const sort = (arr, low, high) => {
        if (low >= high) {
            return;
        }
    
        let i = low;
        let j = high
        const x = arr[i]; // 取出比较值
        while (i < j) {
            // 从数组尾部,找出比x小的数,放到左边
            while (arr[j] >= x && i < j) {
                j--;
            }
            // 将空出的位置,填入当前值,下标j位置空出
            if (i < j) {
                arr[i] = arr[j];
                i++;
            }
    
            // 从数组头部,找出比x大的数字
            while (arr[i] <= x && i < j) {
                i++;
            }
    
            // 将数字填入下标j中,下标i位置突出
            if (i < j) {
                arr[j] = arr[i];
                j--;
            }
            // 一直循环到左右指针i、j相遇
            // 相遇时,i==j,所以下标i位置空出的
        }
        arr[i] = x; // 将空出的位置,填入缓存的数字x,一轮排序完成
    
        // 分别对剩下的两个区间进行递归排序
        sort(arr, low, i - 1);
        sort(arr, i + 1, high);
    }

    sort(arr, 0, arr.length - 1);  
    return arr;
   
}

console.log("快速排序 => ", quickSort(arr))

希尔排序

是一种插入排序的算法,是对简单的插入排序进行改进后,更高效的版本。
特点是利用增量,将数组分为一组组子序列,然后对子序列进行插入排序。
由于增量是从大到小,逐次递减,所以也称为缩小增量排序。

注意:插入排序时,并不是一个分组内的数字一次性用插入排序完成,而是每个分组交叉进行

执行插入时,使用交换法
// 3.1、希尔排序 - 执行插入时,使用交换法
const shellSort = (arr) => {
    // 分组规则 gap 递减
    for (let gap = Math.floor(arr.length / 2); gap > 0; gap = Math.floor(gap / 2)) {
        for (let i = gap; i < arr.length; i++) {
            let j = i;
            // 分组内数据,执行插入排序
            // 当下标大的数字,小于 下标小的数字,进行交互
            // 分组内的数字,并不是一次性比较完,需要i逐步递增,包括下个分组内的数字
            while (j - gap >= 0 && arr[j] < arr[j - gap]) {
                [arr[j], arr[j - gap]] = [arr[j - gap], arr[j]];
                j = j - gap;
            }
        }
    }
    return arr;
}
console.log("希尔排序(交换法) => ", shellSort(arr))
执行插入时,使用移动法
// 3.2、希尔排序 - 执行插入时,使用移动法
const shellSort2 = (arr) => {
    // 分组规则 gap 递减
    for (let gap = Math.floor(arr.length / 2); gap > 0; gap = Math.floor(gap / 2)) {
        for (let i = gap; i < arr.length; i++) {
            let j = i;
            // 缓存数字,空出位置
            const x = arr[j];
            // 分组内数据,执行插入排序
            // 当下标大的数字,小于 下标小的数字,进行交互
            // 分组内的数字,并不是一次性比较完,需要i逐步递增,包括下个分组内的数字
            while (j - gap >= 0 && x < arr[j - gap]) {
                arr[j] = arr[j - gap];  // 将符合条件的数字,填入空出的位置
                j = j - gap;
            }
            arr[j] = x; // 将缓存的数字,填入空出的位置
        }
    }
    return arr;
}
console.log("希尔排序(移动法) => ", shellSort2(arr))

选择排序

每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。

// 4、选择排序
const selectionSort = (arr) => {
    for (let i = 0, len = arr.length; i < len - 1; i++) {
        for (let j = i + 1; j < len; j++) {
            if (arr[i] > arr[j]) {
                [arr[i], arr[j]] = [arr[j], arr[i]]; // 元素交换
            }
        }
    }
    return arr;
}
console.log("选择排序 => ", selectionSort(arr))

归并排序(分治)

利用分治思想,将大的数组,分解为小数组,直至单个元素。然后,使用选择排序的方式,对拆分的小数组,进行回溯,并有序合并,直至合并为一个大数组。

// 5、归并排序 - 分治
const mergeSort = (arr) => {

    // 合并两个有序数组
    const mergeSort = (leftArr, rightArr) => {
        let left = 0;
        let right = 0;
        const temp = [];

        // 使用双指针,对两个数组进行扫描
        while (left < leftArr.length && right < rightArr.length) {
            if (leftArr[left] < rightArr[right]) {
                temp.push(leftArr[left++]);
            } else {
                temp.push(rightArr[right++]);
            }
        }

        // 合并剩下的内容
        if (left < leftArr.length) {
            while (left < leftArr.length) {
                temp.push(leftArr[left++]);
            }
        }

        if (right < rightArr.length) {
            while (right < rightArr.length) {
                temp.push(rightArr[right++]);
            }
        }

        return temp;
    }

    // sort 方法,进行递归
    const sort = (arr, left, right) => {
        // 当 left !== right 时,证明还没拆分到最小元素
        if (left < right) {
            // 取中间值,拆分为两个小的数组
            const mid = Math.floor((left + right) / 2);
            // 递归拆分左边数组
            const leftArr = sort(arr, left, mid);
            // 递归拆分右边数组 
            const rightArr = sort(arr, mid + 1, right);
            // 合并两个数组
            return mergeSort(leftArr, rightArr)
        }

        // left === right 时,已经是最小元素,直接返回即可
        return left >= 0 ? [arr[left]] : []
    }

    return sort(arr, 0, arr.length - 1);
}
console.log("归并排序 => ", mergeSort(arr))
  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值