数据结构与算法八: 6)排序算法--归并排序

217 阅读3分钟

这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战

关注我,以下内容持续更新

数据结构与算法(一):时间复杂度和空间复杂度

数据结构与算法(二):桟

数据结构与算法(三):队列

数据结构与算法(四):单链表

数据结构与算法(五):双向链表

数据结构与算法(六):哈希表

数据结构与算法(七):树

数据结构与算法(八):排序算法

数据结构与算法(九):经典算法面试题

归并排序的介绍

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。归并排序,首先把一个数组中的元素,依次折半拆分,直至无法拆分,再按照正确的顺序两两合并为有序的子序列,然后再把有序的子序列继续两两合并,直至最后一次合并,得到一个完全有序的序列。所以归并排序的思想是逐步将已有序的子序列合并,得到完全有序的序列。(将两个有序表合并成一个有序表,称为二路归并。)

归并排序其实要做两件事:分解和合并

(1)“分解”——将序列每次折半划分

(2)“合并”——将划分后的序列段两两合并后排序

(1) 分治图解

分解.png

(2) 单趟合并图解

例如要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8]

单趟合并.png

归并排序有两种实现方式:基于递归的归并排序和基于循环的归并排序(也叫自顶向下的归并排序和自底向上的归并排序)。无论是基于递归还是循环的归并排序,它们调用的核心方法都是相同的:完成一趟合并的算法,即两个已经有序的数组序列合并成一个更大的有序数组序列。

归并排序的递归实现

基于递归的归并排序又叫做自顶向下的归并排序。

原理:使用递归方法来实现归并排序时,核心思想是两个有序子序列的合并,注意这里是有序子序列的合并,因此下面要做两件事,整个过程如下图所示:

(1)将待排序序列从中间一分为二,对左右两边再进行递归分割操作,得到n个相互独立的子序列; (2)对n个独立的子序列递归的执行合并操作,最终得到有序的序列。

分解.png

//归并排序的递归实现
-(NSArray*)mergeSort:(NSArray*)arr{
    if (arr.count<=1) {//递归停止条件
        return [arr mutableCopy];
    }

    //1. 把数组从中间分成左右两部分
    int center = (int)arr.count/2;

    NSArray*left = [arr subarrayWithRange:NSMakeRange(0, center)];

    NSArray*right = [arr subarrayWithRange:NSMakeRange(center, arr.count-center)];
    
    //2.分别对对左右两半部分进行递归
    NSArray*leftSub = [self mergeSort:left];
    NSArray*rightSub = [self mergeSort:right];
    
    //3.合并
    return [self mergeLeft:leftSub right:rightSub];
}
//合并的逻辑
-(NSArray*)mergeLeft:(NSArray*)left right:(NSArray*)right{

    NSMutableArray*result = [NSMutableArray array];
    int i = 0;
    int j = 0;

    while (i<left.count && j<right.count) {
        if ([left[i] intValue] < [right[j] intValue]) {
            [result addObject:left[i]];
            i++;
        }else {
            [result addObject:right[j]];
            j++;
        }
    }

    while (i<left.count) {
        [result addObject:left[i]];
        i++;
    }

    while (j<right.count) {
        [result addObject:right[j]];
        j++;
    }
    return result.copy;
}

递归的终止条件为子序列的长度为1,因为元素为1个默认是有序的

核心代码如下:

//2.分别对左右两半部分进行递归
NSArray*leftSub = [self mergeSort:left];
NSArray*rightSub = [self mergeSort:right];

//3.合并
return [self mergeLeft:leftSub right:rightSub];

递归方法的不足:每一步合并都必须创建一个临时数组,此数组用来暂存已经排好序的子序列,直到序列完全排好序。整个归并排序过程中的空间复杂度为O(n)。

归并排序的性能

归并排序是稳定排序,它也是一种十分高效的排序,它利用完全二叉树特性。 归并排序的最好、最坏和平均时间复杂度都是O(nlog2n),空间复杂度是 O(n)。

其他排序算法

排序算法:1)直接插入排序

排序算法:2)希尔排序

排序算法:3)冒泡排序

排序算法:4)快速排序

排序算法:5)选择排序

排序算法:6)归并排序

排序算法:7)基数排序

排序算法:8)堆排序