排序 --- 归并排序

来都来了 2020-10-21 14:14:16 ⋅ 610 阅读

此篇文章引自 这里,个人感觉无出其右者,只好借鉴而来

归并排序 是递归分治和有序合并的简称, 首先利用分治法的思想将序列递归分裂成若干个子序列,使将子序列基本有序,最后使整体有序。

一、图示过程

1、归并排序的流程


 
 

2.合并两个有序数组的流程


 
 

二、动图展示

 
 

三、代码展示

//java展示
public static void mergeSort(int[] arr) {
    sort(arr, 0, arr.length - 1);
}

public static void sort(int[] arr, int L, int R) {
    if(L == R) {
        return;
    }
    int mid = L + ((R - L) >> 1);
    sort(arr, L, mid);
    sort(arr, mid + 1, R);
    merge(arr, L, mid, R);
}

public static void merge(int[] arr, int L, int mid, int R) {
    int[] temp = new int[R - L + 1];
    int i = 0;
    int p1 = L;
    int p2 = mid + 1;
    // 比较左右两部分的元素,哪个小,把那个元素填入temp中
    while(p1 <= mid && p2 <= R) {
        temp[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
    }
    // 上面的循环退出后,把剩余的元素依次填入到temp中
    // 以下两个while只有一个会执行
    while(p1 <= mid) {
        temp[i++] = arr[p1++];
    }
    while(p2 <= R) {
        temp[i++] = arr[p2++];
    }
    // 把最终的排序的结果复制给原数组
    for(i = 0; i < temp.length; i++) {
        arr[L + i] = temp[i];
    }
}
//C语言展示

/** 此处求数组长度,因为在c语言中,数组作为形参传递的话 ,在被调用函数中只是作为首地址的指针,因此无法求出数组长度,需要写一个辅助函数*/
int k_length(int arr[]) {
    int *p = arr;
    int i = 0;
    while ((*p)!= '\0') {
        p++;
        i++;
    }
    return i;
}

void mergeSort(int arr[]) {
    sort(arr, 0, k_length(arr) - 1);
}

void sort(int arr[], int L, int R) {
    if(L == R) {
        return;
    }
    int mid = (L+R)/2;
    sort(arr, L, mid);
    sort(arr, mid + 1, R);
    merge(arr,L, mid, R);
}

void merge(int arr[],  int L, int mid, int R) {
    
    int arrLength = k_length(arr);
    int *temp;
    temp= (int *)calloc(arrLength,sizeof(int));
    
    int i = 0;
    int p1 = L;
    int p2 = mid + 1;
    // 比较左右两部分的元素,哪个小,把那个元素填入temp中
    while(p1 <= mid && p2 <= R) {
        temp[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
    }
    // 上面的循环退出后,把剩余的元素依次填入到temp中
    // 以下两个while只有一个会执行
    while(p1 <= mid) {
        temp[i++] = arr[p1++];
    }
    while(p2 <= R) {
        temp[i++] = arr[p2++];
    }
    // 把最终的排序的结果复制给原数组
    int  tempLength = k_length(temp);
    for(i = 0; i < tempLength; i++) {
        arr[L + i] = temp[i];
    }
}



   #pragma mark - 使用
    int arr[] = {2,1,4,3,6,5,8,7};
    int length = sizeof(arr) /sizeof(int);
    mergeSort(arr);
    for (int i = 0; i< length; i++) {
        printf("%d,",arr[i]);
    }

//OC使用
- (void)k_OC_mergeSort:(NSMutableArray *)arr {
    [self k_OC_Sort:arr start:0 end:arr.count - 1];
}

- (void)k_OC_Sort:(NSMutableArray *)arr start:(NSInteger)start end:(NSInteger)end {
    if (start == end) {
        return;
    }
    
    NSInteger mid = (start + end)/2;
    [self k_OC_Sort:arr start:start end:mid];
    [self k_OC_Sort:arr start:mid+1 end:end];
    [self k_OC_merge:arr sart:start mid:mid end:end];
}

- (void)k_OC_merge:(NSMutableArray *)arr sart:(NSInteger)start mid:(NSInteger)mid end:(NSInteger)end {
    
    NSMutableArray *temp = [NSMutableArray array];
    NSInteger i = 0;
    NSInteger p1 = start;
    NSInteger p2 = mid + 1;
    
    while(p1 <= mid && p2 <= end) {
        NSNumber *tempNum = ([arr[p1] integerValue] < [arr[p2] integerValue])? arr[p1++] : arr[p2++];
        [temp addObject:tempNum];
    }
    while(p1 <= mid) {
        [temp addObject:arr[p1++]];
    }
    while(p2 <= end) {
        [temp addObject:arr[p2++]];
    }
    
    for(i = 0; i < temp.count; i++) {
        arr[start + i] = temp[i];
    }
}


  #pragma mark - 使用
 NSMutableArray *arr = [@[@(7),@(4),@(0),@(3),@(6),@(1),@(2),@(5)] mutableCopy];
    [self k_OC_mergeSort:arr];
    NSLog(@"+++++++++ %@",arr);

四、复杂度

时间复杂度:O(nlogn)
空间复杂度:O(N) 归并排序需要一个与原数组相同长度的数组做辅助来排序
稳定性:归并排序是稳定的排序算法,temp[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];这行代码可以保证当左右两部分的值相等的时候,先复制左边的值,这样可以保证值相等的时候两个元素的相对位置不变。



作者:挽弓如月_80dc
链接:https://www.jianshu.com/p/0d401c14eb65
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

全部评论: 0

    我有话说:

    算法实战---OC希尔排序(二)

    我没有为这种算法做任何事,我的名字不应该出现在算法的名字中。---- 希尔(shell排序作者)

    Java项目权威排名:Nacos未上版,Maven排名 28

    来源:toutiao.com/i6908912198412681732/ https://github.com/ossf/criticality_score 发布了开源项目排名, 下载地址

    算法实战---OC快速排序(一)

    近来在巩固数据结构和算法的知识, 动动手操作操作. 能讲出来是真的懂了, 分享是件快乐的事第一.

    InfluxDB 1.7.11 发布,开源时序数据库

    InfluxDB 1.7.11 现已发布,具体更新内容如下: Bug 修复 #17633:fix(storage/reads):更新 sortKey 排序方法以使用空字节作为分隔符,而不是逗号

    xrkmonitor 字符云监控系统 v3.3 日志系统增强

    该版本主要增强日志系统功能,包括引入通用日志文件监控插件,核心代码上日志系统新增日志数和日志类型统计图表,日志系统按配置大小自动滚动日志;插件架构上,插件配置项通过引用排序权重可实现排序显示,插件的

    Redis为什么变慢了?Redis性能问题排查详述

    Redis 作为优秀的内存数据库,其拥有非常高的性能,单个实例的 OPS 能够达到 10W 左右。但也正因此如此,当我们在使用 Redis 时,如果发现操作延迟变大的情况,就会与我们的预期不符。 你也许或多或少地,也遇到过以下这些场景: 在 R...

    抱歉,前端兄弟们,我拖后腿了

    开源中国最新统计的2019年最受开发者欢迎的开源软件排名

    GitHub精选:2018年11月份最热门的Java开源项目

    又到了揭晓 11 月份最热门 Java 开源项目排名的时候了,在本月的名单中,出现了几个新面孔,如Java 核心知识库、轻量级容错组件Resilience4j .....

    Node rabbitmq 入门就够了

    集成。 通过提供消息传递和消息排队模型 ,它可以...

    数据结构

    结构,简单的理解就是关系。严格点说,结构是指各个组成部分相互搭配和排列的方式。在现实世界中,不同数据元素之间不是独立的,而是存在特定的关系,我们将这些关系成为结构。 数据结构:是相互之间存在一种

    「转载」微服务分布式架构中,如何实现日志链路跟踪?

    背景 开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用ELK来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,我们来看下面的图     上图

    「千万级秒杀架构」千万级并发流量下,如何将流量串行化?

    流量串行化,是指在高并发的场景下通过排队的方式将无序的并发流量整理成有序串行流量。大家都知道在 Redis 集群部署模式出现之前,市面上大多数 的 Redis 都是采用一主多从模式,写操作全部是由主

    Beeorder 3.6.0 发布,餐饮点餐小程序

    项目简介 beeorder是餐饮点餐商城微信小程序,针对餐饮行业推出的一套完整的餐饮解决方案,实现了用户在线点餐下单、外卖、叫号排队、支付、配送等功能,完美的使餐饮行业更高效便捷! 新增:1. 增加

    假期归来,睡前看一看多款软件发布最新版本

    SpringBoot、Element和React UI等多款软件发布新版本

    RedisPlus 3.0.0 重构归来免费开源,优化性能和交互体验

    RedisPlus是为Redis可视化管理开发的一款开源免费的桌面客户端软件,支持Windows 、Linux、Mac三大系统平台,RedisPlus提供更加高效、方便、快捷的使用体验,有着更加现代化的用户界面风格。