Javascript算法系列之快速排序(Quicksort)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Javascript算法系列之快速排序(Quicksort)
原⽂出⾃:
快速排序(Quicksort)是对冒泡排序的⼀种改进,是⼀种分⽽治之算法归并排序的风格
核⼼的思想就是通过⼀趟排序将要排序的数据分割成独⽴的两部分,其中⼀部分的所有数据都⽐另外⼀部分的所有数据都要⼩,然后再按此⽅法对这两部分数据分别进⾏快速排序,整个排序过程可以递归进⾏,以此达到整个数据变成有序序列
理论上的步骤:
1. 找到⼀个“⽀点”项⽬在数组中,可以是中⼼点,基准
2. 在阵列中的第⼀项开始指针(左指针)。

3. 在数组中的最后⼀个项⽬开始⼀个指针(右指针)。

4. ⽽在左指针数组中的值⼩于枢轴值,将左指针向右(加1)。

继续,直到在左指针的值⼤于或等于所述枢轴值。

5. ⽽在合适的指针数组中的值⼤于枢轴值,将右指针向左(减去1)。

继续下去,直到在正确的指针的值⼩于或等于所述枢轴值。

6. 如果左指针是⼩于或等于右指针,然后交换的值在数组中的这些位置。

7. 移动左指针向右由1和右指针向左之⼀。

8. 如果左指针和右指针不符合,请转到步骤1。

原⽂太罗嗦了,简单的来说
1. 在数据集之中,选择⼀个元素作为"基准"(pivot)。

2. 所有⼩于"基准"的元素,都移到"基准"的左边;所有⼤于"基准"的元素,都移到"基准"的右边。

3. 对"基准"左边和右边的两个⼦集,不断重复第⼀步和第⼆步,直到所有⼦集只剩下⼀个元素为⽌。

来个实际的demo
var items = [4, 2, 6, 5, 3, 9];
具体的流程算法如下:
针对这⼀组数组,如何选择这个⽀点呢,有些算法选择第⼀项为⽀点,这是不是最好的选择,性能最差。

⼀般更好地选择数组中间的⽀点,所以考虑5是枢轴值(数组的长度除以2)
接下来从左边拿0位置拿第⼀个数与⽀点5对⽐,如果4<5,那么指针的位置就偏移到1,然后2<5,⼀次类推
如果6>5的时候,此时左边的指针就停⽌移动
然后从右边的指针开始移动,也是如此,只是右边是取的⼤于的值,⽐如9>5 ,往前移位,3<5,此时也停⽌移动,然后交换指针对应的数值
第⼀步:选择⽀点
第⼆步: 指针在前后开始偏移
第三步:如果4<5,继续移动左边的指针往下
第四步:如果2<5,往下,6>5停⽌
第五步:9>5,往前,3<5停⽌
第六步:交换指针指向的值
第七步:继续如上的操作,直到⽀点
第⼋部:如果指针到了⽀点,就停⽌
配合实现交换的swap的代码
function swap(items, firstIndex, secondIndex){
var temp = items[firstIndex];
items[firstIndex] = items[secondIndex];
items[secondIndex] = temp;
}
实现的代码
function partition(items, left, right) {
var pivot = items[Math.floor((right + left) / 2)],
i = left,
j = right;
while (i <= j) {
while (items[i] < pivot) {
i++;
}
while (items[j] > pivot) {
j--;
}
if (i <= j) {
swap(items, i, j);
i++;
j--;
}
}
return i;
}
这个函数接受三个参数: items ,这是值进⾏排序的阵列, left ,这是该指数以启动左指针时,和right ,这是该指数以启动右指针。

枢轴值是通过将所确定的left和right的值,然后除以2。

因为这个值可能是⼀个浮点数,有必要进⾏⼀些舍⼊。

整个算法是循环只是⼀个循环。

外环确定何时所有的数组范围的项⽬已经被处理。

左,右指针的两个内部循环控制运动。

当两个内部循环的完成,则该指针进⾏⽐较,以确定是否交换是必要的。

在交换之后,两个指针被移动,使外循环继续,在合适的地⽅。

该函数返回的左指针的值,因为这是⽤于确定从哪⾥开始隔间的下⼀次。

请记住,该分区是发⽣在地⽅,⽽不会产⽣任何额外的数组。

快速排序算法基本上通过划分整个阵列的⼯作原理,然后递归地分割阵列的左侧和右侧的部分,直到整个阵列被排序。

在前⾯的例⼦中,数组变[4, 2, 3, 5, 6, 9]⼀个分区,并返回索引后为4(左指针的最后⼀个席位),开始递归左右2个分割阵列
如下⾯的图所⽰
第⼀步:找到指针遍历的位置,确定⽀点
第⼆步:从左右指针位置开始,对⽐4<3,停⽌
第三步:因为5>3,移动右边的指针,因为3==3,停⽌
第四步:交换指针指向的值
第五步:依次如上处理
第六步:因为2<3,移动左边指针,因为4>3,停⽌
因为左边的指针超过了右边的指针,停⽌
该过程之后,该阵列变成[3, 2, 4, 5, 6, 9]和返回的索引是1,继续这样,直到所有的阵列左侧的排序。

然后相同的处理接着在右侧的阵列。

基本对数的快速排序,然后变得⾮常简单:
function quickSort(items, left, right) {
var index;
if (items.length > 1) {
index = partition(items, left, right);
if (left < index - 1) {
quickSort(items, left, index - 1);
}
if (index < right) {
quickSort(items, index, right);
}
}
return items;
}
// first call
var result = quickSort(items, 0, items.length - 1);
快速排序通常被认为是⾼效,快速等特点是使⽤V8引擎的实现Array.prototype.sort()上有超过23个项⽬的数组。

对于少于23个项⽬,V8采⽤插⼊排序法[2]。

归并排序是快速排序的竞争对⼿,因为它也是⾼效,快捷,但有被稳定的好处。

这就是为什么Mozilla和Safari中使⽤它⾃⼰的执
⾏Array.prototype.sort()。

相关文档
最新文档