使用合并排序计算反转,Swift
Counting Inversions with merge sort, Swift
我在使用 Swift 计算倒数时遇到问题。我花了 45 分钟,45 分钟后 Xcode 崩溃了。我从来没有得到答案。你能帮我弄清楚问题是什么吗?因为这个问题只花了人们几秒钟的时间。这些代码有什么问题?顺便说一句,问题是计算数组中的反转(100000 个未排序的整数)
import UIKit
var count: Int = Int()
func mergeSort(_ array: [Int]) -> [Int] {
guard array.count > 1 else { return array }
let middleIndex = array.count / 2
let leftArray = mergeSort(Array(array[0..<middleIndex]))
let rightArray = mergeSort(Array(array[middleIndex..<array.count]))
return merge(leftPile: leftArray, rightPile: rightArray)
}
func merge(leftPile: [Int], rightPile: [Int]) -> [Int] {
var leftIndex = 0
var rightIndex = 0
var orderedPile = [Int]()
while leftIndex < leftPile.count && rightIndex < rightPile.count {
if leftPile[leftIndex] < rightPile[rightIndex] {
orderedPile.append(leftPile[leftIndex])
leftIndex += 1
} else if leftPile[leftIndex] > rightPile[rightIndex] {
orderedPile.append(rightPile[rightIndex])
count += leftPile.count - leftIndex
rightIndex += 1
} else {
orderedPile.append(leftPile[leftIndex])
leftIndex += 1
orderedPile.append(rightPile[rightIndex])
rightIndex += 1
}
}
while leftIndex < leftPile.count {
orderedPile.append(leftPile[leftIndex])
leftIndex += 1
}
while rightIndex < rightPile.count {
orderedPile.append(rightPile[rightIndex])
rightIndex += 1
}
return orderedPile
}
func ready(fileName: String) -> [Int] {
guard let path = Bundle.main.path(forResource: fileName, ofType: "txt") else {
return [Int]()
}
do {
let numbers = try String(contentsOfFile: path).components(separatedBy: "\r\n")
.flatMap {Int([=11=])}
mergeSort(numbers)
return numbers
} catch {
return [Int]()
}
}
ready(fileName: "IntegerArray"))
print(count)
我认为您的实施有一些问题阻碍了进展。我在操场上重建了你的项目,并将你的代码与以下代码进行了比较,我认为这是一种更 "classical" 的算法实现方式:
func mergeAlt(leftPile: [Int], rightPile: [Int]) -> [Int] {
var leftPileCopy = leftPile
var rightPileCopy = rightPile
var orderedPile = [Int]()
while !leftPileCopy.isEmpty && !rightPileCopy.isEmpty {
if leftPileCopy.first! <= rightPileCopy.first! {
orderedPile.append(leftPileCopy.first!)
leftPileCopy.removeFirst()
} else {
orderedPile.append(rightPileCopy.first!)
rightPileCopy.removeFirst()
}
}
// By this stage, only one array will have anything in it
while !leftPileCopy.isEmpty {
orderedPile.append(leftPileCopy.first!)
leftPileCopy.removeFirst()
}
while !rightPileCopy.isEmpty {
orderedPile.append(rightPileCopy.first!)
rightPileCopy.removeFirst()
}
return orderedPile
}
您会注意到这里的主要区别在于此实现比较每个数组中的第一项,然后删除较小的一项,从而逐渐减小数组的大小。我认为您的方法是使用索引跟踪每个数组中的位置,这是导致延迟的原因。
例如,我 运行 在操场上反对你在 1000 运行dom 数字的数组上的实现。你的算法 运行s 代码的 "compare" 部分(即 "if leftPile[index] < rightPile[index]...")每堆几乎 8000 次,然后 运行s 处理剩余代码的代码(即section starting "while leftIndex < leftPile.count...") 每堆超过 1000 次。以上实现运行s 500次用于对比测试然后4次处理任何残留元素
你能运行将这个用于更大的阵列吗?如果有帮助请告诉我?
好的。解决了。不要使用 playground 来 运行 这个。打开一个 x-code 项目
大约需要 1 秒。
以防有人在这里试图找到基于归并排序
的计数倒置Swift 4 版本
import Foundation
func sortAndCount(_ array : [Int]) -> ([Int], Int) {
guard array.count > 1 else {
return (array, 0)
}
let middleIndex = array.count / 2
let (leftArray, leftCount) = sortAndCount(Array(array[0..<middleIndex]))
let (rightArray, rightCount) = sortAndCount(Array(array[middleIndex..<array.count]))
let (finalArray, splitCount) = mergeAndCountSplitInversation(leftArray, rightArray)
return (finalArray, leftCount + rightCount + splitCount)
}
func mergeAndCountSplitInversation(_ leftPile: [Int], _ rightPile: [Int]) -> ([Int], Int) {
var leftIndex = 0
var rightIndex = 0
var orderedPile = [Int]()
var inversationCount = 0
while leftIndex < leftPile.count && rightIndex < rightPile.count {
if leftPile[leftIndex] <= rightPile[rightIndex] {
orderedPile.append(leftPile[leftIndex])
leftIndex += 1
} else {
orderedPile.append(rightPile[rightIndex])
rightIndex += 1
inversationCount = inversationCount + leftPile.count - leftIndex
}
}
while leftIndex < leftPile.count {
orderedPile.append(leftPile[leftIndex])
leftIndex += 1
}
while rightIndex < rightPile.count {
orderedPile.append(rightPile[rightIndex])
rightIndex += 1
}
print("inversion for array - \(orderedPile)")
print("count - \(inversationCount)")
return (orderedPile, inversationCount)
}
func inverstionCountNaive (_ array :[Int]) -> Int {
var inverstionCount = 0
for i in 0..<array.count-1 {
for j in i+1..<array.count {
if array[i] > array[j] {
inverstionCount += 1
}
}
}
return inverstionCount
}
let array = [2, 1, 3, 1, 2]
print("origin - \(array)")
print("sorted - \(sortAndCount(array))")
print("naive approuch count - \(inverstionCountNaive(array))")
我在使用 Swift 计算倒数时遇到问题。我花了 45 分钟,45 分钟后 Xcode 崩溃了。我从来没有得到答案。你能帮我弄清楚问题是什么吗?因为这个问题只花了人们几秒钟的时间。这些代码有什么问题?顺便说一句,问题是计算数组中的反转(100000 个未排序的整数)
import UIKit
var count: Int = Int()
func mergeSort(_ array: [Int]) -> [Int] {
guard array.count > 1 else { return array }
let middleIndex = array.count / 2
let leftArray = mergeSort(Array(array[0..<middleIndex]))
let rightArray = mergeSort(Array(array[middleIndex..<array.count]))
return merge(leftPile: leftArray, rightPile: rightArray)
}
func merge(leftPile: [Int], rightPile: [Int]) -> [Int] {
var leftIndex = 0
var rightIndex = 0
var orderedPile = [Int]()
while leftIndex < leftPile.count && rightIndex < rightPile.count {
if leftPile[leftIndex] < rightPile[rightIndex] {
orderedPile.append(leftPile[leftIndex])
leftIndex += 1
} else if leftPile[leftIndex] > rightPile[rightIndex] {
orderedPile.append(rightPile[rightIndex])
count += leftPile.count - leftIndex
rightIndex += 1
} else {
orderedPile.append(leftPile[leftIndex])
leftIndex += 1
orderedPile.append(rightPile[rightIndex])
rightIndex += 1
}
}
while leftIndex < leftPile.count {
orderedPile.append(leftPile[leftIndex])
leftIndex += 1
}
while rightIndex < rightPile.count {
orderedPile.append(rightPile[rightIndex])
rightIndex += 1
}
return orderedPile
}
func ready(fileName: String) -> [Int] {
guard let path = Bundle.main.path(forResource: fileName, ofType: "txt") else {
return [Int]()
}
do {
let numbers = try String(contentsOfFile: path).components(separatedBy: "\r\n")
.flatMap {Int([=11=])}
mergeSort(numbers)
return numbers
} catch {
return [Int]()
}
}
ready(fileName: "IntegerArray"))
print(count)
我认为您的实施有一些问题阻碍了进展。我在操场上重建了你的项目,并将你的代码与以下代码进行了比较,我认为这是一种更 "classical" 的算法实现方式:
func mergeAlt(leftPile: [Int], rightPile: [Int]) -> [Int] {
var leftPileCopy = leftPile
var rightPileCopy = rightPile
var orderedPile = [Int]()
while !leftPileCopy.isEmpty && !rightPileCopy.isEmpty {
if leftPileCopy.first! <= rightPileCopy.first! {
orderedPile.append(leftPileCopy.first!)
leftPileCopy.removeFirst()
} else {
orderedPile.append(rightPileCopy.first!)
rightPileCopy.removeFirst()
}
}
// By this stage, only one array will have anything in it
while !leftPileCopy.isEmpty {
orderedPile.append(leftPileCopy.first!)
leftPileCopy.removeFirst()
}
while !rightPileCopy.isEmpty {
orderedPile.append(rightPileCopy.first!)
rightPileCopy.removeFirst()
}
return orderedPile
}
您会注意到这里的主要区别在于此实现比较每个数组中的第一项,然后删除较小的一项,从而逐渐减小数组的大小。我认为您的方法是使用索引跟踪每个数组中的位置,这是导致延迟的原因。
例如,我 运行 在操场上反对你在 1000 运行dom 数字的数组上的实现。你的算法 运行s 代码的 "compare" 部分(即 "if leftPile[index] < rightPile[index]...")每堆几乎 8000 次,然后 运行s 处理剩余代码的代码(即section starting "while leftIndex < leftPile.count...") 每堆超过 1000 次。以上实现运行s 500次用于对比测试然后4次处理任何残留元素
你能运行将这个用于更大的阵列吗?如果有帮助请告诉我?
好的。解决了。不要使用 playground 来 运行 这个。打开一个 x-code 项目 大约需要 1 秒。
以防有人在这里试图找到基于归并排序
的计数倒置Swift 4 版本import Foundation
func sortAndCount(_ array : [Int]) -> ([Int], Int) {
guard array.count > 1 else {
return (array, 0)
}
let middleIndex = array.count / 2
let (leftArray, leftCount) = sortAndCount(Array(array[0..<middleIndex]))
let (rightArray, rightCount) = sortAndCount(Array(array[middleIndex..<array.count]))
let (finalArray, splitCount) = mergeAndCountSplitInversation(leftArray, rightArray)
return (finalArray, leftCount + rightCount + splitCount)
}
func mergeAndCountSplitInversation(_ leftPile: [Int], _ rightPile: [Int]) -> ([Int], Int) {
var leftIndex = 0
var rightIndex = 0
var orderedPile = [Int]()
var inversationCount = 0
while leftIndex < leftPile.count && rightIndex < rightPile.count {
if leftPile[leftIndex] <= rightPile[rightIndex] {
orderedPile.append(leftPile[leftIndex])
leftIndex += 1
} else {
orderedPile.append(rightPile[rightIndex])
rightIndex += 1
inversationCount = inversationCount + leftPile.count - leftIndex
}
}
while leftIndex < leftPile.count {
orderedPile.append(leftPile[leftIndex])
leftIndex += 1
}
while rightIndex < rightPile.count {
orderedPile.append(rightPile[rightIndex])
rightIndex += 1
}
print("inversion for array - \(orderedPile)")
print("count - \(inversationCount)")
return (orderedPile, inversationCount)
}
func inverstionCountNaive (_ array :[Int]) -> Int {
var inverstionCount = 0
for i in 0..<array.count-1 {
for j in i+1..<array.count {
if array[i] > array[j] {
inverstionCount += 1
}
}
}
return inverstionCount
}
let array = [2, 1, 3, 1, 2]
print("origin - \(array)")
print("sorted - \(sortAndCount(array))")
print("naive approuch count - \(inverstionCountNaive(array))")