排序算法学习

术语说明

  • 稳定: 如果a原本在b前面,a=b,排序后a仍然在b的前面
  • 不稳定: 如果a原本在b前面,a=b,排序后a可能会出现在b的后面
  • 内排序: 所有排序操作在内存完成
  • 外排序:由于数据太大,数据存在磁盘中,排序通过磁盘和内存的数据传输才能进行

稳定性排序

  • 稳定: 冒泡、插入、归并、计数、桶排序、基数排序
  • 不稳定:选择排序、希尔排序、快排、堆排序

各类排序算法介绍

冒泡排序
  • 最佳情况:T(n) = O(n)
  • 最差情况:T(n) = O(n²)
  • 平均情况:T(n) = O(n²)
  1. 比较相邻的元素,如果第一个比第二个大,交换
  2. 对每一对相邻元素做同样的工作,每轮结束后,最大的数位于元素最后
  3. 重复以上步骤,除了每轮最后一个,直到排序完成
Swift
func bubbleSort(_ numbers: inout [T]) {
    for i in 0 ..< numbers.count {
        for j in 0 ..< numbers.count - i-1  {
            if numbers[j] > numbers[j+1] {
                (numbers[j], numbers[j+1]) = (numbers[j+1], numbers[j])
            }
            
        }
        print("第\(i)趟: \(numbers)")
    }
}

var array = [100, 50, 30, 10, 200, 0, -11, 44.5, -20, 120.3]
print("冒泡排序前:\(array)")
bubbleSort(&array)
print("冒泡排序后:\(array)")

OC
- (void)bubbleSort:(NSMutableArray*)numbers{
    for(int i = 0; i < numbers.count;i++){
        BOOL isExchange = NO;
        for(int j = 0; j < numbers.count-i-1; j++){
            if (numbers[j].floatValue > numbers[j+1].floatValue) {
                isExchange = YES;
                [numbers exchangeObjectAtIndex:j withObjectAtIndex:j+1];
            }
        }
        if (!isExchange) {  //一次排序未发生任何交换,证明已排序完毕,结束。 增加此代码,原总共需排序10躺将变为排序8躺
            break;
        }
        NSLog(@"第%d躺:%@", i, [numbers mj_JSONString]);
    }
}
NSMutableArray *array = [NSMutableArray arrayWithArray:@[@100, @50, @30, @10, @200, @0, @-11, @44.5, @-20, @120.3]];
    NSLog(@"冒泡排序前:%@",[array mj_JSONString]);
    [self bubbleSort:array];
    NSLog(@"冒泡排序后:%@", [array mj_JSONString]);

冒泡排序前:[100.0, 50.0, 30.0, 10.0, 200.0, 0.0, -11.0, 44.5, -20.0, 120.3]
第0趟: [50.0, 30.0, 10.0, 100.0, 0.0, -11.0, 44.5, -20.0, 120.3, 200.0]
第1趟: [30.0, 10.0, 50.0, 0.0, -11.0, 44.5, -20.0, 100.0, 120.3, 200.0]
第2趟: [10.0, 30.0, 0.0, -11.0, 44.5, -20.0, 50.0, 100.0, 120.3, 200.0]
第3趟: [10.0, 0.0, -11.0, 30.0, -20.0, 44.5, 50.0, 100.0, 120.3, 200.0]
第4趟: [0.0, -11.0, 10.0, -20.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]
第5趟: [-11.0, 0.0, -20.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]
第6趟: [-11.0, -20.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]
第7趟: [-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]
第8趟: [-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]
第9趟: [-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]
冒泡排序后:[-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]
选择排序
  • 最佳情况:T(n) = O(n²)
  • 最差情况:T(n) = O(n²)
  • 平均情况:T(n) = O(n²)
  1. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
  2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾
  3. 重复1、2,直到所有元素均排序完毕
Swift
func selectionSort(_ numbers: inout [T]) {  //选择
    for i in 0 ..< numbers.count {
        var minIdx = i
        //数组中找出一个最小数
        for j in i ..< numbers.count   {
            if numbers[j] < numbers[minIdx] {
                minIdx = j
            }
        }
        //将数组中最小数与待排位置交换
        (numbers[i], numbers[minIdx]) = (numbers[minIdx], numbers[i])
        print("第\(i)趟: \(numbers)")
    }
}
var array = [100, 50, 30, 10, 200, 0, -11, 44.5, -20, 120.3]
print("选择排序前:\(array)")
selectionSort(&array)
print("选择排序后:\(array)")

OC
- (void)selectionSort:(NSMutableArray *)numbers{
    for(int i = 0; i < numbers.count; i++){
        int minIdx = i;
        for(int j = i; j < numbers.count; j++){
            if ([numbers objectAtIndex:j].floatValue < numbers[minIdx].floatValue) {
                minIdx = j;
            }
        }
        [numbers exchangeObjectAtIndex:i withObjectAtIndex:minIdx];
    }
}
NSMutableArray *array = [NSMutableArray arrayWithArray:@[@100, @50, @30, @10, @200, @0, @-11, @44.5, @-20, @120.3]];
NSLog(@"选择排序前:%@",[array mj_JSONString]);
    [self selectionSort:array];
