Swift 排序算法

插入排序

通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

时间复杂度 最好 O(N) 平均、最坏 O(n^2)

空间复杂度 O(1)

func insertionSort(_ array: inout [Int]) { let n = array.count for i in 1..<n { let key = array[i] var j = i - 1 // 将 array[i] 插入到已排序的子数组 array[0...i-1] 中 while j >= 0 && array[j] > key { array[j + 1] = array[j] j -= 1 } array[j + 1] = key } } // 测试插入排序 var numbers = [5, 2, 9, 1, 5, 6] insertionSort(&numbers) print(numbers)

这段代码定义了一个名为 insertionSort 的函数,它接受一个整型数组作为输入,并对其进行原地排序。insertionSort 函数的核心是两个嵌套的循环:外部循环从数组的第二个元素开始遍历(因为第一个元素默认是有序的),内部循环用于将当前元素插入到已排序部分的正确位置。


选择排序

每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。

时间复杂度 O(n^2)

空间复杂度 O(1)

func selectionSort(_ array: inout [Int]) { let n = array.count for i in 0..<n { // 假设最小数为当前元素 var minIndex = i // 找到当前数往后剩余数组中最小的元素 for j in i+1..<n { if array[j] < array[minIndex] { minIndex = j } } // 如果最小数 index 发生了变化,则交换当前元素和最小元素 if minIndex != i { array.swapAt(i, minIndex) } } } // 测试选择排序 var numbers = [5, 2, 9, 1, 5, 6] selectionSort(&numbers) print(numbers)

这段代码定义了一个名为 selectionSort 的函数,它接受一个整型数组作为输入,并对其进行原地排序。selectionSort 函数的核心是两个嵌套的循环:外部循环从数组的第一个元素开始遍历,内部循环用于找到剩余部分中的最小元素并与当前元素交换。通过这种方式,数组逐渐变得有序。


冒泡排序

冒泡排序(Bubble Sort)是一种简单的排序算法,它通过重复地遍历要排序的元素,比较每对相邻的元素,并在它们的顺序不正确时交换它们的位置,直到整个列表有序。

时间复杂度 最坏 O(n^2) 最好 O(n)

空间复杂度 O(1)

func bubbleSort(array: inout [Int]) { let n = array.count for i in 0..<n { for j in 1..<n-i { if array[j-1] > array[j] { array.swapAt(j-1, j) } } } } // 测试冒泡排序 var numbers = [5, 2, 9, 1, 5, 6] bubbleSort(&numbers) print(numbers)

快速排序

采用分治法(Divide and Conquer)来将一个序列分为较小和较大的两个子序列,然后递归地排序两个子序列。

时间复杂度 最好、平均 O(nlogn) 最坏 O(n^2)

空间复杂度 最坏 O(n) 平均 O(log n)

func quickSort<T: Comparable>(_ array: [T]) -> [T] { // 如果数组为空或只有一个元素,直接返回该数组 guard array.count > 1 else { return array } // 选择基准元素 let pivot = array[array.count / 2] // 将数组分成三个部分 let less = array.filter { $0 < pivot } let equal = array.filter { $0 == pivot } let greater = array.filter { $0 > pivot } // 递归排序每个部分,并合并结果 return quickSort(less) + equal + quickSort(greater) } // 测试快速排序 var numbers = [5, 2, 9, 1, 5, 6] print(quickSort(numbers))

这段代码定义了两个函数:quickSort 和 partition。quickSort 函数使用递归将数组分成两部分,并分别对这两部分进行排序。partition 函数选择一个枢轴,并根据枢轴将数组分成两部分,使得枢轴左边的元素都小于或等于枢轴,右边的元素都大于枢轴。通过不断递归地分割和排序,最终得到一个有序的数组。


归并排序

采用分治法(Divide and Conquer)将一个序列分成两个子序列,分别进行排序,然后将两个已排序的子序列合并成一个有序序列。

时间复杂度 O(nlogn)

空间复杂度 O(n)

import Foundation func mergeSort(array: [Int]) -> [Int] { guard array.count > 1 else { return array } let leftArray = Array(array[0..<array.count/2]) let rightArray = Array(array[array.count/2..<array.count]) return merge(left: mergeSort(array: leftArray), right: mergeSort(array: rightArray)) } func merge(left: [Int], right: [Int]) -> [Int] { var mergedArray: [Int] = [] var left = left var right = right while left.count > 0 && right.count > 0 { if left.first! < right.first! { mergedArray.append(left.removeFirst()) } else { mergedArray.append(right.removeFirst()) } } return mergedArray + left + right } var numbers: [Int] = [4,3,2,5,1] print(numbers) print(mergeSort(array: numbers))

这段代码定义了两个函数:mergeSort 和 merge。mergeSort 函数使用递归将数组分成两半,并对每一半进行排序。merge 函数将两个有序的子数组合并成一个有序的数组。通过递归地将数组不断分割,直到每个子数组的长度为 1,然后再通过合并操作将它们逐步合并成一个有序的数组。


堆排序

堆排序(Heapsort)是一种基于堆这种数据结构的比较排序算法。堆排序将数组视为二叉树结构,通过调整二叉树来进行排序。

时间复杂度 O(nlogn)

空间复杂度 O(1)

func heapSort(_ array: inout [Int]) { let n = array.count // 构建最大堆 for i in stride(from: n / 2 - 1, through: 0, by: -1) { heapify(&array, n, i) } // 一个一个取出元素进行调整 for i in stride(from: n - 1, through: 1, by: -1) { array.swapAt(0, i) heapify(&array, i, 0) } } func heapify(_ array: inout [Int], _ n: Int, _ i: Int) { var largest = i let left = 2 * i + 1 let right = 2 * i + 2 if left < n && array[left] > array[largest] { largest = left } if right < n && array[right] > array[largest] { largest = right } if largest != i { array.swapAt(i, largest) heapify(&array, n, largest) } } // 测试堆排序 var numbers = [5, 2, 9, 1, 5, 6] heapSort(&numbers) print(numbers)

这段代码定义了两个函数:heapSort 和 heapify。heapSort 函数首先构建一个最大堆,然后将堆顶元素与当前堆的最后一个元素交换,再调整堆,以此类推,直到整个数组有序。heapify 函数用于维护堆的性质,使其满足最大堆的条件。通过这种方式,数组逐渐变得有序。