一网打尽之冒泡排序

105 阅读4分钟

排序算法是一个老生常谈的话题,也是面试中非常喜欢问的一个知识点,预计7月份更完面试中的10大排序算法(冒泡、选择、插入、希尔、堆、快速、归并、计数、基数、桶)。

一、冒泡排序的定义

如果你是以最大值为维度的排序算法,其实都可以叫冒泡排序。冒泡嘛,鱼吐泡,泡越来越大,新吐出来的泡也一定是最小的,映射到程序上就是每次得出array里的最大值并放到array的最后一项。

二、冒泡排序的重要性

是入门级的算法,也是排序算法里出现时间较早的一个算法。所以对于程序员来说,冒泡是基本功。

三、代码实践

比如我们有这样的一个数组A:[5, 8, 10, 3, 30, 20]。根据冒泡的思想,每次循环得出一个最大值。那对于数组A来说,就需要遍历6次才能得到一个从小到大的完整排序数组。

第一次遍历,有如下逻辑:

58比较,5小于8,这次比较中,8是最大值,所以58的位置不动,此时的数组:[5, 8, 10, 3, 30, 20];
810比较,8小于10,这次比较中,10是最大值,所以810的位置不动,此时的数组:[5, 8, 10, 3, 30, 20];
103比较,10大于3,这次比较中,10是最大值,所以10需要跟3对换位置,此时的数组:[5, 8, 3, 10, 30, 20];
1030比较,10小于30,这次比较中,30是最大值,所以1030的位置不动,此时的数组:[5, 8, 3, 10, 30, 20];
3020比较,30大于20,这次比较中,30是最大值,所以30需要跟20的位置对调,此时的数组:[5, 8, 3, 10, 20, 30];

第一次遍历结束,我们得到了整个数组的最大值30,所以我们第二次循环的时候,最后一项就是20的位置。

第二次遍历,有如下逻辑:

// 第二次遍历开始的时候,数组A:[5, 8, 3, 10, 20, 30];
58比较,5小于8,这次比较中,8是最大值,所以58的位置不动,此时的数组:[5, 8, 3, 10, 20, 30];
83比较,8大于3,这次比较中,8是最大值,所以83的位置对调,此时的数组:[5, 3, 8, 10, 20, 30];
810比较,8小于10,这次比较中,10是最大值,所以810的位置不动,此时的数组:[5, 3, 8, 10, 20, 30];
1020比较,10小于20,这次比较中,20是最大值,所以1020的位置不动,此时的数组:[5, 3, 8, 10, 20, 30];

第二次遍历结束,我们得到了整个数组的第二大值,所以我们第三次循环的时候,最后一项就是10的位置

第N次循环,逻辑跟上面的一样,循环往复......

因此,根据上面的分析,我们可以得出如下冒泡代码:

function bubbling(arr){
    let arrLength = arr.length;
    let arr1 = [...arr];
    // 最外围的遍历
    for (let roundIndex = 0; roundIndex < arr1.length; roundIndex++){
        // 在最外围的基础上,比较每个数据项
        for (let dataIndex = 0; dataIndex < arrLength - roundIndex; dataIndex++){
            if (arr1[dataIndex] > arr1[dataIndex + 1]){
                // 交换位置
                [ arr1[dataIndex], arr1[dataIndex + 1] ] = [ arr1[dataIndex + 1], arr1[dataIndex] ];
            }
        }
    }
    return arr1;
}

四、最后

好啦,本次冒泡到这里就结束啦,其实网上有很多关于冒泡的优化,但是在我看来治标不治本,因为他们的算法在遇到最坏的情况下,跟没优化的代码是一样的(其实主要还是看应用场景,毕竟场景不同,数据的表现形式千变万化),都要走那么多步骤,当然你们也可以去了解一下。

下期我会讲一下冒泡的逆向实现(也就是选择排序),我们下次再见啦~~