JS撸算法:快速排序

181 阅读2分钟

快速排序

思路

如何选定一个数组内元素,将数组划分为小于等于该元素和大于该元素的部分?

我们可以找随机一个中心点,做一次划分操作:小于中心点的元素放在中心点的左边,大于中心点的元素放在中心点的右边。

这样划分完成后,中心点就放在了有序的位置,数组也变得相对有序。

我们可以不停的划分数组,一直把数组划分为单个元素为止,单个元素本身就是有序的,即所有的元素就都被排好了序。

这种思想在算法中通常叫做分治,一般用递归来实现。

例子

把数组从小到大排序。

首先我们把数组最后一个元素作为中心点。

接下来,我们在不改变内存的情况下,通过元素间的交换完成划分的操作,可以通过双指针的方式完成,第一个指针左边的元素小于等于中心点,第二个指针右边元素全部大于等于中心点。。

第一个指针从左边第一个元素开始,第二个指针从中心点开始。

当第一个指针指向的元素大于中心点时,将该元素与右指针的前一个元素交换,此时第一个指针位置不变,右指针向前一步。

当第一个指针指向的元素小于等于中心点时,将左指针向前一步。

循环比较第一个指针指向的元素与中心点,直到两指针相遇。

通过把划分的操作一直递归操作下去,至子数组为一个元素为止,递归完成后即排序完成。

快速排序过程如下图所示:

js实现


function swap(data, i, j) { 
  let temp = data[i];
  data[i] = data[j];
  data[j] = temp;
}

function sort(data, start = 0, end = data.length - 1) {
  if (end - start < 1) return;

  const mid = partition(data, start, end);

  sort(data, 0, mid - 1);
  sort(data, mid + 1, end);
}

function partition(data, start, end) {
  const pivot = data[end];
  let i = start, j = end;
  while(i !== j) {
    if(data[i] > pivot) {
      swap(data, i, --j);
    } else {
      i++;
    }
  }
  swap(data, j, end);
  return j;
}

Tips

coding的难点在于数组的划分,通过双指针把数组划为三个部分:小于中心点部分,不符合规则部分,大于中心点部分。通过指针的移动,直到消除所有不符合规则的部分。

完成了划分,即可通过分治,控制好终止条件,一直向下划分即可。