排序算法
排序算法是计算机科学中的基本概念,它们在许多实际问题中有广泛的应用。以下是一些经典的排序算法,并分析其优缺点、时间复杂度和空间复杂度,并提供 Objective-C 和 Swift 的实现代码。
1. Bubble Sort (冒泡排序)
思想
逐步比较数组中的相邻元素,对它们进行交换以确保较大的元素逐步移动到数组的末尾。重复这一过程直到整个数组都有序。
优缺点
- 优点:简单易懂,适合初学者。
- 缺点:效率低,适合小数据集。
时间复杂度
- 最坏情况: O(n^2)
- 最好情况: O(n)
- 平均情况: O(n^2)
空间复杂度
O(1)(原地排序)
Objective-C 实现
- (void)bubbleSort:(NSMutableArray<NSNumber *> *)arr {
NSUInteger n = arr.count;
BOOL swapped;
do {
swapped = NO;
for (NSUInteger i = 1; i < n; i++) {
if ([arr[i - 1] compare:arr[i]] == NSOrderedDescending) {
[arr exchangeObjectAtIndex:i withObjectAtIndex:i - 1];
swapped = YES;
}
}
n--;
} while (swapped);
}
Swift 实现
func bubbleSort(_ arr: inout [Int]) {
let n = arr.count
var swapped = false
repeat {
swapped = false
for i in 1..<n {
if arr[i - 1] > arr[i] {
arr.swapAt(i - 1, i)
swapped = true
}
}
} while swapped
}
2. Selection Sort (选择排序)
思想
选择数组中最小的元素,将其与数组的第一个元素交换位置,并在剩下的元素中重复这一过程。
优缺点
- 优点:简单易实现,对小数据集有效。
- 缺点:性能不佳,适合小数据集。
时间复杂度
- 最坏情况: O(n^2)
- 最好情况: O(n^2)
- 平均情况: O(n^2)
空间复杂度
O(1)
Objective-C 实现
- (void)selectionSort:(NSMutableArray<NSNumber *> *)arr {
NSUInteger n = arr.count;
for (NSUInteger i = 0; i < n - 1; i++) {
NSUInteger minIndex = i;
for (NSUInteger j = i + 1; j < n; j++) {
if ([arr[j] compare:arr[minIndex]] == NSOrderedAscending) {
minIndex = j;
}
}
[arr exchangeObjectAtIndex:i withObjectAtIndex:minIndex];
}
}
Swift 实现
func selectionSort(_ arr: inout [Int]) {
let n = arr.count
for i in 0..<n - 1 {
var minIndex = i
for j in i + 1..<n {
if arr[j] < arr[minIndex] {
minIndex = j
}
}
if i != minIndex {
arr.swapAt(i, minIndex)
}
}
}
3. Insertion Sort (插入排序)
思想
将数组分成已排序和未排序两部分,逐步将未排序部分的元素插入到已排序部分的正确位置。
优缺点
- 优点:适用于小型数据集,在数据量较小时表现良好。
- 缺点:性能不佳,不适合大型数据集。
时间复杂度
- 最坏情况: O(n^2)
- 最好情况: O(n)
- 平均情况: O(n^2)
空间复杂度
O(1)
Objective-C 实现
- (void)insertionSort:(NSMutableArray<NSNumber *> *)arr {
NSUInteger n = arr.count;
for (NSUInteger i = 1; i < n; i++) {
NSNumber *key = arr[i];
NSInteger j = i - 1;
while (j >= 0 && [arr[j] compare:key] == NSOrderedDescending) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
Swift 实现
func insertionSort(_ arr: inout [Int]) {
let n = arr.count
for i in 1..<n {
let key = arr[i]
var j = i - 1
while j >= 0 && arr[j] > key {
arr[j + 1] = arr[j]
j -= 1
}
arr[j + 1] = key
}
}
4. Merge Sort (归并排序)
思想
将数组分为两个子数组,对每个子数组进行排序,然后合并两个已排序的子数组。
优缺点
- 优点:性能稳定,适用于大型数据集。
- 缺点:需要额外的内存空间,递归调用有一定的额外开销。
时间复杂度
- 最坏情况: O(n log n)
- 最好情况: O(n log n)
- 平均情况: O(n log n)
空间复杂度
O(n)
Objective-C 实现
- (NSMutableArray<NSNumber *> *)mergeSort:(NSMutableArray<NSNumber *> *)arr {
if (arr.count <= 1) return arr;
NSUInteger mid = arr.count / 2;
NSMutableArray<NSNumber *> *leftArr = [[arr subarrayWithRange:NSMakeRange(0, mid)] mutableCopy];
NSMutableArray<NSNumber *> *rightArr = [[arr subarrayWithRange:NSMakeRange(mid, arr.count - mid)] mutableCopy];
return [self merge:[self mergeSort:leftArr] rightArr:[self mergeSort:rightArr]];
}
- (NSMutableArray<NSNumber *> *)merge:(NSMutableArray<NSNumber *> *)leftArr rightArr:(NSMutableArray<NSNumber *> *)rightArr {
NSMutableArray<NSNumber *> *result = [NSMutableArray array];
while (leftArr.count > 0 && rightArr.count > 0) {
if ([leftArr[0] compare:rightArr[0]] == NSOrderedAscending) {
[result addObject:leftArr[0]];
[leftArr removeObjectAtIndex:0];
} else {
[result addObject:rightArr[0]];
[rightArr removeObjectAtIndex:0];
}
}
[result addObjectsFromArray:leftArr];
[result addObjectsFromArray:rightArr];
return result;
}
Swift 实现
func mergeSort(_ arr: [Int]) -> [Int] {
guard arr.count > 1 else { return arr }
let mid = arr.count / 2
let leftArr = mergeSort(Array(arr[0..<mid]))
let rightArr = mergeSort(Array(arr[mid..<arr.count]))
return merge(leftArr, rightArr)
}
func merge(_ leftArr: [Int], _ rightArr: [Int]) -> [Int] {
var leftIndex = 0
var rightIndex = 0
var result: [Int] = []
while leftIndex < leftArr.count && rightIndex < rightArr.count {
if leftArr[leftIndex] < rightArr[rightIndex] {
result.append(leftArr[leftIndex])
leftIndex += 1
} else {
result.append(rightArr[rightIndex])
rightIndex += 1
}
}
result.append(contentsOf: leftArr[leftIndex..<leftArr.count])
result.append(contentsOf: rightArr[rightIndex..<rightArr.count])
return result
}
5. Quick Sort (快速排序)
思想
选择一个基准元素,将数组分为两部分,所有小于基准的元素放在左边,所有大于基准的元素放在右边,然后递归地对这两个部分进行排序。
优缺点
- 优点:平均性能优越,适合大型数据集。
- 缺点:最坏情况下性能较差,适用于随机访问的数据。
时间复杂度
- 最坏情况: O(n^2)
- 最好情况: O(n log n)
- 平均情况: O(n log n)
空间复杂度
O(log n)
Objective-C 实现
- (void)quickSort:(NSMutableArray<NSNumber *> *)arr low:(NSInteger)low high:(NSInteger)high {
if (low < high) {
NSInteger pi = [self partition:arr low:low high:high];
[self quickSort:arr low:low high:pi - 1];
[self quickSort:arr low:pi + 1 high:high];
}
}
- (NSInteger)partition:(NSMutableArray<NSNumber *> *)arr low:(NSInteger)low high:(NSInteger)high {
NSNumber *pivot = arr[high];
NSInteger i = low - 1;
for (NSInteger j = low; j < high; j++) {
if ([arr[j] compare:pivot] == NSOrderedAscending || [arr[j] isEqualToNumber:pivot]) {
i++;
[arr exchangeObjectAtIndex:i withObjectAtIndex:j];
}
}
[arr exchangeObjectAtIndex:i + 1 withObjectAtIndex:high];
return i + 1;
}
Swift 实现
func quickSort(_ arr: inout [Int], low: Int, high: Int) {
if low < high {
let pi = partition(&arr, low: low, high: high)
quickSort(&arr, low: low, high: pi - 1)
quickSort(&arr, low: pi + 1, high: high)
}
}
func partition(_ arr: inout [Int], low: Int, high: Int) -> Int {
let pivot = arr[high]
var i = low - 1
for j in low..<high {
if arr[j] <= pivot {
i += 1
arr.swapAt(i, j)
}
}
arr.swapAt(i + 1, high)
return i + 1
}
6. Heap Sort (堆排序)
思想
利用堆这种数据结构进行排序。构建最大堆,然后将堆顶元素与末尾元素交换,调整堆,重复该过程直到堆为空。
优缺点
- 优点:性能稳定,不受输入数据影响。
- 缺点:实现复杂,对缓存不友好。
时间复杂度
- 最坏情况: O(n log n)
- 最好情况: O(n log n)
- 平均情况: O(n log n)
空间复杂度
O(1)
Objective-C 实现
- (void)heapSort:(NSMutableArray<NSNumber *> *)arr {
NSUInteger n = arr.count;
for (NSInteger i = n / 2 - 1; i >= 0; i--) {
[self heapify:arr n:n i:i];
}
for (NSInteger i = n - 1; i >= 0; i--) {
[arr exchangeObjectAtIndex:0 withObjectAtIndex:i];
[self heapify:arr n:i i:0];
}
}
- (void)heapify:(NSMutableArray<NSNumber *> *)arr n:(NSUInteger)n i:(NSUInteger)i {
NSUInteger largest = i;
NSUInteger left = 2 * i + 1;
NSUInteger right = 2 * i + 2;
if (left < n && [arr[left] compare:arr[largest]] == NSOrderedDescending) {
largest = left;
}
if (right < n && [arr[right] compare:arr[largest]] == NSOrderedDescending) {
largest = right;
}
if (largest != i) {
[arr exchangeObjectAtIndex:i withObjectAtIndex:largest];
[self heapify:arr n:n i:largest];
}
}
Swift 实现
func heapSort(_ arr: inout [Int]) {
let n = arr.count
for i in stride(from: n / 2 - 1, through: 0, by: -1) {
heapify(&arr, n, i)
}
for i in stride(from: n - 1, through: 0, by: -1) {
arr.swapAt(0, i)
heapify(&arr, i, 0)
}
}
func heapify(_ arr: inout [Int], _ n: Int, _ i: Int) {
var largest = i
let left = 2 * i + 1
let right = 2 * i + 2
if left < n && arr[left] > arr[largest] {
largest = left
}
if right < n && arr[right] > arr[largest] {
largest = right
}
if largest != i {
arr.swapAt(i, largest)
heapify(&arr, n, largest)
}
}
总结
每种排序算法都有其特定的应用场景和优缺点。在实际开发中,应结合具体情况选择合适的排序算法。以下是各算法的时间复杂度和空间复杂度总结表:
排序算法 | 最坏时间复杂度 | 最好时间复杂度 | 平均时间复杂度 | 空间复杂度 |
---|---|---|---|---|
冒泡排序 | O(n^2) | O(n) | O(n^2) | O(1) |
选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) |
插入排序 | O(n^2) | O(n) | O(n^2) | O(1) |
归并排序 | O(n log n) | O(n log n) | O(n log n) | O(n) |
快速排序 | O(n^2) | O(n log n) | O(n log n) | O(log n) |
堆排序 | O(n log n) | O(n log n) | O(n log n) | O(1) |
将来的你会感谢今天如此努力的你!
版权声明:本文为博主原创文章,未经博主允许不得转载。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
2015-07-17 iOS开发基础10-UIButton内边距和图片拉伸模式
2015-07-17 iOS开发基础9-提示框(UIAlertController)