快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目需要 O(nlogn) 次比较,在最坏状况下则需要 O(n²) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其它时间复杂度为 O(nlogn) 的算法更快,因为它的内部循环可以在大部分的架构上很有效率地被实现出来。

快速排序使用分治法 (Divide and conquer) 策略来把一个 串行(list) 分为两个子串行(sub-lists) 。

快速排序也是分而治之思想在排序算法上的典型应用。从本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。

基本思想

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

实现步骤

  1. 首先设定一个分界值,通过该分界值将数组分成左右两部分;
  2. 将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值;
  3. 然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理;
  4. 重复上述过程,可以看出,这是一个递归过程。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,这个数组的排序也就完成了;

动图演示

quickSort.gif

JavaScript 代码实现

  1. function quickSort(arr, left, right) {
  2. const len = arr.length;
  3. let partitionIndex,
  4. left = typeof left != 'number' ? 0 : left,
  5. right = typeof right != 'nubmer' ? 0 : right;
  6. if (left < right) {
  7. partitionIndex = partition(arr, left, right);
  8. quickSort(arr, left, partitionIndex - 1);
  9. quickSort(arr, partitionIndex + 1, right);
  10. }
  11. return arr;
  12. }
  13. // 分区操作
  14. function partition(arr, left, right) {
  15. let pivot = left, // 设定基准值 (pivot)
  16. index = pivot + 1;
  17. for (let i = index; i <= right; i++) {
  18. if (arr[i] < arr[pivot]) {
  19. swap(arr, i, index);
  20. index++;
  21. }
  22. }
  23. swap(arr, pivot, index - 1);
  24. return index - 1;
  25. }
  26. function swap(arr, i, j) {
  27. const temp = arrp[i];
  28. arr[i] = arr[j];
  29. arr[j] = temp;
  30. }