|  | 
|  | 1 | +//: Playground - noun: a place where people can play | 
|  | 2 | + | 
|  | 3 | +import Foundation | 
|  | 4 | + | 
|  | 5 | + | 
|  | 6 | +// *** Simple but inefficient version of quicksort *** | 
|  | 7 | + | 
|  | 8 | +func quicksort<T: Comparable>(a: [T]) -> [T] { | 
|  | 9 | +  if a.count <= 1 { | 
|  | 10 | +    return a | 
|  | 11 | +  } else { | 
|  | 12 | +    let pivot = a[a.count/2] | 
|  | 13 | +    let less = a.filter { $0 < pivot } | 
|  | 14 | +    let equal = a.filter { $0 == pivot } | 
|  | 15 | +    let greater = a.filter { $0 > pivot } | 
|  | 16 | +     | 
|  | 17 | +    // Uncomment this following line to see in detail what the  | 
|  | 18 | +    // pivot is in each step and how the subarrays are partitioned. | 
|  | 19 | +    //print(pivot, less, equal, greater) | 
|  | 20 | +     | 
|  | 21 | +    return quicksort(less) + equal + quicksort(greater) | 
|  | 22 | +  } | 
|  | 23 | +} | 
|  | 24 | + | 
|  | 25 | +let list1 = [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ] | 
|  | 26 | +quicksort(list1) | 
|  | 27 | + | 
|  | 28 | + | 
|  | 29 | + | 
|  | 30 | +// *** Using Lomuto partitioning *** | 
|  | 31 | + | 
|  | 32 | +/* | 
|  | 33 | +  Lomuto's partitioning algorithm. | 
|  | 34 | + | 
|  | 35 | +  The return value is the index of the pivot element in the new array. The left | 
|  | 36 | +  partition is [low...p-1]; the right partition is [p+1...high], where p is the | 
|  | 37 | +  return value. | 
|  | 38 | +*/ | 
|  | 39 | +func partitionLomuto<T: Comparable>(inout a: [T], low: Int, high: Int) -> Int { | 
|  | 40 | +  let pivot = a[high] | 
|  | 41 | +   | 
|  | 42 | +  var i = low | 
|  | 43 | +  for j in low..<high { | 
|  | 44 | +    if a[j] <= pivot { | 
|  | 45 | +      (a[i], a[j]) = (a[j], a[i]) | 
|  | 46 | +      i += 1 | 
|  | 47 | +    } | 
|  | 48 | +  } | 
|  | 49 | +   | 
|  | 50 | +  (a[i], a[high]) = (a[high], a[i]) | 
|  | 51 | +  return i | 
|  | 52 | +} | 
|  | 53 | + | 
|  | 54 | +var list2 = [ 10, 0, 3, 9, 2, 14, 26, 27, 1, 5, 8, -1, 8 ] | 
|  | 55 | +partitionLomuto(&list2, low: 0, high: list2.count - 1) | 
|  | 56 | +list2 | 
|  | 57 | + | 
|  | 58 | +func quicksortLomuto<T: Comparable>(inout a: [T], low: Int, high: Int) { | 
|  | 59 | +  if low < high { | 
|  | 60 | +    let p = partitionLomuto(&a, low: low, high: high) | 
|  | 61 | +    quicksortLomuto(&a, low: low, high: p - 1) | 
|  | 62 | +    quicksortLomuto(&a, low: p + 1, high: high) | 
|  | 63 | +  } | 
|  | 64 | +} | 
|  | 65 | + | 
|  | 66 | +quicksortLomuto(&list2, low: 0, high: list2.count - 1) | 
|  | 67 | + | 
|  | 68 | + | 
|  | 69 | + | 
|  | 70 | +// *** Hoare partitioning *** | 
|  | 71 | + | 
|  | 72 | +/* | 
|  | 73 | +  Hoare's partitioning scheme. | 
|  | 74 | + | 
|  | 75 | +  The return value is NOT necessarily the index of the pivot element in the | 
|  | 76 | +  new array. Instead, the array is partitioned into [low...p] and [p+1...high], | 
|  | 77 | +  where p is the return value. The pivot value is placed somewhere inside one | 
|  | 78 | +  of the two partitions, but the algorithm doesn't tell you which one or where. | 
|  | 79 | +*/ | 
|  | 80 | +func partitionHoare<T: Comparable>(inout a: [T], low: Int, high: Int) -> Int { | 
|  | 81 | +  let pivot = a[low] | 
|  | 82 | +  var i = low - 1 | 
|  | 83 | +  var j = high + 1 | 
|  | 84 | +   | 
|  | 85 | +  while true { | 
|  | 86 | +    repeat { j -= 1 } while a[j] > pivot | 
|  | 87 | +    repeat { i += 1 } while a[i] < pivot | 
|  | 88 | +     | 
|  | 89 | +    if i < j { | 
|  | 90 | +      swap(&a[i], &a[j]) | 
|  | 91 | +    } else { | 
|  | 92 | +      return j | 
|  | 93 | +    } | 
|  | 94 | +  } | 
|  | 95 | +} | 
|  | 96 | + | 
|  | 97 | +var list3 = [ 8, 0, 3, 9, 2, 14, 10, 27, 1, 5, 8, -1, 26 ] | 
|  | 98 | +partitionHoare(&list3, low: 0, high: list3.count - 1) | 
|  | 99 | +list3 | 
|  | 100 | + | 
|  | 101 | +func quicksortHoare<T: Comparable>(inout a: [T], low: Int, high: Int) { | 
|  | 102 | +  if low < high { | 
|  | 103 | +    let p = partitionHoare(&a, low: low, high: high) | 
|  | 104 | +    quicksortHoare(&a, low: low, high: p) | 
|  | 105 | +    quicksortHoare(&a, low: p + 1, high: high) | 
|  | 106 | +  } | 
|  | 107 | +} | 
|  | 108 | + | 
|  | 109 | +quicksortHoare(&list3, low: 0, high: list3.count - 1) | 
|  | 110 | + | 
|  | 111 | + | 
|  | 112 | + | 
|  | 113 | +// *** Randomized sorting *** | 
|  | 114 | + | 
|  | 115 | +/* Returns a random integer in the range min...max, inclusive. */ | 
|  | 116 | +public func random(min min: Int, max: Int) -> Int { | 
|  | 117 | +  assert(min < max) | 
|  | 118 | +  return min + Int(arc4random_uniform(UInt32(max - min + 1))) | 
|  | 119 | +} | 
|  | 120 | + | 
|  | 121 | +func quicksortRandom<T: Comparable>(inout a: [T], low: Int, high: Int) { | 
|  | 122 | +  if low < high { | 
|  | 123 | +    let pivotIndex = random(min: low, max: high) | 
|  | 124 | +    (a[pivotIndex], a[high]) = (a[high], a[pivotIndex]) | 
|  | 125 | +     | 
|  | 126 | +    let p = partitionLomuto(&a, low: low, high: high) | 
|  | 127 | +    quicksortRandom(&a, low: low, high: p - 1) | 
|  | 128 | +    quicksortRandom(&a, low: p + 1, high: high) | 
|  | 129 | +  } | 
|  | 130 | +} | 
|  | 131 | + | 
|  | 132 | +var list4 = [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ] | 
|  | 133 | +quicksortRandom(&list4, low: 0, high: list4.count - 1) | 
|  | 134 | +list4 | 
|  | 135 | + | 
|  | 136 | + | 
|  | 137 | + | 
|  | 138 | +// *** Dutch national flag partioning *** | 
|  | 139 | + | 
|  | 140 | +/* | 
|  | 141 | +  Swift's swap() doesn't like it if the items you're trying to swap refer to | 
|  | 142 | +  the same memory location. This little wrapper simply ignores such swaps. | 
|  | 143 | +*/ | 
|  | 144 | +public func swap<T>(inout a: [T], _ i: Int, _ j: Int) { | 
|  | 145 | +  if i != j { | 
|  | 146 | +    swap(&a[i], &a[j]) | 
|  | 147 | +  } | 
|  | 148 | +} | 
|  | 149 | + | 
|  | 150 | +/* | 
|  | 151 | +  Dutch national flag partitioning. | 
|  | 152 | +  Returns a tuple with the start and end index of the middle area. | 
|  | 153 | +*/ | 
|  | 154 | +func partitionDutchFlag<T: Comparable>(inout a: [T], low: Int, high: Int, pivotIndex: Int) -> (Int, Int) { | 
|  | 155 | +  let pivot = a[pivotIndex] | 
|  | 156 | +   | 
|  | 157 | +  var smaller = low | 
|  | 158 | +  var equal = low | 
|  | 159 | +  var larger = high | 
|  | 160 | +   | 
|  | 161 | +  while equal <= larger { | 
|  | 162 | +    if a[equal] < pivot { | 
|  | 163 | +      swap(&a, smaller, equal) | 
|  | 164 | +      smaller += 1 | 
|  | 165 | +      equal += 1 | 
|  | 166 | +    } else if a[equal] == pivot { | 
|  | 167 | +      equal += 1 | 
|  | 168 | +    } else { | 
|  | 169 | +      swap(&a, equal, larger) | 
|  | 170 | +      larger -= 1 | 
|  | 171 | +    } | 
|  | 172 | +  } | 
|  | 173 | +  return (smaller, larger) | 
|  | 174 | +} | 
|  | 175 | + | 
|  | 176 | +var list5 = [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ] | 
|  | 177 | +partitionDutchFlag(&list5, low: 0, high: list5.count - 1, pivotIndex: 10) | 
|  | 178 | +list5 | 
|  | 179 | + | 
|  | 180 | +func quicksortDutchFlag<T: Comparable>(inout a: [T], low: Int, high: Int) { | 
|  | 181 | +  if low < high { | 
|  | 182 | +    let pivotIndex = random(min: low, max: high) | 
|  | 183 | +    let (p, q) = partitionDutchFlag(&a, low: low, high: high, pivotIndex: pivotIndex) | 
|  | 184 | +    quicksortDutchFlag(&a, low: low, high: p - 1) | 
|  | 185 | +    quicksortDutchFlag(&a, low: q + 1, high: high) | 
|  | 186 | +  } | 
|  | 187 | +} | 
|  | 188 | + | 
|  | 189 | +quicksortDutchFlag(&list5, low: 0, high: list5.count - 1) | 
0 commit comments