快排:Swift实现

中心思想

分治

问题描述

对数组A[p..r]进行排序,让排序后的数组非递减。

问题思路

分治三步曲

分解(divide)

将数组A[p..r]分割成子数组A[p..q-1]与A[q+1..r],满足A[p..q-1]中的元素都不大于A[q]且A[q+1..r]中的元素都不小于A[q]。(标兵q的选择后续在讨论)

解决(conquer)

通过无脑递归调用快排,对子数组A[p..q-1]与A[q+1..r]进行排序。

这里递归终止的条件为子数组只有一个元素,反之继续递归的条件为 p < r

伪代码如下:

QUICKSORT(A, p, r)
if p < r
    q = PARTITION(A, p, r)
    QUICKSORT(A, p, q-1)
    QUICKSORT(A, q+1, r)

这里有个标兵q的选择问题,也就是数组划分问题,PARTITON函数实现了这一过程,伪代码如下:

PARTITION(A, p, r)
x = A[r]
i = p - 1
for j = p to r - 1
    if A[j] <= x
        i = i + 1
        exchange A[i] with A[j]
exchange A[i+1] with A[r]
return i + 1

PARTITION函数是有技巧的,我们可以这么想B,C就是我们想要的那两个数组,最开始为“空”(i,j值为p-1与p),那么只要遍历元素组一轮,将对应的元素丢到B,C最后通过q粘合到一起就可以得到我们快排一次后的数组A`,在没有辅助空间的情况下就需要我们对元素做交换操作以及用不同数组下标i,j做子数组区分,其中索引p到索引i为子数组B索引i到索引j为子数组C

起初子数组B的索引为-1(空数组),C的索引为0(含有首位置元素的子数组),即A数组第一个元素,从A数组使用j开始遍历,

当遇到得元素k <= q的时候也就是相当于B数组增加了一个成员,此时B数组要扩容相当于索引i要+1,并且因为扩容后在没有进行元素搬动之前,当前i的索引值为C子数组的成员,所以要当前的索引j进行元素交换。

遍历一轮以后最后将A[i+1]与A[r]进行交换完成一轮快排。PARTITON的时间复杂度为Θ(n)

合并(combine)

原址操作无需合并 略

Swift实现

func exchangeTwoValue(inout val1: Int, inout val2: Int) {
    val1 = val1 + val2
    val2 = val1 - val2
    val1 = val1 - val2
}

func partitonforlast(inout targetArray: [Int], startIndex: Int, tailIndex: Int) -> Int {
    var satelliteValue = targetArray[tailIndex]
    var i = startIndex - 1
    for var j = startIndex; j < tailIndex; j++ {
        if targetArray[j] <= satelliteValue {
            i++
            exchangeTwoValue(&targetArray[i], &targetArray[j])
        }
    }

    exchangeTwoValue(&targetArray[i+1], &targetArray[tailIndex])
    return i + 1
}

func quicksort(inout targetArray: [Int], startIndex: Int, tailIndex: Int) {
    if startIndex < tailIndex {
        var satelliteIndex = partitonforlast(&targetArray, startIndex, tailIndex)
        quicksort(&targetArray, startIndex, satelliteIndex-1)
        quicksort(&targetArray, satelliteIndex+1, tailIndex)
    }
}


// TEST CASE

var testArray :[Int] = [2, 8, 7, 1, 3, 5, 6, 4]
quicksort(&testArray, 0, testArray.count-1)

for item in testArray {
    print("\(item)\t")
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值