快速排序动图演示-JS代码实现

588 阅读2分钟

Hoare版本(左右指针法)

霍尔(Sir Charles Antony Richard Hoare)是一位英国计算机科学家,也是快速排序算法的发明者。

算法思路:分治法

分治法就是大问题分解成各个小问题,对小问题求解,使得大问题得以解决。

快速排序是在每一轮挑选一个基准元素,并让比它大的元素移动到数列一边,比它小的元素移动到数列另一边,从而把数列拆解成两个部分。每一部分在下一轮又分别被拆分成两部分,直到不可再分为止。

单轮排序动图

快排霍尔版本动图.gif

代码实现

  1. 取基准元素
  2. 分区过程
  3. 对两个区间重复进行分区操作
function quickSort(arr, startIndex, endIndex) {
  // 递归结束条件
  if (startIndex >= endIndex) {
    return;
  }
  // 每一轮排序后,都要定位pivot所在位置,然后再对其左右两侧的数组分别排序
  let pivotIndex = partition(arr, startIndex, endIndex);
  // 根据基准元素位置,分成两部分递归排序
  quickSort(arr, startIndex, pivotIndex - 1);
  quickSort(arr, pivotIndex + 1, endIndex);
}

function partition(arr, startIndex, endIndex) {
  let i = startIndex;
  let j = endIndex;
  // 取第一个位置的元素作为基准元素
  let pivot = arr[startIndex];
  while (j != i ) {
     //控制右侧指针比较并左移
    while(arr[j] > pivot && i < j) {
      j--;
    }
    //控制左侧指针比较并右移
    while(arr[i] <= pivot && i < j) {
      i++;
    }
    // 跳出上面两个循环后,说明左右指针都不动了.
    // 这时如果左右指针还未重合,就要交换左右指针所指向的元素
    if (i < j) {
      let temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
        j--;   //注意:交换所指向值之后,再次从右指针开始移动
    }
  }
  // 左右指针重合,交换指向元素和基准元素pivot
  arr[startIndex] = arr[j];  
  arr[j] = pivot;   
  return j;
}

let arr = [4,6,5,3,2,8,1,9,7];
quickSort(arr, 0, arr.length -1);
console.log(arr);

时间复杂度

对于基准元素的选择,最简单的方式选择数列的第一个元素。但是如果这个元素是该数列的最大值或最小值,则排序时无法将数列拆解成两部分,时间复杂度会退化成O(n^2)。

因此快速排序最坏时间复杂度是O(n^2),最好的时间复杂度是O(nlogn)。

平均时间复杂度是O(nlogn)。

空间复杂度

在对序列的操作过程中只需花费常数级的空间,因为没有用到额外开辟的集合空间,空间复杂度是O(1)。

但需要注意执行递归操作所需要的内存空间和递归的深度成正比,因此最坏的空间复杂度是O(n), 最好的空间复杂度是O(logn)。

算法稳定性

快速排序是不稳定的排序算法。因为我们无法保证相等的数据按顺序被扫描到和按顺序存放。


参考

六大排序算法