Go语言实现快速排序(QuickSort)
快速排序(QuickSort) 作为最流行的排序算法之一,又有非常出色的性能,被广大的编程语言作为标准库默认排序方法。
快速排序的设计思想是一个很好的分治法(divide-and-conquer) 的实例,理解他的实现原理将有助于我们在实际生产过程中设计自己的解决问题的算法。最直接的,很多算法题目需要使用到类似的思想。
先贴代码(Go):
func quickSort(nums []int, l, r int) { //[l,r]
if l < r {
m := partition(nums, l, r)
quickSort(nums, l, m-1)
quickSort(nums, m+1, r)
}
}func partition(nums []int, l int, r int) int {
key := nums[r]
//all in [l,i) < key
//all in [i,j] > key
i := l
j := l
for j < r {
if nums[j] < key {
nums[i], nums[j] = nums[j], nums[i]
i++
}
j++
}
nums[i], nums[r] = nums[r], nums[i]
return i
}
首先我们先大致介绍一下分治法。很多有用的算法在结构是递归的,为了解决给定的问题,他们多次递归的调用自己去解决一个相关的子问题。这些算法通常遵循分治法,即他们将原问题划分为多个规模更小且与原问题相似的子问题,然后递归的解决子问题,最后合并子问题的答案得到原问题的答案。
分治法在每一次递归阶段都分为三个步骤:
- 划分: 将问题划分为一系列规模更小的相似子问题。
- 处理: 递归的解决子问题,如果子问题的规模足够的小,则直接解决它。
- 合并: 将各个子问题的答案合并为原文题的答案。
其中在处理过程中,如果子问题规模大到需要递归处理,则我们称它为递归实例(recursive case),如果子问题规模足够的小,递归“到达了最低点”,则我们称它为基础实例(base case)。有时,除了解决相似问题的较小规模的子问题外,我们还必须解决与原问题不太相同的子问题。我们一般将解决此类子问题作为合并步骤的一部分。
nums[p..r]
:- 划分: 将数组
nums[l..r]
划分为两个子数组nums[l..m-1]
和nums[m+1..r]
,使得nums[l..m-1]
的每个元素小于或等于nums[m]
,nums[m+1..r]
的每个元素大于或等于nums[m]
。 计算索引m
的值是此划分过程的一部分。 - 处理: 递归调用快速排序算法,排序两个子数组
nums[l..m-1]
和nums[m+1..r]
。 - 合并: 因为子数组已经排序,所以不需要将它们合并起来,整个数组
nums
现在已排好序。
在待划分的数组
nums[l..r]
中,维护三个范围状态。- 数组
[l,i)
范围的所有元素小于key
- 数组
[l,i)
范围的所有元素大于等于key
初始:
i,j
都为l
,则数组范围[l,i)
和[l,i)
均无元素,不变量成立。保持: 在迭代过程中,按照
nums[j]
的值分为两种处理情况:- 若
nums[j]
小于key
,交换nums[i]
和nums[j]
,同时i
后移,j
后移,不变量成立。 - 若
nums[j]
大于等于key
,j
后移,不变量成立。
j == r
时,循环终止。此时不变量成立。之后交换nums[i]
(当前数组位置中第一个大于等于 key
的值)和 nums[r]
,使得原nums[r]
的值key
放入正确位置。同时i
即是正确位置的值的数组索引号。因此,在经过以上的处理后,遵循分治法的三个步骤处理,最终数组是升序的。
快速排序是高效的排序方法,平均时间复杂度为
O(nlogn)
,且处理阶段不需要额外的存储空间(原址排序)。【Go语言实现快速排序(QuickSort)】为了保证快速排序的性能,通常我们可以增加一个随机抽样的处理过程,即随机选择数组中的一个值作为
key
值,具体原理可以参考《算法导论》。推荐阅读
- System Center 2012 - App Controller 安装语言包
- Android UI设计与开发使用ViewPager实现欢迎引导页面
- element动态路由面包屑的实现示例
- 实现vue图片缩放方式-拖拽组件
- 如何从Zip文件中删除密码(详细实现介绍)
- 火山引擎|火山引擎 MARS X 今日头条 | 大型App高效协同开发,实现研发流程自动化
- 共读《redis设计与实现》-单机
- 最新在实际应用中实现的12大数据结构算法合集介绍
- Amazing!巧用|Amazing!巧用 CSS 视差实现酷炫交互动效
- 如何在Selenium中等待页面加载(三种实现方式介绍)