LeetCode.快速排序_图解(Swift)

144 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情 。如果哪里写的不对,请大家评论批评。

希望往后的日子,可以每天坚持一个算法,最近发现一个有意思的事情,LeetCode中等难度的题,也不简单,暴力算法固然能解决问题,但是从时间复杂度和空间复杂度上肯定达不到要求。

今天发现一个不是LeetCode上的题目在CodeTop的小程序上涨的很快,仔细一看居然是快排,难道现在对于排序都这么热衷了吗?

快速排序

题目

使用快速排序对数组排序

分析

  • 取任意值(通常是数组第一位)作为关键数据,讲数组中比它小的值放在左边,比它大的值放在右面
  • 第一轮直接就分成了两个部分,关键数据左边和右边
  • 然后依照葫芦画瓢,把左右两边看做两个数组,进行循环迭代
  • 直到左右两边数组没有值了。
  • 整体思路这样。其实就是一个递归的方式,进行二分排序。

伪代码解析

  1. 设置关键数据key = A[0],设置两个变量i、j,排序开始的时候:i=1,j=list.count-1
  2. 从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]的值交换
  3. 从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]的值交换
  4. 重复第2、3步,直到i==j;

图解

  1. 假设一开始序列[8,2,7,9,10,15,9,17],设定key=8,i=0,j=list.count - 1 快速排序.drawio (2).png

  2. 此时,记录key=8,此时的i=8j=17,从后往前找,j第一个17>8,因此j--继续比较,直到j=7,然后把j的值赋值给i的位置,然后轮到i和key进行比较,此时2<8因此不变,此时j--,不满足i < j的条件当前循环停止,把key保存的值赋值给i.....实际上就是完成三个数据的交换。快速排序.drawio (3).png

  3. 此时,把整个数组按照i的位置分割成了两个数组,一部分是[0...i-1]另一部分是[i+1...count-1]

  4. 左边部分按照2的思路很快就可以得出结果,右边部分因为9已经最小值,j--到最后也不能完成交换快速排序.drawio (4).png

  5. 下面几乎都是右半部分的排序了,因为9最小,所以还是只有右半部分的数组

  6. 还是步骤2的方式,j--到9的位置,比key=10小,于是a[i] = a[j]

  7. 之后i++,此时15 > 10,于是a[j] = a[i],此时j--不满足i < j的条件,停止循环

  8. 最后把key的值a[i] = key

快速排序.drawio (5).png

代码

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)