八大排序算法(上 包含:冒泡,选择,插入,希尔,希尔插入)

这篇博客详细介绍了冒泡排序、选择排序、插入排序以及希尔排序的实现原理,并通过JavaScript实现进行了性能测试。冒泡排序在最佳情况下提前结束,选择排序减少了交换操作,插入排序保持了数组部分有序,而希尔排序则通过分组优化了排序过程。文章通过实际运行时间展示了不同排序算法在大规模数据(80000个元素)下的性能差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(() => {

    // 冒泡排序
    let arr = [];

    /**
     * 从数组的第0个索引开始依次从左到右比较数组中的最小值,如果右边的值比左边小,那么交换值,这样右边的值一直都是最大的值
     * 从而将最大的值冒泡到数组的最后一个索引的位置
     * 然后从第1...n个索引循环 使用依次从左到右比较数组中的最小值,如果右边的值比左边小,那么交换值 冒泡到第n-1...0个索引
     * @param {*} size 
     */
    function bubble(size) {
        initArr(size);
        let isChange = false;
        for (let index = 0; index < arr.length; index++) {
            isChange = false;
            for (let k = 1; k < arr.length - index; k++) {
                if (arr[k - 1] > arr[k]) {
                    [arr[k - 1], arr[k]] = [arr[k], arr[k - 1]];
                    isChange = true;
                }
            }
            if (!isChange) { // 优化
                console.log("提前结束冒泡排序: " + index);
                break;
            }
        }
        console.log("冒泡排序后: ", arr);
    }

    /**
     * 从第0个索引开始找到数组中最小的值,然后交换最小值到0索引  将0索引的值赋值到最小值索引
     * 然后依次 从第1....n个索引开始找出数组中最小的值 在次交换
     * 直到第n个索引将数组全部完成此操作就将数组排序了
     * @param {*} size 
     */
    function selectSort(size) { // 相对于冒泡排序减少了频繁的交换数组位置的操作平均下来时间上优于冒泡排序
        initArr(size);
        let minIndex = 0;
        for (let index = 0; index < arr.length; index++) {
            minIndex = index;
            for (let j = index + 1; j < arr.length; j++) { // 找到未排序区间中一个最小的值的index
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            if (minIndex != index) {
                let temp = arr[index];
                arr[index] = arr[minIndex];
                arr[minIndex] = temp;
                // 在java语言中根据视频结果得知 插入排序的平均执行时间是大于选择排序的,但是在js中 结果却是相反的,也不是下面这句话造成的
                // [arr[minIndex], arr[index]] = [arr[index], arr[minIndex]]; // 交换最小值到下一个排队点
            }
        }
    }

    /**
     * 插入排序 将数组分成两部分看待 一部分是 0-(n-1)的有序数组 一部分是n-length-1的无序数组
     * 保存第n个索引的数值,和有序数组中 (n-1) ~ 0依次比较,如果有序数组中的数值大于第n个索引的数值
     * 那么将有序数组中当前比较索引的数值赋值给 +1 的索引,否则 当前索引就是目标位置,将保存的插入数值进行复制即可
     * @param {*} size 
     */
    function insterSort(size) {
        initArr(size);
        let crtIdx = 0;
        let crtVal = 0;
        for (let index = 1; index < arr.length; index++) {
            crtIdx = index - 1;
            crtVal = arr[index];
            while (crtIdx >= 0 && crtVal < arr[crtIdx]) { // 如果有序数组中的数值大于了插入数值那么就将有序数组中的数值往后排
                arr[crtIdx + 1] = arr[crtIdx];
                crtIdx--;
            }
            arr[crtIdx + 1] = crtVal;
        }
    }

    function shellInsertSort(size) {
        initArr(size);

        // let excuteCount = 0;
        let crtIdx = crtVal = 0;
        for (let gap = Math.floor(arr.length / 2); gap > 0; gap = Math.floor(gap / 2)) {
            for (let i = gap; i < arr.length; i++) {
                crtIdx = i;
                crtVal = arr[i];
                // if(arr[i - gap] > arr[i]){ // 比较当前的值和 下一个值是否存在逆序
                    while(crtIdx-gap >= 0 && crtVal < arr[crtIdx-gap]){ // 使用插入排序的方式
                        arr[crtIdx] = arr[crtIdx-gap];  // 仅仅是将数字赋值到下一个索引
                        crtIdx -= gap;
                    }
                    arr[crtIdx] = crtVal; // 最后一次切换顺序
                // }
            }
            // console.log(`希尔排序第${++excuteCount}轮`, arr);
        }
    }

    function shellSort(size) {
        initArr(size);

        // let excuteCount = 0;
        for (let gap = Math.floor(arr.length / 2); gap > 0; gap = Math.floor(gap / 2)) {
            for (let i = gap; i < arr.length; i++) {
                for (let j = i; j >= gap; j -= gap) {
                    if (arr[j] < arr[j - gap]) { // 只要有顺序问题就会交换,如果是最小的值那么就会全部进行交换
                        [arr[j], arr[j - gap]] = [arr[j - gap], arr[j]];
                    }
                }
            }
            // console.log(`希尔排序第${++excuteCount}轮`, arr);
        }

        /* 
        for (let i = gap; i < arr.length; i++) {
                changeIndex = i;
                changeVal = arr[i];
                for (let j = i; j >= gap; j -= gap) {
                    if (changeVal < arr[j - gap]) {
                        arr[j] = arr[j - gap];
                        changeIndex = j - gap;
                    }
                }
                arr[changeIndex] = changeVal;
            }
        */

		// 记录算法逻辑过程
        /*let test = [8, 9, 1, 7, 2, 3, 5, 4, 6, 0, 3];
        // 第一轮 根据数组长度将其分组  Math.floor(test.length / 2); 也就是 5组
        // 再将每组进行排序
        for (let i = 5; i < test.length; i++) {
            for (let j = i; j >= 5; j -= 5) {
                if (test[j] < test[j - 5]) {
                    [test[j], test[j - 5]] = [test[j - 5], test[j]]; // 交换
                }
            }
        }
        console.log("希尔第一轮: ", test);
        // 第二轮 根据数组长度将其分组  Math.floor(test.length / 2 / 2); 也就是 2组
        // 再将每组进行排序
        for (let i = 2; i < test.length; i++) {
            for (let j = i; j >= 2; j -= 2) { // 将分组内的数组进行排序,这样这两组数组是有序的
                if (test[j] < test[j - 2]) {
                    [test[j], test[j - 2]] = [test[j - 2], test[j]]; // 交换
                }
            }
        }
        console.log("希尔第二轮: ", test);
        // 第三轮 根据数组长度将其分组  Math.floor(test.length / 2 / 2 / 2); 也就是 1组
        // 再将每组进行排序
        for (let i = 1; i < test.length; i++) {
            for (let j = i; j >= 1; j -= 1) { // 从索引1开始 到 length-1 和数组的起始位置进行比较并排序 
                if (test[j] < test[j - 1]) {
                    [test[j], test[j - 1]] = [test[j - 1], test[j]]; // 交换
                }
            }
        }
        console.log("希尔第三轮: ", test);*/
    }

    function initArr(size) {
        arr = new Array(size);  
        for (let index = 0; index < size; index++) {

            arr[index] = Math.floor(Math.random() * size)
        }
        console.log("随机初始化数组", arr);
    }
    let size = 80000;
    console.time("冒泡时间:");
    bubble(size);
    console.timeEnd("冒泡时间:");
    console.time("选择时间:");
    selectSort(size);
    console.log("排序结果", arr);
    console.timeEnd("选择时间:");
    console.time("插入时间:");
    insterSort(size);
    console.log("排序结果", arr);
    console.timeEnd("插入时间:");
    console.time("希尔时间:");
    shellSort(size);
    console.log("排序结果", arr);
    console.timeEnd("希尔时间:");
    console.time("希尔2时间:");
    shellInsertSort(size);
    console.log("排序结果", arr);
    console.timeEnd("希尔2时间:");

})();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值