算法导论之js实现--快速排序
更新日期:
快速排序的javascript实现。
简单快速排序
排序问题
- 输入:n个数的一个序列
<a1, a2, ..., an>
- 输出:输入序列的一个排列
<a1', a2', ..., an'>
,满足a1' <= a2' <= ... <= an'
思路
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。
步骤为:
- 从数列中挑出一个元素,称为”基准”(pivot),
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
js基本思路实现
这里我们先使用两个数组分别保存“基准”左边、右边的子集。
1 | function fakeQuickSort(iArr) { |
验证
1 | fakeQuickSort([5, 2, 4, 6, 1, 3]); |
快速排序
原址排序
在排序算法中,如果输入数组中仅有常数个元素需要在排序过程中存储在数组之外,则称排序算法是原址的。
插入排序、堆排序、快速排序等都是原址排序。
归并排序不是原址的。
上面简单版本的缺点是,它需要Ω(n)的额外存储空间,也就跟归并排序一样不好。额外需要的存储器空间配置,在实际上的实现,也会极度影响速度和缓存的性能。有一个比较复杂使用原地(in-place)分区算法的版本,且在好的基准选择上,平均可以达到O(log n)空间的使用复杂度。
快速排序思路
上面我们移动位置是通过建立新的子集数组伪装的,这里我们则需要实现真正的位置交换。
- 获取基准值
- 将低于基准值的排列在左侧,剩下的排列在右侧
- 分别对左侧和右侧进行递归排序
这是原址排序算法,它分区了标示为”左边(left)”和”右边(right)”的序列部分,借由移动小于a[pivotIndex]的所有元素到子序列的开头,留下所有大于或等于的元素接在他们后面。
在这个过程它也为基准元素找寻最后摆放的位置,也就是它回传的值。它暂时地把基准元素移到子序列的结尾,而不会被前述方式影响到。
由于算法只使用交换,因此最后的数列与原先的数列拥有一样的元素。要注意的是,一个元素在到达它的最后位置前,可能会被交换很多次。
js基本思路实现
1 | // 交换数组值 |
验证
1 | quickSort([5, 2, 4, 6, 1, 3], 0, 6); |
码生艰难,写文不易,给我家猪囤点猫粮了喵~
查看Github有更多内容噢:https://github.com/godbasin
更欢迎来被删的前端游乐场边撸猫边学前端噢
如果你想要关注日常生活中的我,欢迎关注“牧羊的猪”公众号噢