中心思想

分治

问题描述

对数组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")
}

【补】Swift使用filter实现

func qsort(var array: [Int]) -> [Int] {
        if array.isEmpty { return [] }
        let pivot = array.removeAtIndex(0)
        let lesser = array.filter { $0 < pivot }
        let greater = array.filter { $0 >= pivot }
        return qsort(lesser) + [pivot] + qsort(greater)
    }

Cruise_Chan
729 声望71 粉丝

技能树点歪了...咋办