这篇文章会介绍几种经典的排序算法思想和它们的javaScript实现。
一:冒泡排序
冒泡排序的核心思想是“比较”,即通过比较相邻元素的大小,从而实现从小到大或者从大到小的排序。下面我们以一个最终为从小到大的排序来理解一下冒泡排序的实现思路:

1:从坐标为0的元素开始,比较相邻的两个元素,大的元素放在小的元素后面,直到数组的最后2个元素比较完,这算一个循环。这一轮循环之后,最大的元素会在数组的最后边,但是前面的元素依然是混乱的。

2:依然是从坐标为0的元素开始依次两两比较,直到数组的倒数第二个和倒数第三个这一组比较成成。这一轮完成之后,第二大的元素会在倒数第二的位置,前面的元素依然是混乱的。

从上面的2点,我们可以看出冒泡排序的思路是:
1: 第一趟把最大的元素挪到数组的最后一个
2: 第二趟把第二大的元素挪到数组的倒数第二个
3: 以此类推。每次都是从数组的第0个元素开始两两比较,但是每一趟需要比较的次数依次减1,因为在上一轮里面最大的元素已经在数组的最右边。

当我们已经想清楚了算法的思想,具体到代码实现的时候,我们就需要2个变量:
1: 一个变量i,表示需要循环的趟数,为数组lenght - 1 趟
2: 一个变量j,表示在每一趟里需要比较的次数。每一趟里面它都是从0开始,但是每一趟里面它的最大值会随着趟数的增加依次减1

下面来看一下代码实现。下面是一个从小到大排序的实现。我们打印了每一对元素比较之后的临时数组,可以清楚地看到数组是怎样随着i和j的变化从而一步步变成有序数组的:

function bubbleSort(arr) {
    let len = arr.length;
    for (let i = 0; i < len - 1; i++) {
        console.log("=================");
        console.log(`i: ${i}`);
        for (let j = 0; j < len - 1 - i; j++) {
            console.log(`j: ${j}`);
            if (arr[j] > arr[j + 1]) {
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; //利用ES6的解构特性,交换相邻两个元素
            }
            console.log(`arr: ${arr}`);
        }

    }
    return arr;
}

bubbleSort([5, 4, 3, 2, 1]);

下面是打印信息:

=================
i: 0
j: 0
arr: 4,5,3,2,1
j: 1
arr: 4,3,5,2,1
j: 2
arr: 4,3,2,5,1
j: 3
arr: 4,3,2,1,5
=================
i: 1
j: 0
arr: 3,4,2,1,5
j: 1
arr: 3,2,4,1,5
j: 2
arr: 3,2,1,4,5
=================
i: 2
j: 0
arr: 2,3,1,4,5
j: 1
arr: 2,1,3,4,5
=================
i: 3
j: 0
arr: 1,2,3,4,5    

二: 快速排序
快速排序的特点就是快,它主要采用“分而治之”的思想。递归地二分数组,在分的小组里面进行排序,最后链接这些已经排好序的小组,最终形成一个有序数组。具体的算法思想为:
1: 选一个基准点(一般是选数组中间的元素)
2: 新建两个空数组left和right,比基准点小的元素都放到left数组,大的放到right数组
3: 对left和right子数组递归地重复上面的2步,直到子数组的长度为1。且每一次都链接left数组+基准点+right数组
4: 最终得到一个有序数组

下面我们来看一下代码的实现:

let quickSort = function (arr) {
    if (arr.length <= 1) {
        return arr;
    }
    let pivotIndex = Math.floor(arr.length / 2); 
    let pivot = arr.splice(pivotIndex, 1)[0];
    let left = [];
    let right = [];
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }
    return quickSort(left).concat([pivot], quickSort(right)); 
};

如果用一个图,形象地来说明的话就是:
图片描述

其中:

蓝色的我们需要排序的数组
黄色代表left数组
红色代表right数组
绿色代表我们的基准点,也就是上面代码里的pivot变量

第一轮调用的时候,我们得到

left = [2, 1];
right = [5, 4];
pivot = 3;

接下来我们递归地调用quickSort(left),也就是quickSort(2, 1),得到

pivot = 1;
right = [2];
left = [];

同理,递归调用quickSort(right),也就是quickSort([5, 4]), 得到

pivot = 4;
right = [5];
left = [];

继续递归,但是我们的数组已经都是length为1的数组和空数组了,所以会直接返回数组,从而结束递归。我们通过concat()方法,每一次递归的left,pivot,right链接起来,最终得到排好序的数组。


nanaistaken
586 声望43 粉丝