美文网首页
归并排序

归并排序

作者: 点滴86 | 来源:发表于2024-08-12 22:31 被阅读0次

归并排序

归并排序的核心思想还是蛮简单的。如果要排序一个数组,先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就有序了。


归并排序使用的就是分治思想。分治,顾名思义,就是分而治之,将一个大问题分解成小的子问题来解决。小的子问题解决了,大问题也就解决了。
代码实现如下:
@interface DMMergeSort : NSObject

// 归并排序
- (void)mergeSort:(NSMutableArray *)dataArray;

@end

@implementation DMMergeSort

- (void)mergeSort:(NSMutableArray *)dataArray
{
    NSLog(@"归并排序前:%@", dataArray);
    if ([dataArray count] > 1) {
        [self mergeSort:dataArray startIndex:0 endIndex:[dataArray count] - 1];
    }
    NSLog(@"归并排序后:%@", dataArray);
}

- (void)mergeSort:(NSMutableArray *)dataArray startIndex:(NSInteger)startIndex endIndex:(NSInteger)endIndex
{
    // 递归终止条件
    if (startIndex >= endIndex) {
        return;
    }
    
    // 取 startIndex到endIndex之间的中间位置
    NSInteger tmpIndex = startIndex + (endIndex - startIndex) / 2;
    
    // 分治递归
    [self mergeSort:dataArray startIndex:startIndex endIndex:tmpIndex];
    [self mergeSort:dataArray startIndex:tmpIndex + 1 endIndex:endIndex];
    
    // 将 有序数组startIndex...tmpIndex 和 有序数组tmpIndex + 1...endIndex 合并为 startIndex...endIndex 有序
    [self merge:dataArray startIndex:startIndex midIndex:tmpIndex endIndex:endIndex];
}

- (void)merge:(NSMutableArray *)dataArray startIndex:(NSInteger)startIndex midIndex:(NSInteger)midIndex endIndex:(NSInteger)endIndex
{
    NSMutableArray *tmpArray = [[NSMutableArray alloc] init];
    NSInteger i = startIndex;
    NSInteger j = midIndex + 1;
    while (i <= midIndex && j <= endIndex) {
        NSNumber *numOne = [dataArray objectAtIndex:i];
        NSNumber *numTwo = [dataArray objectAtIndex:j];
        if ([numOne integerValue] <= [numTwo integerValue]) {
            [tmpArray addObject:numOne];
            i++;
        } else {
            [tmpArray addObject:numTwo];
            j++;
        }
    }
    
    // 判断那个子数组中有剩余的数据
    if (i > midIndex) {
        // 将剩余的数据拷贝到临时数组tmp
        while (j <= endIndex) {
            NSNumber *num = [dataArray objectAtIndex:j];
            [tmpArray addObject:num];
            j++;
        }
    } else {
        // 将剩余的数据拷贝到临时数组tmp
        while (i <= midIndex) {
            NSNumber *num = [dataArray objectAtIndex:i];
            [tmpArray addObject:num];
            i++;
        }
    }
    
    // 将tmp中的数据拷贝回数组dataArray中,下标startIndex...endIndex
    for (NSInteger i = startIndex, j = 0; i <= endIndex; i++, j++) {
        [dataArray replaceObjectAtIndex:i withObject:[tmpArray objectAtIndex:j]];
    }
}

@end

@interface DMSortDemo : NSObject

@end

@implementation DMSortDemo

- (void)demo 
{   
    // 归并排序
    DMMergeSort *mergeSort = [[DMMergeSort alloc] init];
    {
        NSMutableArray *dataArray = [[NSMutableArray alloc] init];
        [dataArray addObject:[NSNumber numberWithInteger:11]];
        [dataArray addObject:[NSNumber numberWithInteger:8]];
        [dataArray addObject:[NSNumber numberWithInteger:3]];
        [dataArray addObject:[NSNumber numberWithInteger:9]];
        [dataArray addObject:[NSNumber numberWithInteger:7]];
        [dataArray addObject:[NSNumber numberWithInteger:1]];
        [dataArray addObject:[NSNumber numberWithInteger:2]];
        [dataArray addObject:[NSNumber numberWithInteger:5]];
        [mergeSort mergeSort:dataArray];
    }
    {
        NSMutableArray *dataArray = [[NSMutableArray alloc] init];
        [dataArray addObject:[NSNumber numberWithInteger:4]];
        [dataArray addObject:[NSNumber numberWithInteger:5]];
        [dataArray addObject:[NSNumber numberWithInteger:6]];
        [dataArray addObject:[NSNumber numberWithInteger:1]];
        [dataArray addObject:[NSNumber numberWithInteger:3]];
        [dataArray addObject:[NSNumber numberWithInteger:2]];
        [mergeSort mergeSort:dataArray];
    }
}

