排序:快速排序

发布于 2024-09-20 11:40:08 字数 2460 浏览 10 评论 0

快速排序也许是最常用的排序算法了。它的复杂度为 O(nlogn),且它的性能通常比其他的复杂度为 O(nlogn) 的排序算法要好。和归并排序一样,快速排序也使用分治的方法,将原始数组分为较小的数组(但它没有像归并排序那样将它们分割开)。

快速排序比到目前为止你学过的其他排序算法要复杂一些。让我们一步步地来学习。

  1. 首先,从数组中选择中间一项作为主元。
  2. 创建两个指针,左边一个指向数组第一个项,右边一个指向数组最后一个项。移动左指针直到我们找到一个比主元大的元素,接着,移动右指针直到找到一个比主元小的元素,然后交换它们,重复这个过程,直到左指针超过了右指针。这个过程将使得比主元小的值都排在主元之前,而比主元大的值都排在主元之后。这一步叫作划分操作。
  3. 接着,算法对划分后的小数组(较主元小的值组成的子数组,以及较主元大的值组成的子数组)重复之前的两个步骤,直至数组已完全排序。

让我们开始快速排序的实现吧:

this.quickSort = function(){
  quick(array,  0, array.length - 1);
};

就像归并算法那样,开始我们声明一个主方法来调用递归函数,传递待排序数组,以及索引 0 及其最末的位置(因为我们要排整个数组,而不是一个子数组)作为参数。

var quick = function(array, left, right){

  var index; //{1}

  if (array.length > 1) { //{2}

    index = partition(array, left, right); //{3}

    if (left < index - 1) {                //{4}
      quick(array, left, index - 1);     //{5}
    }

    if (index < right) {  //{6}
      quick(array, index, right);        //{7}
    }
  }
};

首先声明 index(行 {1}),该变量能帮助我们将子数组分离为较小值数组和较大值数组,这样,我们就能再次递归的调用 quick 函数了。partition 函数返回值将赋值给 index(行 {3})。

如果数组的长度比 1 大(因为只有一个元素的数组必然是已排序了的(行 {2}),我们将对给定子数组执行 partition 操作(第一次调用是针对整个数组)以得到 index(行{3})。如果子数组存在较小值的元素(行 {4}),则对该数组重复这个过程(行 {5})。同理,对存在较大值得子数组也是如此,如果存在子数组存在较大值,我们也将重复快速排序过程(行 {7})。

划分过程

第一件要做的事情是选择主元(pivot),有好几种方式。最简单的一种是选择数组的第一项(最左项)。然而,研究表明对于几乎已排序的数组,这不是一个好的选择,它将导致该算法的最差表现。另外一种方式是随机选择一个数组项或是选择中间项。

现在,让我们看看划分过程:

var partition = function(array, left, right) {
 
  var pivot = array[Math.floor((right + left) / 2)], //{8}
    i = left,                                      //{9}
    j = right;                                     //{10}
 
  while (i <= j) {                //{11}
    while (array[i] < pivot) {  //{12}
      i++;
    }
    while (array[j] > pivot) {  //{13}
      j--;
    }
    if (i <= j) { //{14}
      swap(array, i, j); //{15}
      i++;
      j--;
    }
  }
  return i; //{16}
};

在本实现中,我们选择中间项作为主元(行 {8})。我们初始化两个指针:left(低——行{9}),初始化为数组第一个元素;right(高——行 {10}),初始化为数组最后一个元素。

只要 left 和 right 指针没有相互交错(行 {11}),就执行划分操作。首先,移动 left 指针直到找到一个元素比主元大(行{12})。对 right 指针,我们做同样的事情,移动 right 指针直到我们找到一个元素比主元小。

当左指针指向的元素比主元大且右指针指向的元素比主元小,并且此时左指针索引没有右指针索引大(行 {14}),意思是左项比右项大(值比较)。我们交换它们,然后移动两个指针,并重复此过程(从行{11}再次开始)。

在划分操作结束后,返回左指针的索引,用来在行{3}处创建子数组。

swap 函数代码如下:

[array[index1], array[index2]] = [array[index2], array[index1]];

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

画中仙

暂无简介

0 文章
0 评论
24 人气
更多

推荐作者

謌踐踏愛綪

文章 0 评论 0

开始看清了

文章 0 评论 0

高速公鹿

文章 0 评论 0

alipaysp_PLnULTzf66

文章 0 评论 0

热情消退

文章 0 评论 0

白色月光

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文