Skip to content

Commit 5f0ea9b

Browse files
committed
Spell mergesort as merge sort
Add a bottom-up implementation Plus other small tweaks
1 parent 29fb51e commit 5f0ea9b

File tree

9 files changed

+464
-251
lines changed

9 files changed

+464
-251
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/* Top-down recursive version */
2+
3+
func mergeSort(array: [Int]) -> [Int] {
4+
guard array.count > 1 else { return array }
5+
let middleIndex = array.count / 2
6+
let leftArray = mergeSort(Array(array[0..<middleIndex]))
7+
let rightArray = mergeSort(Array(array[middleIndex..<array.count]))
8+
return merge(leftPile: leftArray, rightPile: rightArray)
9+
}
10+
11+
func merge(leftPile leftPile: [Int], rightPile: [Int]) -> [Int] {
12+
var leftIndex = 0
13+
var rightIndex = 0
14+
var orderedPile = [Int]()
15+
16+
while leftIndex < leftPile.count && rightIndex < rightPile.count {
17+
if leftPile[leftIndex] < rightPile[rightIndex] {
18+
orderedPile.append(leftPile[leftIndex])
19+
leftIndex += 1
20+
} else if leftPile[leftIndex] > rightPile[rightIndex] {
21+
orderedPile.append(rightPile[rightIndex])
22+
rightIndex += 1
23+
} else {
24+
orderedPile.append(leftPile[leftIndex])
25+
leftIndex += 1
26+
orderedPile.append(rightPile[rightIndex])
27+
rightIndex += 1
28+
}
29+
}
30+
31+
while leftIndex < leftPile.count {
32+
orderedPile.append(leftPile[leftIndex])
33+
leftIndex += 1
34+
}
35+
36+
while rightIndex < rightPile.count {
37+
orderedPile.append(rightPile[rightIndex])
38+
rightIndex += 1
39+
}
40+
41+
return orderedPile
42+
}
43+
44+
let array = [2, 1, 5, 4, 9]
45+
let sortedArray = mergeSort(array)
46+
47+
48+
49+
/* Bottom-up iterative version */
50+
51+
func mergeSortBottomUp<T>(a: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] {
52+
let n = a.count
53+
var z = [a, a] // the two working arrays
54+
var d = 0 // z[d] is used for reading, z[1 - d] for writing
55+
56+
var width = 1
57+
while width < n {
58+
59+
var i = 0
60+
while i < n {
61+
62+
var j = i
63+
var l = i
64+
var r = i + width
65+
66+
let lmax = min(l + width, n)
67+
let rmax = min(r + width, n)
68+
69+
while l < lmax && r < rmax {
70+
if isOrderedBefore(z[d][l], z[d][r]) {
71+
z[1 - d][j] = z[d][l]
72+
l += 1
73+
} else {
74+
z[1 - d][j] = z[d][r]
75+
r += 1
76+
}
77+
j += 1
78+
}
79+
while l < lmax {
80+
z[1 - d][j] = z[d][l]
81+
j += 1
82+
l += 1
83+
}
84+
while r < rmax {
85+
z[1 - d][j] = z[d][r]
86+
j += 1
87+
r += 1
88+
}
89+
90+
i += width*2
91+
}
92+
93+
width *= 2 // in each step, the subarray to merge becomes larger
94+
d = 1 - d // swap active array
95+
}
96+
return z[d]
97+
}
98+
99+
mergeSortBottomUp(array, <)

Merge Sort/MergeSort.swift

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//
2+
// Mergesort.swift
3+
//
4+
//
5+
// Created by Kelvin Lau on 2016-02-03.
6+
//
7+
//
8+
9+
func mergeSort(array: [Int]) -> [Int] {
10+
guard array.count > 1 else { return array }
11+
let middleIndex = array.count / 2
12+
let leftArray = mergeSort(Array(array[0..<middleIndex]))
13+
let rightArray = mergeSort(Array(array[middleIndex..<array.count]))
14+
return merge(leftPile: leftArray, rightPile: rightArray)
15+
}
16+
17+
func merge(leftPile leftPile: [Int], rightPile: [Int]) -> [Int] {
18+
var leftIndex = 0
19+
var rightIndex = 0
20+
var orderedPile = [Int]()
21+
22+
while leftIndex < leftPile.count && rightIndex < rightPile.count {
23+
if leftPile[leftIndex] < rightPile[rightIndex] {
24+
orderedPile.append(leftPile[leftIndex])
25+
leftIndex += 1
26+
} else if leftPile[leftIndex] > rightPile[rightIndex] {
27+
orderedPile.append(rightPile[rightIndex])
28+
rightIndex += 1
29+
} else {
30+
orderedPile.append(leftPile[leftIndex])
31+
leftIndex += 1
32+
orderedPile.append(rightPile[rightIndex])
33+
rightIndex += 1
34+
}
35+
}
36+
37+
while leftIndex < leftPile.count {
38+
orderedPile.append(leftPile[leftIndex])
39+
leftIndex += 1
40+
}
41+
42+
while rightIndex < rightPile.count {
43+
orderedPile.append(rightPile[rightIndex])
44+
rightIndex += 1
45+
}
46+
47+
return orderedPile
48+
}
49+
50+
/*
51+
This is an iterative bottom-up implementation. Instead of recursively splitting
52+
up the array into smaller sublists, it immediately starts merging the individual
53+
array elements.
54+
55+
As the algorithm works its way up, it no longer merges individual elements but
56+
larger and larger subarrays, until eventually the entire array is merged and
57+
sorted.
58+
59+
To avoid allocating many temporary array objects, it uses double-buffering with
60+
just two arrays.
61+
*/
62+
func mergeSortBottomUp<T>(a: [T], _ isOrderedBefore: (T, T) -> Bool) -> [T] {
63+
let n = a.count
64+
var z = [a, a] // the two working arrays
65+
var d = 0 // z[d] is used for reading, z[1 - d] for writing
66+
67+
var width = 1
68+
while width < n {
69+
70+
var i = 0
71+
while i < n {
72+
73+
var j = i
74+
var l = i
75+
var r = i + width
76+
77+
let lmax = min(l + width, n)
78+
let rmax = min(r + width, n)
79+
80+
while l < lmax && r < rmax {
81+
if isOrderedBefore(z[d][l], z[d][r]) {
82+
z[1 - d][j] = z[d][l]
83+
l += 1
84+
} else {
85+
z[1 - d][j] = z[d][r]
86+
r += 1
87+
}
88+
j += 1
89+
}
90+
while l < lmax {
91+
z[1 - d][j] = z[d][l]
92+
j += 1
93+
l += 1
94+
}
95+
while r < rmax {
96+
z[1 - d][j] = z[d][r]
97+
j += 1
98+
r += 1
99+
}
100+
101+
i += width*2
102+
}
103+
104+
width *= 2 // in each step, the subarray to merge becomes larger
105+
d = 1 - d // swap active array
106+
}
107+
return z[d]
108+
}

0 commit comments

Comments
 (0)