@end

方法 - (void)merge:(NSMutableArray *)dataArray startIndex:(NSInteger)startIndex midIndex:(NSInteger)midIndex endIndex:(NSInteger)endIndex 的作用就是,将已经有序的A[p...q]和A[q+1...r]合并成一个有序的数组,并且放入A[p...r]。
如下图所示,申请一个临时数组tmp,大小与A[p...r]相同。用两个游标i和j,分别指向A[p...q]和A[q+1...r]的第一个元素。比较这两个元素A[i]和A[j],如果A[i] <= A[j],就把A[i]放入到临时数组tmp,并且i后移一位,否则将A[j]放入到临时数组tmp,并且j后移一位。
继续上述比较过程,直到其中一个子数组中的所有数据都放入临时数组中,再把另一个数组中的数据依次加入到临时数组的末尾,这个时候,临时数组中存储的就是两个子数组合并之后的结果了。最后再把临时数组tmp中的数据拷贝到原数组A[p...r]中。

归并排序的性能分析

第一,归并排序是稳定的排序算法吗?

归并排序稳不稳定关键看merge方法,也就是两个有序数组合并成一个有序数组的那部分代码实现。在合并的过程中,如果A[p...q]和A[q+1...r]之间有值相同的元素,先把A[p...q]中的元素放入tmp数组。这样就保证了值相同的元素,在合并前后的先后顺序不变。所以,归并排序是一个稳定的排序算法。

第二,归并排序的时间复杂度是多少?

归并排序的执行效率与要排序的原始数据的有序程度无关,所以其时间复杂度是非常稳定的,不管是最好情况、最坏情况,还是平均情况,时间复杂度都是O(nlogn)。

第三,归并排序的空间复杂度是多少?

在任意时刻,只会有一个临时的内存空间在使用。临时内存空间最大也不会超过n个数据的大小,所以空间复杂度是O(n)。

相关文章

  • 排序算法

    约定 选择排序 冒泡排序 插入排序 希尔排序 归并排序1. 归并方法2. 自顶向下归并排序3. 自底向上归并排序 ...

  • 排序二:归并、快排

    文章结构 归并排序 快速排序 源码 1. 归并排序 1.1 什么是归并排序 归并排序的思想是:将待排序的区间平分成...

  • java归并排序

    归并排序什么是归并排序:图解归并排序归并排序有两种实现方式,一是基于递归,而是基于迭代1)基于递归的归并排序: 基...

  • 算法—排序篇2

    1、归并排序(Merging Sort) 归并排序(Merging Sort): 就是利用归并的思想实现排序⽅法....

  • 常见的排序算法(2)

    要点 快速排序 归并排序 1.快速排序 2.归并排序

  • 排序算法之归并排序

    归并排序(Merge Sort) 归并排序是利用归并的思想实现排序的方式,该算法采用的是经典的分治算法 归并排序过...

  • 算法 第二章第二部分笔记

    各种排序算法的性能特点 选择排序 插入排序 希尔排序 归并排序 本地归并排序 自底向上的归并排序 快速排序 三向切...

  • 归并排序(二路归并排序)

    归并排序的思路 归并排序是通过“归并”操作完成排序的,将两个或者多个有序子表归并成一个子表。归并排序是“分治法”的...

  • 算法排序之归并排序和快速排序

    归并排序和快速排序用的都是分治的思想,用递归的编程技巧来实现.咱们先来看归并排序. 归并排序 归并排序的核心思想就...

  • 基于左闭右开的乱序数组归并排序 2020-04-24(未经允许,

    归并排序代码模板 递归形式思路:二分nums数组后对nums的归并排序 = 对左侧数组归并排序+对右侧数组归并排序...

网友评论

      本文标题:归并排序

      本文链接:https://www.haomeiwen.com/subject/vlmdkjtx.html