diff --git a/Assignments/Sorting/ShellSort.playground/Pages/Shell Sort.xcplaygroundpage/Contents.swift b/Assignments/Sorting/ShellSort.playground/Pages/Shell Sort.xcplaygroundpage/Contents.swift index 5161e34..3fc64dd 100644 --- a/Assignments/Sorting/ShellSort.playground/Pages/Shell Sort.xcplaygroundpage/Contents.swift +++ b/Assignments/Sorting/ShellSort.playground/Pages/Shell Sort.xcplaygroundpage/Contents.swift @@ -16,22 +16,21 @@ class ShellSequence: SequenceType { } func generate() -> AnyGenerator { - // YOUR CODE + var m = n return anyGenerator { - // YOUR CODE - - nil + m = m/2 + return m >= 1 ? m : nil } } } //: Test your code with assert. Make sure asserts don't raise any errors. -//assert(Array(ShellSequence(n: 20)) == [10, 5, 2, 1]) -//assert(Array(ShellSequence(n: 9)) == [4, 2, 1]) -//assert(Array(ShellSequence(n: 2)) == [1]) -//assert(Array(ShellSequence(n: 1)) == []) +assert(Array(ShellSequence(n: 20)) == [10, 5, 2, 1]) +assert(Array(ShellSequence(n: 9)) == [4, 2, 1]) +assert(Array(ShellSequence(n: 2)) == [1]) +assert(Array(ShellSequence(n: 1)) == []) /*: @@ -50,15 +49,25 @@ class KnuthSequence: SequenceType { } func generate() -> AnyGenerator { + var gaps = [Int]() + for i in 1...n/3 { + let x = (Int(pow(3.0, Double(i))) - 1) / 2 + guard x < n else { break } + gaps.append(x) + } + + gaps.sortInPlace(>) + var g = gaps.generate() return anyGenerator { - nil + return g.next() } } } -//assert(Array(KnuthSequence(n: 200)) == [121, 40, 13, 4, 1]) -//assert(Array(KnuthSequence(n: 10)) == [4, 1]) +assert(Array(KnuthSequence(n: 200)) == [121, 40, 13, 4, 1]) +assert(Array(KnuthSequence(n: 10)) == [4, 1]) +assert(Array(KnuthSequence(n: 4)) == [1]) /*: @@ -69,8 +78,33 @@ Write a shell sort by using one of the generators you created above. Knuth's gap */ func shellSort(var array: [T], isOrderedBefore: (T, T) -> Bool) -> [T] { + guard array.count > 1 else { return array } - for i in KnuthSequence(n: array.count) { + for gap in KnuthSequence(n: array.count) { + print("gap \(gap)") + + // Create a sub array of this gap's items + var subArray = [T]() + for i in 0.stride(to: array.count, by: gap) { + subArray.append(array[i]) + } + + // Sort that sub array using insertion sort + for i in 1.. 0 && isOrderedBefore(currentItem, subArray[j-1]) { + subArray[j] = subArray[j-1] + j-- + } + subArray[j] = currentItem + } + + // Update the original array with the sorted subArray's values + var g = subArray.generate() + for i in 0.stride(to: array.count, by: gap) { + array[i] = g.next()! + } } @@ -79,14 +113,20 @@ func shellSort(var array: [T], isOrderedBefore: (T, T) -> Bool) -> [T] { let items = ["c", "d", "b", "a"] let sortedItems = shellSort(items, isOrderedBefore: <) -//assert(sortedItems.isSorted()) +assert(sortedItems.isSorted()) assert(items == ["c", "d", "b", "a"]) // double check that items does not change +let charArray = Array("A whole lot of text to sort so we get more than a few gaps. Also: Lorem Ipsum, or something.".characters) +charArray.count +let sortedCharArray = shellSort(charArray, isOrderedBefore: <) +assert(sortedCharArray.isSorted()) +assert(sortedCharArray.count == charArray.count) assert(shellSort([Int](), isOrderedBefore: <).isSorted()) assert(shellSort([1], isOrderedBefore: <).isSorted()) assert(shellSort([1, 2, 3], isOrderedBefore: <).isSorted()) -//assert(shellSort([1, 2, 3], isOrderedBefore: >).isSorted(>)) -//assert(shellSort([3, 0, 2, 1, 2, -1], isOrderedBefore: <).isSorted()) +assert(shellSort([1, 2, 3], isOrderedBefore: >).isSorted(>)) +assert(shellSort([3, 0, 2, 1, 2, -1], isOrderedBefore: <).isSorted()) +assert(shellSort([3, 10, 23, 25, 1235, 234, 980, -3245, 0, 10, 89, 2, 200, 1, 100298, 2, 253, -983, 1039, -1], isOrderedBefore: <).isSorted())