携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情 。如果哪里写的不对,请大家评论批评。
希望往后的日子,可以每天坚持一个算法,最近发现一个有意思的事情,LeetCode
中等难度的题,也不简单,暴力算法固然能解决问题,但是从时间复杂度和空间复杂度上肯定达不到要求。
今天发现一个不是LeetCode
上的题目在CodeTop
的小程序上涨的很快,仔细一看居然是快排,难道现在对于排序都这么热衷了吗?
快速排序
题目
使用快速排序对数组排序
分析
- 取任意值(通常是数组第一位)作为关键数据,讲数组中比它小的值放在左边,比它大的值放在右面
- 第一轮直接就分成了两个部分,关键数据左边和右边
- 然后依照葫芦画瓢,把左右两边看做两个数组,进行循环迭代
- 直到左右两边数组没有值了。
- 整体思路这样。其实就是一个递归的方式,进行二分排序。
伪代码解析
- 设置关键数据key = A[0],设置两个变量i、j,排序开始的时候:i=1,j=list.count-1
- 从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]的值交换
- 从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]的值交换
- 重复第2、3步,直到i==j;
图解
-
假设一开始序列[8,2,7,9,10,15,9,17],设定
key=8
,i=0
,j=list.count - 1
-
此时,记录
key=8
,此时的i=8
,j=17
,从后往前找,j第一个17>8
,因此j--
继续比较,直到j=7
,然后把j的值赋值给i的位置,然后轮到i和key进行比较,此时2<8
因此不变,此时j--
,不满足i < j
的条件当前循环停止,把key保存的值赋值给i.....实际上就是完成三个数据的交换。快速排序.drawio (3).png -
此时,把整个数组按照i的位置分割成了两个数组,一部分是[0...i-1]另一部分是[i+1...count-1]
-
左边部分按照
2
的思路很快就可以得出结果,右边部分因为9已经最小值,j--
到最后也不能完成交换 -
下面几乎都是右半部分的排序了,因为9最小,所以还是只有右半部分的数组
-
还是步骤
2
的方式,j--
到9的位置,比key=10
小,于是a[i] = a[j]
-
之后
i++
,此时15 > 10
,于是a[j] = a[i]
,此时j--
不满足i < j
的条件,停止循环 -
最后把key的值
a[i] = key
代码
func quickSort(a: inout [Int], low: Int, high: Int) {
if low >= high { // 递归结束条件
return
}
var i = low
var j = high
let key = a[i]
while i < j {
// 从右边开始比较,比key大的数位置不变
while i < j && a[j] >= key {
j -= 1
}
// 只要出现一个比key小的数,将这个数放入左边i的位置
a[i] = a[j]
// 从左边开始比较,比key小的数位置不变
while i < j && a[i] <= key {
i += 1
}
// 只要出现一个比key大的数,将这个数放入右边j的位置
a[j] = a[i]
}
a[i] = key // 将key放入i的位置,则左侧数都比key小,右侧数都比key大
quickSort(a: &a, low: low, high: i - 1) // 左递归
quickSort(a: &a, low: i + 1, high: high) // 右递归
}
// 示例
var m = [2,7,9,10,15,9,17]
quickSort(a: &m, low: 0, high: m.count - 1)
print(m)