NSLog(@"选择排序后:%@", [array mj_JSONString]);

选择排序前:[100.0, 50.0, 30.0, 10.0, 200.0, 0.0, -11.0, 44.5, -20.0, 120.3]
第0趟: [-20.0, 50.0, 30.0, 10.0, 200.0, 0.0, -11.0, 44.5, 100.0, 120.3]
第1趟: [-20.0, -11.0, 30.0, 10.0, 200.0, 0.0, 50.0, 44.5, 100.0, 120.3]
第2趟: [-20.0, -11.0, 0.0, 10.0, 200.0, 30.0, 50.0, 44.5, 100.0, 120.3]
第3趟: [-20.0, -11.0, 0.0, 10.0, 200.0, 30.0, 50.0, 44.5, 100.0, 120.3]
第4趟: [-20.0, -11.0, 0.0, 10.0, 30.0, 200.0, 50.0, 44.5, 100.0, 120.3]
第5趟: [-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 200.0, 100.0, 120.3]
第6趟: [-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 200.0, 100.0, 120.3]
第7趟: [-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 200.0, 120.3]
第8趟: [-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]
第9趟: [-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]
选择排序后:[-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]
插入排序
  • 最佳情况:T(n) = O(n)
  • 最差情况:T(n) = O(n²)
  • 平均情况:T(n) = O(n²)
  1. 第一个元素当着已排序序列,取下一个元素,在已排序序列中从后往前扫描
  2. 如果已排序元素大于新数,将该元素往后移动一位
  3. 重复2,直到出现已排序元素小于或等于新元素。将新元素插入到该位置后
  4. 重复2、3
Swift
func insertionSort(_ numbers: inout [T]) {  //插入
    for i in 0 ..< numbers.count-1 {
        var preIdx = i  //已排序好的序列
        let current = numbers[i+1]  //待排序数
        //已排序数组中,移动数据,直到新元素大于已排序数
        while preIdx >= 0 && current < numbers[preIdx] {
            numbers[preIdx+1] = numbers[preIdx]
            preIdx -= 1
        }
        numbers[preIdx+1] = current
        print("第\(i)趟: \(numbers),待排数\(current)")
    }
}
var array = [100, 50, 30, 10, 200, 0, -11, 44.5, -20, 120.3]
print("排序前:\(array)")
insertionSort(&array)
print("排序后:\(array)")

OC
- (void)insertionSort:(NSMutableArray*)numbers{
    for(int i = 0; i < numbers.count-1;i++){
        double current = [numbers[i+1] doubleValue];
        int preIdx = i;
        while (preIdx >= 0 && current < numbers[preIdx].doubleValue) {
            [numbers exchangeObjectAtIndex:preIdx withObjectAtIndex:preIdx+1];
            preIdx--;
        }
        numbers[preIdx+1] = @(current);
        NSLog(@"第%d躺:%@", i, [numbers mj_JSONString]);
    }
}
NSMutableArray *array = [NSMutableArray arrayWithArray:@[@100, @50, @30, @10, @200, @0, @-11, @44.5, @-20, @120.3]];
NSLog(@"排序前:%@",[array mj_JSONString]);
[self insertionSort:array];
NSLog(@"排序后:%@", [array mj_JSONString]);

排序前:[100.0, 50.0, 30.0, 10.0, 200.0, 0.0, -11.0, 44.5, -20.0, 120.3]
第0趟: [50.0, 100.0, 30.0, 10.0, 200.0, 0.0, -11.0, 44.5, -20.0, 120.3],待排数50.0
第1趟: [30.0, 50.0, 100.0, 10.0, 200.0, 0.0, -11.0, 44.5, -20.0, 120.3],待排数30.0
第2趟: [10.0, 30.0, 50.0, 100.0, 200.0, 0.0, -11.0, 44.5, -20.0, 120.3],待排数10.0
第3趟: [10.0, 30.0, 50.0, 100.0, 200.0, 0.0, -11.0, 44.5, -20.0, 120.3],待排数200.0
第4趟: [0.0, 10.0, 30.0, 50.0, 100.0, 200.0, -11.0, 44.5, -20.0, 120.3],待排数0.0
第5趟: [-11.0, 0.0, 10.0, 30.0, 50.0, 100.0, 200.0, 44.5, -20.0, 120.3],待排数-11.0
第6趟: [-11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 200.0, -20.0, 120.3],待排数44.5
第7趟: [-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 200.0, 120.3],待排数-20.0
第8趟: [-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0],待排数120.3
排序后:[-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]
快速排序
  • 最佳情况:T(n) = O(nlogn)
  • 最差情况:T(n) = O(n²)
  • 平均情况:T(n) = O(nlogn)

