排序算法

排序算法是计算机科学中的基本概念,它们在许多实际问题中有广泛的应用。以下是一些经典的排序算法,并分析其优缺点、时间复杂度和空间复杂度,并提供 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)
posted @   Mr.陳  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
历史上的今天:
2015-07-17 iOS开发基础10-UIButton内边距和图片拉伸模式
2015-07-17 iOS开发基础9-提示框(UIAlertController)
点击右上角即可分享
微信分享提示