-
Notifications
You must be signed in to change notification settings - Fork 9.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add Swift codes for chapter_sorting articles (#313)
* feat: add Swift codes for bubble_sort article * feat: add Swift codes for insertion_sort article * feat: add Swift codes for quick_sort article * feat: add Swift codes for merge_sort article * feat: add Swift codes for radix_sort * refactor: remove ^ operator
- Loading branch information
Showing
10 changed files
with
525 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/** | ||
* File: bubble_sort.swift | ||
* Created Time: 2023-01-29 | ||
* Author: nuomi1 (nuomi1@qq.com) | ||
*/ | ||
|
||
/* 冒泡排序 */ | ||
func bubbleSort(nums: inout [Int]) { | ||
// 外循环:待排序元素数量为 n-1, n-2, ..., 1 | ||
for i in stride(from: nums.count - 1, to: 0, by: -1) { | ||
// 内循环:冒泡操作 | ||
for j in stride(from: 0, to: i, by: 1) { | ||
if nums[j] > nums[j + 1] { | ||
// 交换 nums[j] 与 nums[j + 1] | ||
let tmp = nums[j] | ||
nums[j] = nums[j + 1] | ||
nums[j + 1] = tmp | ||
} | ||
} | ||
} | ||
} | ||
|
||
/* 冒泡排序(标志优化)*/ | ||
func bubbleSortWithFlag(nums: inout [Int]) { | ||
// 外循环:待排序元素数量为 n-1, n-2, ..., 1 | ||
for i in stride(from: nums.count - 1, to: 0, by: -1) { | ||
var flag = false // 初始化标志位 | ||
for j in stride(from: 0, to: i, by: 1) { | ||
if nums[j] > nums[j + 1] { | ||
// 交换 nums[j] 与 nums[j + 1] | ||
let tmp = nums[j] | ||
nums[j] = nums[j + 1] | ||
nums[j + 1] = tmp | ||
flag = true // 记录交换元素 | ||
} | ||
} | ||
if !flag { // 此轮冒泡未交换任何元素,直接跳出 | ||
break | ||
} | ||
} | ||
} | ||
|
||
@main | ||
enum BubbleSort { | ||
/* Driver Code */ | ||
static func main() { | ||
var nums = [4, 1, 3, 1, 5, 2] | ||
bubbleSort(nums: &nums) | ||
print("冒泡排序完成后 nums = \(nums)") | ||
|
||
var nums1 = [4, 1, 3, 1, 5, 2] | ||
bubbleSortWithFlag(nums: &nums1) | ||
print("冒泡排序完成后 nums1 = \(nums1)") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/** | ||
* File: insertion_sort.swift | ||
* Created Time: 2023-01-29 | ||
* Author: nuomi1 (nuomi1@qq.com) | ||
*/ | ||
|
||
/* 插入排序 */ | ||
func insertionSort(nums: inout [Int]) { | ||
// 外循环:base = nums[1], nums[2], ..., nums[n-1] | ||
for i in stride(from: 1, to: nums.count, by: 1) { | ||
let base = nums[i] | ||
var j = i - 1 | ||
// 内循环:将 base 插入到左边的正确位置 | ||
while j >= 0, nums[j] > base { | ||
nums[j + 1] = nums[j] // 1. 将 nums[j] 向右移动一位 | ||
j -= 1 | ||
} | ||
nums[j + 1] = base // 2. 将 base 赋值到正确位置 | ||
} | ||
} | ||
|
||
@main | ||
enum InsertionSort { | ||
/* Driver Code */ | ||
static func main() { | ||
var nums = [4, 1, 3, 1, 5, 2] | ||
insertionSort(nums: &nums) | ||
print("插入排序完成后 nums = \(nums)") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/** | ||
* File: merge_sort.swift | ||
* Created Time: 2023-01-29 | ||
* Author: nuomi1 (nuomi1@qq.com) | ||
*/ | ||
|
||
/** | ||
* 合并左子数组和右子数组 | ||
* 左子数组区间 [left, mid] | ||
* 右子数组区间 [mid + 1, right] | ||
*/ | ||
func merge(nums: inout [Int], left: Int, mid: Int, right: Int) { | ||
// 初始化辅助数组 | ||
let tmp = Array(nums[left ..< (right + 1)]) | ||
// 左子数组的起始索引和结束索引 | ||
let leftStart = left - left | ||
let leftEnd = mid - left | ||
// 右子数组的起始索引和结束索引 | ||
let rightStart = mid + 1 - left | ||
let rightEnd = right - left | ||
// i, j 分别指向左子数组、右子数组的首元素 | ||
var i = leftStart | ||
var j = rightStart | ||
// 通过覆盖原数组 nums 来合并左子数组和右子数组 | ||
for k in left ... right { | ||
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++ | ||
if i > leftEnd { | ||
nums[k] = tmp[j] | ||
j += 1 | ||
} | ||
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++ | ||
else if j > rightEnd || tmp[i] <= tmp[j] { | ||
nums[k] = tmp[i] | ||
i += 1 | ||
} | ||
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++ | ||
else { | ||
nums[k] = tmp[j] | ||
j += 1 | ||
} | ||
} | ||
} | ||
|
||
/* 归并排序 */ | ||
func mergeSort(nums: inout [Int], left: Int, right: Int) { | ||
// 终止条件 | ||
if left >= right { // 当子数组长度为 1 时终止递归 | ||
return | ||
} | ||
// 划分阶段 | ||
let mid = (left + right) / 2 // 计算中点 | ||
mergeSort(nums: &nums, left: left, right: mid) // 递归左子数组 | ||
mergeSort(nums: &nums, left: mid + 1, right: right) // 递归右子数组 | ||
// 合并阶段 | ||
merge(nums: &nums, left: left, mid: mid, right: right) | ||
} | ||
|
||
@main | ||
enum MergeSort { | ||
/* Driver Code */ | ||
static func main() { | ||
/* 归并排序 */ | ||
var nums = [7, 3, 2, 6, 0, 1, 5, 4] | ||
mergeSort(nums: &nums, left: 0, right: nums.count - 1) | ||
print("归并排序完成后 nums = \(nums)") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/** | ||
* File: quick_sort.swift | ||
* Created Time: 2023-01-29 | ||
* Author: nuomi1 (nuomi1@qq.com) | ||
*/ | ||
|
||
/* 元素交换 */ | ||
func swap(nums: inout [Int], i: Int, j: Int) { | ||
let tmp = nums[i] | ||
nums[i] = nums[j] | ||
nums[j] = tmp | ||
} | ||
|
||
/* 快速排序类 */ | ||
// 快速排序类-哨兵划分 | ||
func quickSortPartition(nums: inout [Int], left: Int, right: Int) -> Int { | ||
// 以 nums[left] 作为基准数 | ||
var i = left | ||
var j = right | ||
while i < j { | ||
while i < j, nums[j] >= nums[left] { | ||
j -= 1 // 从右向左找首个小于基准数的元素 | ||
} | ||
while i < j, nums[i] <= nums[left] { | ||
i += 1 // 从左向右找首个大于基准数的元素 | ||
} | ||
swap(nums: &nums, i: i, j: j) // 交换这两个元素 | ||
} | ||
swap(nums: &nums, i: i, j: left) // 将基准数交换至两子数组的分界线 | ||
return i // 返回基准数的索引 | ||
} | ||
|
||
// 快速排序类-快速排序 | ||
func quickSort(nums: inout [Int], left: Int, right: Int) { | ||
// 子数组长度为 1 时终止递归 | ||
if left >= right { | ||
return | ||
} | ||
// 哨兵划分 | ||
let pivot = quickSortPartition(nums: &nums, left: left, right: right) | ||
// 递归左子数组、右子数组 | ||
quickSort(nums: &nums, left: left, right: pivot - 1) | ||
quickSort(nums: &nums, left: pivot + 1, right: right) | ||
} | ||
|
||
/* 快速排序类(中位基准数优化) */ | ||
// 快速排序类(中位基准数优化)-选取三个元素的中位数 | ||
func quickSortMedianThree(nums: [Int], left: Int, mid: Int, right: Int) -> Int { | ||
if (nums[left] < nums[mid]) != (nums[left] < nums[right]) { | ||
return left | ||
} else if (nums[mid] < nums[left]) != (nums[mid] < nums[right]) { | ||
return mid | ||
} else { | ||
return right | ||
} | ||
} | ||
|
||
// 快速排序类(中位基准数优化)-哨兵划分(三数取中值) | ||
func quickSortMedianPartition(nums: inout [Int], left: Int, right: Int) -> Int { | ||
// 选取三个候选元素的中位数 | ||
let med = quickSortMedianThree(nums: nums, left: left, mid: (left + right) / 2, right: right) | ||
// 将中位数交换至数组最左端 | ||
swap(nums: &nums, i: left, j: med) | ||
return quickSortPartition(nums: &nums, left: left, right: right) | ||
} | ||
|
||
// 快速排序类(中位基准数优化)-快速排序 | ||
func quickSortMedian(nums: inout [Int], left: Int, right: Int) { | ||
// 子数组长度为 1 时终止递归 | ||
if left >= right { | ||
return | ||
} | ||
// 哨兵划分 | ||
let pivot = quickSortMedianPartition(nums: &nums, left: left, right: right) | ||
// 递归左子数组、右子数组 | ||
quickSortMedian(nums: &nums, left: left, right: pivot - 1) | ||
quickSortMedian(nums: &nums, left: pivot + 1, right: right) | ||
} | ||
|
||
/* 快速排序类(尾递归优化) */ | ||
// 快速排序类(尾递归优化)-哨兵划分 | ||
func quickSortTailCallPartition(nums: inout [Int], left: Int, right: Int) -> Int { | ||
quickSortPartition(nums: &nums, left: left, right: right) | ||
} | ||
|
||
// 快速排序类(尾递归优化)-快速排序(尾递归优化) | ||
func quickSortTailCall(nums: inout [Int], left: Int, right: Int) { | ||
var left = left | ||
var right = right | ||
// 子数组长度为 1 时终止 | ||
while left < right { | ||
// 哨兵划分操作 | ||
let pivot = quickSortTailCallPartition(nums: &nums, left: left, right: right) | ||
// 对两个子数组中较短的那个执行快排 | ||
if (pivot - left) < (right - pivot) { | ||
quickSortTailCall(nums: &nums, left: left, right: pivot - 1) // 递归排序左子数组 | ||
left = pivot + 1 // 剩余待排序区间为 [pivot + 1, right] | ||
} else { | ||
quickSortTailCall(nums: &nums, left: pivot + 1, right: right) // 递归排序右子数组 | ||
right = pivot - 1 // 剩余待排序区间为 [left, pivot - 1] | ||
} | ||
} | ||
} | ||
|
||
@main | ||
enum QuickSort { | ||
/* Driver Code */ | ||
static func main() { | ||
/* 快速排序 */ | ||
var nums = [2, 4, 1, 0, 3, 5] | ||
quickSort(nums: &nums, left: 0, right: nums.count - 1) | ||
print("快速排序完成后 nums = \(nums)") | ||
|
||
/* 快速排序(中位基准数优化) */ | ||
var nums1 = [2, 4, 1, 0, 3, 5] | ||
quickSortMedian(nums: &nums1, left: 0, right: nums1.count - 1) | ||
print("快速排序(中位基准数优化)完成后 nums1 = \(nums1)") | ||
|
||
/* 快速排序(尾递归优化) */ | ||
var nums2 = [2, 4, 1, 0, 3, 5] | ||
quickSortTailCall(nums: &nums2, left: 0, right: nums2.count - 1) | ||
print("快速排序(尾递归优化)完成后 nums2 = \(nums2)") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/** | ||
* File: radix_sort.swift | ||
* Created Time: 2023-01-29 | ||
* Author: nuomi1 (nuomi1@qq.com) | ||
*/ | ||
|
||
/* 获取元素 num 的第 k 位,其中 exp = 10^(k-1) */ | ||
func digit(num: Int, exp: Int) -> Int { | ||
// 传入 exp 而非 k 可以避免在此重复执行昂贵的次方计算 | ||
(num / exp) % 10 | ||
} | ||
|
||
/* 计数排序(根据 nums 第 k 位排序) */ | ||
func countSort(nums: inout [Int], exp: Int) { | ||
// 十进制的各位数字范围为 0~9 ,因此需要长度为 10 的桶 | ||
var bucket = Array(repeating: 0, count: 10) | ||
let n = nums.count | ||
// 借助桶来统计 0~9 各数字的出现次数 | ||
for i in nums.indices { | ||
let d = digit(num: nums[i], exp: exp) // 获取 nums[i] 第 k 位,记为 d | ||
bucket[d] += 1 // 统计数字 d 的出现次数 | ||
} | ||
// 求前缀和,将“出现个数”转换为“数组索引” | ||
for i in 1 ..< 10 { | ||
bucket[i] += bucket[i - 1] | ||
} | ||
// 倒序遍历,根据桶内统计结果,将各元素填入暂存数组 tmp | ||
var tmp = Array(repeating: 0, count: n) | ||
for i in stride(from: n - 1, through: 0, by: -1) { | ||
let d = digit(num: nums[i], exp: exp) | ||
let j = bucket[d] - 1 // 获取 d 在数组中的索引 j | ||
tmp[j] = nums[i] // 将当前元素填入索引 j | ||
bucket[d] -= 1 // 将 d 的数量减 1 | ||
} | ||
// 将 tmp 复制到 nums | ||
for i in nums.indices { | ||
nums[i] = tmp[i] | ||
} | ||
} | ||
|
||
/* 基数排序 */ | ||
func radixSort(nums: inout [Int]) { | ||
// 获取数组的最大元素,用于判断最大位数 | ||
var ma = Int.min | ||
for num in nums { | ||
if num > ma { | ||
ma = num | ||
} | ||
} | ||
// 按照从低位到高位的顺序遍历 | ||
for exp in sequence(first: 1, next: { ma >= ($0 * 10) ? $0 * 10 : nil }) { | ||
// 对数组元素的第 k 位执行「计数排序」 | ||
// k = 1 -> exp = 1 | ||
// k = 2 -> exp = 10 | ||
// k = 3 -> exp = 100 | ||
// 即 exp = 10^(k-1) | ||
countSort(nums: &nums, exp: exp) | ||
} | ||
} | ||
|
||
@main | ||
enum RadixSort { | ||
/* Driver Code */ | ||
static func main() { | ||
/* 基数排序 */ | ||
var nums = [23, 12, 3, 4, 788, 192] | ||
radixSort(nums: &nums) | ||
print("基数排序完成后 nums = \(nums)") | ||
} | ||
} |
Oops, something went wrong.