快速排序

概念:

快速排序采用分治法对列表元素进行排序。即将问题分解成子问题,再将子问题分解成子子问题,直到最后的子问题不能分解为止。

工作原理:

  1. 在数组中选择一个元素,这个元素被称为基准(Pivot)。通常把数组中的第一个或中间的元素或最后一个元素作为基准。
  2. 然后,重新排列数组的元素,以使基准左侧的有元素都小于基准,而右侧的所有元素都大于基准。这一步称为分区。如果一个元素等于基准,那么在哪一侧都无关紧要。
  3. 针对基准的左侧和右侧分别重复这一过程,直到对数组完成排序。

接下来通过一个例子理解这些步骤。假设有一个含有未排序元素 [7, -2, 4, 1, 6, 5, 0, -4, 2] 的数组。选择最后一个元素作为基准。数组的分解步骤如下图所示:

在算法的步骤1中被选为基准的元素带颜色。分区后,基准元素始终处于数组中的正确位置。

黑色粗体边框的数组表示该特定递归分支结束时的样子,最后得到的数组只包含一个元素。

最后可以看到该算法的结果排序。

代码实现:

这个算法最主要的是分区的思想,我们先抽出一个数组分区的方法:

function partition(arr, start, end){
    // 以最后一个元素为基准
    const pivotValue = arr[end];
    let pivotIndex = start; 
    for (let i = start; i < end; i++) {
        if (arr[i] < pivotValue) {
        // 交换元素(最后pivotIndex前面的值比pivotIndex后面的值小)
        [arr[i], arr[pivotIndex]] = [arr[pivotIndex], arr[i]];
        // 移动到下一个元素
        pivotIndex++;
        }
    }
    
    // 把基准值放在中间(pivotIndex的位置,不一定是数组最中间的位置)
    [arr[pivotIndex], arr[end]] = [arr[end], arr[pivotIndex]] 
    return pivotIndex;
};

递归方法1(以末尾元素为基准):

function quickSortRecursive(arr, start, end) {
    // 终止条件
    if (start >= end) {
        return;
    }
    
    // 返回 pivotIndex
    let index = partition(arr, start, end);
    
    // 将相同的逻辑递归地用于左右子数组
    quickSortRecursive(arr, start, index - 1);
    quickSortRecursive(arr, index + 1, end);
}

递归方法2(以中间元素为基准)

    var devide_Xin = function (array, start, end) {
        if(start >= end) return array;
        var baseIndex = Math.floor((start + end) / 2), // 基数索引
             i = start,
             j = end;

        while (i <= j) {
            while (array[i] < array[baseIndex]) {
                i++;
            }
            while (array[j] > array[baseIndex])  {
                j--;
            }

            if(i <= j) {
                var temp = array[i];
                array[i] = array[j];
                array[j] = temp;
                i++;
                j--;
            }
        }
        return i;
    }

    var quickSort_Xin = function (array, start, end) {
        if(array.length < 1) {
            return array;
        }
        var index = devide_Xin(array, start, end);
        if(start < index -1) {
            quickSort_Xin(array, start, index - 1);
        }
        if(end > index) {
            quickSort_Xin(array, index, end);
        }

        return array;
    }

测试:

array = [7, -2, 4, 1, 6, 5, 0, -4, 2]
quickSortRecursive(array, 0, array.length - 1)

console.log(array)  // [-4,-2,0,1,2,4,5,6,7]

 效率:

快速排序在最坏情况下的时间复杂度是O( n^2 ) 。平均时间复杂度为O(nlogn)

 

posted @ 2020-10-14 14:53  redRunZhy  阅读(140)  评论(0编辑  收藏  举报