使用合并排序计算Inversions,Swift

时间:2016-10-18 07:02:11

标签: swift sorting merge counting

我有使用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($0)}
        mergeSort(numbers)




        return numbers
    } catch {
        return [Int]()
    }
}
ready(fileName: "IntegerArray"))
print(count)

3 个答案:

答案 0 :(得分:1)

如果有人在这里试图找到基于合并排序的Count Inversion 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))")

答案 1 :(得分:0)

我认为您的实施有一些事情可以解决问题。我在游乐场重建了你的项目,并将你的代码与下面的代码进行了比较,我认为这是实现算法的一种更“经典”的方式:

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个随机数的数组上执行。你的算法运行代码的“比较”部分(即“如果leftPile [index]&lt; rightPile [index] ...”)每堆几乎8000次,然后运行代码来处理剩余代码(即为每一堆开始“while leftIndex&lt; leftPile.count ...”)超过1000次。上述实现对比较测试运行500次,然后处理任何残余元素4次。

你可以为更大的阵列运行它,让我知道它是否有帮助?

答案 2 :(得分:0)

确定。解决了。不要使用游乐场来运行它。打开一个x-code项目 这需要大约1秒钟。