I am trying to implement TimSort in Swift. I have referred to both these links : This and this The code which I have converted to Swift is :
import UIKit
class ViewController: UIViewController {
var arr : [Int] = []
let run : Int = 5
override func viewDidLoad() {
super.viewDidLoad()
for _ in 0..<10 {
arr.append(Int(arc4random_uniform(100)))
}
timSort()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func insertionSort(_ array:[Int]) -> [Int] {
var a = array
for x in 1..<a.count {
var y = x
while y > 0 && a[y] < a[y - 1] {
a.swapAt(y - 1, y)
y -= 1
}
}
return a
}
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])
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 timSort() {
print("Unsorted : \(arr)")
for i in stride(from: 0, to: arr.count, by: run) {
print("i : \(min((i + run),(arr.count)))")
arr.replaceSubrange(i..<min((i + run),(arr.count)), with: insertionSort(Array(arr[i..<min((i + run),(arr.count))])))
}
print("after insertion sort \(arr)")
var runCount = run
while runCount < arr.count{
for x in stride(from: 0, to: arr.count, by: 2 * runCount) {
print("x : \(x) runcount \(runCount) calc : \(x + 2 * runCount)")
arr.replaceSubrange(x..<min((x + 2 * runCount),(arr.count)), with: merge(leftPile: Array(arr[x..<(x + runCount)]), rightPile: Array(arr[(x + runCount)..<min((x + 2 * runCount),(arr.count))])))
}
runCount = runCount * 2
}
print("Sorted : \(arr)")
}
}
The issue that I am facing is that when I execute code in both the links, it works with any run value (like run = 7
), but the same isn't happening in my code.
My code only works properly when run = 5
and arr.count = 10
. In all other cases, it crashes on arr.replaceSubrange(x..<min((x + 2 * runCount),(arr.count)), with: merge(leftPile: Array(arr[x..<(x + runCount)]), rightPile: Array(arr[(x + runCount)..<min((x + 2 * runCount),(arr.count))])))
this line.
I have tried various ways out but not able to get the issue. Please could someone help me point it out.
You need a few more min
checks. In your last while
loop, x + runCount
can exceed arr.count
, so x + runCount
needs to be replaced with min(x + runCount, arr.count)
. With those added min
checks, the code now runs for various sizes of run
and arr.count
:
func timSort() {
print("Unsorted : \(arr)")
for i in stride(from: 0, to: arr.count, by: run) {
print("i : \(min((i + run),(arr.count)))")
arr.replaceSubrange(i..<min((i + run),(arr.count)), with: insertionSort(Array(arr[i..<min((i + run),(arr.count))])))
}
print("after insertion sort \(arr)")
var runCount = run
while runCount < arr.count{
for x in stride(from: 0, to: arr.count, by: 2 * runCount) {
print("x : \(x) runcount \(runCount) calc : \(x + 2 * runCount)")
arr.replaceSubrange(x..<min(x + 2 * runCount, arr.count), with: merge(leftPile: Array(arr[x..<min(x + runCount, arr.count)]), rightPile: Array(arr[min(x + runCount, arr.count)..<min(x + 2 * runCount, arr.count)])))
}
runCount = runCount * 2
}
print("Sorted : \(arr)")
}