通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序
设置两个变量 low、high,排序开始时:low=0,high=size-1。

  • 整个数组找基准正确位置,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面

  • 默认数组的第一个数为基准数据,赋值给key,即key=array[low]。
    因为默认数组的第一个数为基准,所以从后面开始向前搜索(high–),找到第一个小于key的array[high],就将 array[high] 赋给 array[low],即 array[low] = array[high]。(循环条件是 array[high] >= key;结束时 array[high] < key)
    此时从前面开始向后搜索(low++),找到第一个大于key的array[low],就将 array[low] 赋给 array[high],即 array[high] = array[low]。(循环条件是 array[low] <= key;结束时 array[low] > key)

  • 循环,直到 low=high,该位置就是基准位置。

  • 第一趟找到的基准位置,作为下一趟的分界点。

  • 递归调用(recursive)分界点前和分界点后的子数组排序。

Swift
func partitionSort(_ numbers: inout [T], tupe: (low: Int, high: Int)) {
    guard tupe.low < tupe.high && tupe.1 < numbers.count else {
        print("快排start\(tupe.low)必须小于end\(tupe.high)");
        return
    }
    //快排
    let key = numbers[tupe.0]  //默认数组左边第一个数为基准数,排序后,key左边的值小于key,右边的值大于key
    var i = tupe.0 //首
    var j = tupe.1 //尾
    while i < j {
        while i < j && numbers[j] >= key { //数组尾部查找到第一个比基准数小的数,
            j -= 1
        }
        numbers[i] = numbers[j]  //找到比基准数小的数,将该数调整到数组前部
        while i < j && numbers[i] <= key { //找到前部比基准大的数据
            i += 1
        }
        numbers[j] = numbers[i]  //将前部比基准小的数放置在末尾
    }
    //i=j,此位置为基准位置
    numbers[i] = key
    print("快排中:\(numbers)")
    partitionSort(&numbers, tupe: (tupe.low, i-1)) //递归排列左边元素
    partitionSort(&numbers, tupe: (i+1, tupe.high)) //递归排列右边元素
}
var array = [100, 50, 30, 10, 200, 0, -11, 44.5, -20, 120.3]
print("排序前:\(array)")
partitionSort(&array, tupe: (0, array.count-1))
print("排序后:\(array)")

OC
- (void)partitionSort:(NSMutableArray*)numbers low:(int)l high:(int)h{
    if (l >= h || h <= 0 ) {
        return;
    }
    NSNumber* key = numbers[l] ;
    int i = l;
    int j = h;
    while (i < j) {
        while (numbers[j].doubleValue >= key.doubleValue && i < j) { //数组尾部查找到第一个小于基准数
            j--;
        }
        numbers[i] = numbers[j];
        while (numbers[i].doubleValue <= key.doubleValue && i < j) {
            i++;
        }
        numbers[j] = numbers[i];
    }
    numbers[i] = key;
    NSLog(@"快排中%@", numbers.mj_JSONString);
    
    [self partitionSort:numbers low:l high:i-1];
    [self partitionSort:numbers low:i+1 high:h];
}
NSMutableArray *array = [NSMutableArray arrayWithArray:@[@100, @50, @30, @10, @200, @0, @-11, @44.5, @-20, @120.3]];
    NSLog(@"排序前:%@",[array mj_JSONString]);
    [self partitionSort:array low:0 high:array.count-1];
    NSLog(@"排序后:%@", [array mj_JSONString]);

排序前:[100.0, 50.0, 30.0, 10.0, 200.0, 0.0, -11.0, 44.5, -20.0, 120.3]
快排中:[-20.0, 50.0, 30.0, 10.0, 44.5, 0.0, -11.0, 100.0, 200.0, 120.3]
快排中:[-20.0, 50.0, 30.0, 10.0, 44.5, 0.0, -11.0, 100.0, 200.0, 120.3]
快排start0必须小于end-1
快排中:[-20.0, -11.0, 30.0, 10.0, 44.5, 0.0, 50.0, 100.0, 200.0, 120.3]
快排中:[-20.0, -11.0, 30.0, 10.0, 44.5, 0.0, 50.0, 100.0, 200.0, 120.3]
快排start1必须小于end0
快排中:[-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 200.0, 120.3]
快排中:[-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 200.0, 120.3]
快排start2必须小于end1
快排start3必须小于end3
快排start5必须小于end5
快排start7必须小于end6
快排中:[-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]
快排start8必须小于end8
快排start10必须小于end9
排序后:[-20.0, -11.0, 0.0, 10.0, 30.0, 44.5, 50.0, 100.0, 120.3, 200.0]

超详细排序算法总结

你可能感兴趣的:(排序算法学习)