Skip to content

Commit

Permalink
Add quicksort
Browse files Browse the repository at this point in the history
  • Loading branch information
hollance committed Jan 29, 2016
1 parent e1198f8 commit 404c896
Show file tree
Hide file tree
Showing 8 changed files with 889 additions and 1 deletion.
Binary file added Quicksort/Images/Example.graffle
Binary file not shown.
Binary file added Quicksort/Images/Example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
189 changes: 189 additions & 0 deletions Quicksort/Quicksort.playground/Contents.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
//: Playground - noun: a place where people can play

import Foundation


// *** Simple but inefficient version of quicksort ***

func quicksort<T: Comparable>(a: [T]) -> [T] {
if a.count <= 1 {
return a
} else {
let pivot = a[a.count/2]
let less = a.filter { $0 < pivot }
let equal = a.filter { $0 == pivot }
let greater = a.filter { $0 > pivot }

// Uncomment this following line to see in detail what the
// pivot is in each step and how the subarrays are partitioned.
//print(pivot, less, equal, greater)

return quicksort(less) + equal + quicksort(greater)
}
}

let list1 = [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ]
quicksort(list1)



// *** Using Lomuto partitioning ***

/*
Lomuto's partitioning algorithm.

The return value is the index of the pivot element in the new array. The left
partition is [low...p-1]; the right partition is [p+1...high], where p is the
return value.
*/
func partitionLomuto<T: Comparable>(inout a: [T], low: Int, high: Int) -> Int {
let pivot = a[high]

var i = low
for j in low..<high {
if a[j] <= pivot {
(a[i], a[j]) = (a[j], a[i])
i += 1
}
}

(a[i], a[high]) = (a[high], a[i])
return i
}

var list2 = [ 10, 0, 3, 9, 2, 14, 26, 27, 1, 5, 8, -1, 8 ]
partitionLomuto(&list2, low: 0, high: list2.count - 1)
list2

func quicksortLomuto<T: Comparable>(inout a: [T], low: Int, high: Int) {
if low < high {
let p = partitionLomuto(&a, low: low, high: high)
quicksortLomuto(&a, low: low, high: p - 1)
quicksortLomuto(&a, low: p + 1, high: high)
}
}

quicksortLomuto(&list2, low: 0, high: list2.count - 1)



// *** Hoare partitioning ***

/*
Hoare's partitioning scheme.

The return value is NOT necessarily the index of the pivot element in the
new array. Instead, the array is partitioned into [low...p] and [p+1...high],
where p is the return value. The pivot value is placed somewhere inside one
of the two partitions, but the algorithm doesn't tell you which one or where.
*/
func partitionHoare<T: Comparable>(inout a: [T], low: Int, high: Int) -> Int {
let pivot = a[low]
var i = low - 1
var j = high + 1

while true {
repeat { j -= 1 } while a[j] > pivot
repeat { i += 1 } while a[i] < pivot

if i < j {
swap(&a[i], &a[j])
} else {
return j
}
}
}

var list3 = [ 8, 0, 3, 9, 2, 14, 10, 27, 1, 5, 8, -1, 26 ]
partitionHoare(&list3, low: 0, high: list3.count - 1)
list3

func quicksortHoare<T: Comparable>(inout a: [T], low: Int, high: Int) {
if low < high {
let p = partitionHoare(&a, low: low, high: high)
quicksortHoare(&a, low: low, high: p)
quicksortHoare(&a, low: p + 1, high: high)
}
}

quicksortHoare(&list3, low: 0, high: list3.count - 1)



// *** Randomized sorting ***

/* Returns a random integer in the range min...max, inclusive. */
public func random(min min: Int, max: Int) -> Int {
assert(min < max)
return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}

func quicksortRandom<T: Comparable>(inout a: [T], low: Int, high: Int) {
if low < high {
let pivotIndex = random(min: low, max: high)
(a[pivotIndex], a[high]) = (a[high], a[pivotIndex])

let p = partitionLomuto(&a, low: low, high: high)
quicksortRandom(&a, low: low, high: p - 1)
quicksortRandom(&a, low: p + 1, high: high)
}
}

var list4 = [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ]
quicksortRandom(&list4, low: 0, high: list4.count - 1)
list4



// *** Dutch national flag partioning ***

/*
Swift's swap() doesn't like it if the items you're trying to swap refer to
the same memory location. This little wrapper simply ignores such swaps.
*/
public func swap<T>(inout a: [T], _ i: Int, _ j: Int) {
if i != j {
swap(&a[i], &a[j])
}
}

/*
Dutch national flag partitioning.
Returns a tuple with the start and end index of the middle area.
*/
func partitionDutchFlag<T: Comparable>(inout a: [T], low: Int, high: Int, pivotIndex: Int) -> (Int, Int) {
let pivot = a[pivotIndex]

var smaller = low
var equal = low
var larger = high

while equal <= larger {
if a[equal] < pivot {
swap(&a, smaller, equal)
smaller += 1
equal += 1
} else if a[equal] == pivot {
equal += 1
} else {
swap(&a, equal, larger)
larger -= 1
}
}
return (smaller, larger)
}

var list5 = [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ]
partitionDutchFlag(&list5, low: 0, high: list5.count - 1, pivotIndex: 10)
list5

func quicksortDutchFlag<T: Comparable>(inout a: [T], low: Int, high: Int) {
if low < high {
let pivotIndex = random(min: low, max: high)
let (p, q) = partitionDutchFlag(&a, low: low, high: high, pivotIndex: pivotIndex)
quicksortDutchFlag(&a, low: low, high: p - 1)
quicksortDutchFlag(&a, low: q + 1, high: high)
}
}

quicksortDutchFlag(&list5, low: 0, high: list5.count - 1)
4 changes: 4 additions & 0 deletions Quicksort/Quicksort.playground/contents.xcplayground
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='osx'>
<timeline fileName='timeline.xctimeline'/>
</playground>
6 changes: 6 additions & 0 deletions Quicksort/Quicksort.playground/timeline.xctimeline
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Timeline
version = "3.0">
<TimelineItems>
</TimelineItems>
</Timeline>
Loading

0 comments on commit 404c896

Please sign in to comment.