如何快速对Array <t>中的子元素范围进行就地排序?

时间:2018-12-22 21:56:37

标签: swift sorting copy-on-write

用于Array类型的标准排序方法没有变体,可以在变体中缩小要排序的数组区域。由于写时复制语义,使用ArraySlice不会导致对原始数据进行排序。

我是否必须编写新的排序实现以在Array的子​​范围上实现就地排序?还是有一种丑陋的方式来创建第二个数组作为别名,从而从原始数组中别名出所需的元素范围?

3 个答案:

答案 0 :(得分:1)

subscript operation that takes a range返回一个可变值。如果直接在其上调用一个变异方法,它将改变原始数组的位置:

var numbers = [3,5,2,4,1]
numbers[1..<4].sort()
print(numbers) // [3, 2, 4, 5, 1]

从Swift 4.2开始,我认为,这比制作切片的临时副本要有效(来源:forum post 1forum post 2。这些文章讨论了所有各种切片操作,包括更改源集合长度的切片操作,但就地排序应该相同。)

即将推出的Swift 5发行版进行了许多底层更改,目的是提高效率(背景:ownership manifesto)。在Swift 5中,可以将设置程序(如变异下标)建模为协程,这将允许就地执行这种操作。但是我不确定100%是否会在Swift 5.0中出现。

答案 1 :(得分:0)

很难看清您的问题所在:

var arr = [9,8,7,6,5,4,3,2,1]
let range = 4...7
arr.replaceSubrange(range, with: arr[range].sorted())
print(arr) // [9, 8, 7, 6, 2, 3, 4, 5, 1]

那不是预定目标吗?

答案 2 :(得分:0)

我建议使用自定义的quicksort实现:

// MARK: - Array<Element: Comparable>

extension Array where Element: Comparable {

    // MARK: - Internal

    mutating func quickSort(subrange: Range<Int>) {
        privateQuickSort(left: subrange.lowerBound, right: subrange.upperBound - 1)
    }

    // MARK: - Private

    mutating private func partition(left: Int, right: Int) -> Int {
        var i = left
        for j in (left + 1)..<(right + 1) {
            if self[j] < self[left] {
                i += 1
                (self[i], self[j]) = (self[j], self[i])
            }
        }
        (self[i], self[left]) = (self[left], self[i])
        return i
    }
    mutating private func privateQuickSort(left: Int, right: Int) {
        if right > left {
            let pivotIndex = partition(left: left, right: right)
            privateQuickSort(left: left, right: pivotIndex - 1)
            privateQuickSort(left: pivotIndex + 1, right: right)
        }
    }
}

var array = [10,0,2,1,4,5,6,7,8,3]

array.quickSort(subrange: 0..<array.count)
print(array)
  

[0,1,2,3,4,5,6,7,8,10]

但是

var array = [10,0,2,1,4,5,6,7,8,3]

array.quickSort(subrange: 0..<2)
  

[0,10,2,1,4,4,5,6,7,8,3]

原始的快速排序快速算法source