为什么编程语言(例如Swift)不使用最快的可用排序-存储桶排序?

时间:2019-05-12 05:10:44

标签: swift performance sorting optimization programming-languages

Swift的sort()基准,与存储桶排序相比,它是timsort:

项目数| Swift的sort()|桶分类|区别:

  • 10,000 | 0.0403秒| 0.0058秒| x6.9
  • 100,000 | 0.494秒| 0.059秒| x8.4
  • 1,000,000 | 6.2秒| 0.68秒| x9.1
  • 10,000,000 | 42秒8.2秒| x5.1
  • 100,000,000 | 506秒| 94秒x5.4

计算机:iMac Pro(2017),3.2 GHz Intel XeonW。这些值适用于硬编码的self.max()。提供的代码工作时间更长。

为什么编程语言(包括Swift)不使用更快的存储桶排序?

import Foundation

extension Array where Element == Int {
    mutating func sort() {
        guard count > 0 else {
            return
        }
        var count = [Element:Int]()
        for item in self {
            if count[item] != nil {
                count[item] = count[item]! + 1
            } else {
                count[item] = 1
            }
        }
        let n = self.max()!
        self = []
        for value in 0..<n {
            if let count = count[value] {
                for _ in 0..<count {
                    self.append(value)
                }
            }
        }
    }
}

func sort(n: Int) {
    var array = [Int]()
    for _ in 0..<n {
        let newItem = Int.random(in: 0..<n)
        array.append(newItem)
    }
    let start = CFAbsoluteTimeGetCurrent()
    array.sort()
    let end = CFAbsoluteTimeGetCurrent()
    print("Time: \(end - start)")
}

sort(n: 1000000)

P.S。内存消耗几乎相同。

更新

以下代码适用于任何类型,但速度较慢。但是它仍然比Swift中的sort()方法的当前实现好一点。因此,该主题仅适用于对整数排序。

项目数| Swift的sort()|桶分类|区别:

  • 10,000 | 0.0403秒| 0.0405秒| x1
  • 100,000 | 0.494秒| 0.48秒| x1
  • 1,000,000 | 6.2秒| 3.6秒x1.7
  • 10,000,000 | 42秒43秒x1
  • 100,000,000 | 506秒|尚未测试| 〜x1

计算机:iMac Pro(2017),3.2 GHz Intel Xeon W

import Foundation

extension Array where Element: Comparable & Hashable {
    mutating func sort() {
        var count = [Element:Int]()
        for item in self {
            if count[item] != nil {
                count[item] = count[item]! + 1
            } else {
                count[item] = 1
            }
        }
        self = []
        let keys = count.keys.sorted()
        for value in keys {
            if let count = count[value] {
                for _ in 0..<count {
                    self.append(value)
                }
            }
        }
    }
}

func sort(n: Int) {
    var array = [Int]()
    for _ in 0..<n {
        let newItem = Int.random(in: 0..<n)
        array.append(newItem)
    }
    let start = CFAbsoluteTimeGetCurrent()
    array.sort()
    let end = CFAbsoluteTimeGetCurrent()
    print("Time: \(end - start)")
}

sort(n: 1000000)

2 个答案:

答案 0 :(得分:2)

周围没有“最快的排序”,它取决于数据。

例如,对于已被排序最快的数据,则为气泡排序:您什么也不动,仅在读取输入后便知道已完成。即使对于几乎已排序的数据,在某些情况下,气泡排序算法的变化(足够令人惊讶)也是非常合理的选择(例如,基于链接列表的扫描线渲染器,其中许多x值会从一条扫描线中进行少量更新)到下一个)。

在某些情况下,桶排序是一个很好的选择,但前提是密钥很小,或者可以将其分成不太多的小块(并非总是如此)。

快速排序和变体使用随机来避免最坏的情况,并且仅在键之间使用小于比(总是可用)。如果对数据了解不多,并且适合快速随机存取存储器,那么这是一个很好的默认选择。

根据情况,您可能想要最小化比较,或者可能想要最小化交换。不是同一回事。

如果数据太大而无法快速存储,并且整个集合上的随机访问都存在问题,那么合并排序可能是一个不错的选择。

...

换句话说,这取决于:-)

根据我的经验,仅对小整数数组进行排序的测试用例不是很常见。

答案 1 :(得分:-1)

正确的答案是:

  1. 只有整数可以观察到更好的性能;
  2. 提供的代码仅适用于不超过100,000,000的整数-更改此参数会降低性能。

通用代码(请参阅“更新”部分)具有几乎相同的性能。