算法排序5——归并排序&分治思想

简介: 算法排序5——归并排序&分治思想

🟡前言


今天是21天挑战赛第二周,本文主要讲归并排序,也是分治思想的重要体现


🟡概述


1️⃣原理图


fbd46989ec404b9b8248f80b20b06d9a.png


2️⃣排序原理&思想体现


归并排序就是将数组尽可能拆成等分的两组,直至变成单个元素(

然后对拆分出来的元素两两排序后组合,变成一个有序的数组(


🟡调用API解决


1️⃣成员变量


private static Comparable[] assist:完成归并操作所需要的辅助数组


2️⃣构造方法和成员方法


构造方法


Merge();


成员方法


  • public static void sort(Comparable[]a):对数组a中元素进行排序
  • public static void sort(Comparable[]a, int lo, int hi):对数组a中从索引lo到索引hi之间元素进行排序
  • public static void merge(Comparable[]a, int lo, int mid,int hi):数组a中从从索引 lo 到索引 min 为一个子数组,从索引 min+1 到索引 hi 为另一个子数组,把a中的两个子数组合并成一个大数组
  • public static boolean less(Comparable x, Comparable y):判断x是否小于y
  • public static void exch(Comparable[]a, int i, int j):交换数组a中下标为 i 和 j 的元素


3️⃣解题思路


1.定义并初始化一个辅助数组,来完成归并操作

2.定义并初始化数组的最小索引 lo最大索引 hi

3.调用一个方法对数组内元素进行排序后归并排序


4️⃣归并排序思路


1.定义三个"指针"p1、p2和 i,用来指向第一子数组的元素、第二子数组的元素和辅助数组的元素

2.比较p1和p2指向元素的大小,将较小的放入辅助数组中


26321235ae084d4e9191ccd05bb8376f.jpg


3.将刚才较小元素的索引值和辅助数组索引值都加1,

4.将指针指向新的元素值与另一个子数组内指针指向元素比较,并将较小的元素存放到辅助数组内

5.重复2-4的步骤,直至其中一个指针指向该子数组的最后一个元素为止


7d3efdcf41c24a4b814f6f2c6b7ecf95.png

579dfd4ad8fc43acb82d3a94a2361e1a.png

bac3a5d4167641d3a3cc4730552d3f53.png

3eb718997e3c4184ac135044a76b081c.png

d29713b098154e2fad01af01aa1b7046.png


6.当其中一个指针走完时,直接将另一个子数组中元素放入辅助数组中


4eda14f1aaf7457ca4e4837cca814f72.png


7.将排序完成的元素放回元素组中


362b816205614ca4842746e57f79f7b0.png


5️⃣归并排序代码实现


//定义一个归并排序的含参方法
public static void merge(Comparable[]a, int lo, int mid,int hi){
        int p1 = lo;//定义并初始化一个子数组的索引
        int p2 = mid + 1;//定义并初始化另一个子数组的索引
        int i = lo;//定义并初始化辅助数组的索引
        //当两个索引值都在索引范围内,将数值更小的元素放入辅助数组
        while (p1 <= mid && p2 <= hi){
            if(less(a[p1],a[p2])){
                assist[i++] = a[p1++];
            }
            else {
                assist[i++] = a[p2++];
            }
        }
        //当p2索引值超出索引范围时(即满足p1没有超出索引范围)
        while (p1 <= mid){
            assist[i++] = a[p1++];//将p1索引所对应剩下的元素复制到辅助数组中
        }
        //当p1索引值超出索引范围时(即满足p2没有超出索引范围)
        while (p2 <= hi){
            assist[i++] = a[p2++];//将p2索引所对应剩下的元素复制到辅助数组中
        }
        //将已排序的辅助数组赋值给原数组
        for(int index = lo; index <= hi; index++){
            a[index] = assist[index];
        }
    }


6️⃣完整代码


public class MergeSort {
    private static  Comparable[] assist;
    public static void sort(Comparable[] a){
        assist = new Comparable[a.length];
        int lo = 0;
        int hi = a.length-1;
        sort(a,lo,hi);//归并排序
    }
    public static void sort(Comparable[]a, int lo, int hi){
        if(hi <= lo){
            return;
        }
        int mid = lo + (hi-lo)/2;
        sort(a, lo, mid);//子数组排序
        sort(a, mid+1, hi);//子数组排序
        merge(a, lo, mid, hi);//合成有序的一个大数组
    }
    public static void merge(Comparable[]a, int lo, int mid,int hi){
        int p1 = lo;//定义并初始化一个子数组的索引
        int p2 = mid + 1;//定义并初始化另一个子数组的索引
        int i = lo;//定义并初始化辅助数组的索引
        //当两个索引值都在索引范围内,将数值更小的元素放入辅助数组
        while (p1 <= mid && p2 <= hi){
            if(less(a[p1],a[p2])){
                assist[i++] = a[p1++];
            }
            else {
                assist[i++] = a[p2++];
            }
        }
        //当p2索引值超出索引范围时(即满足p1没有超出索引范围)
        while (p1 <= mid){
            assist[i++] = a[p1++];//将p1索引所对应剩下的元素复制到辅助数组中
        }
        //当p1索引值超出索引范围时(即满足p2没有超出索引范围)
        while (p2 <= hi){
            assist[i++] = a[p2++];//将p2索引所对应剩下的元素复制到辅助数组中
        }
        //将已排序的辅助数组赋值给原数组
        for(int index = lo; index <= hi; index++){
            a[index] = assist[index];
        }
    }
    public static boolean less(Comparable x, Comparable y){
        return x.compareTo(y) < 0;
    }
}


🟡空间复杂度


  • 总共分为log8(底数为2)层,即log2(n)


  • 每一层都有2^k个元素(8,4,2)


  • 每个子数组的长度:2^(3-k)(0,2,4)


  • 归并最多需要次数:2^(3-k)


  • 每层归并需要的次数:每一层元素个数*每个子数组的长度:23 =8


  • 总次数:层数 * 每层归并需要的次数:3 * 23 ,即log2(n) * 2log2(n) = log2(n) * n


  • 所以时间复杂度为:O(nlogn)


🟡归并排序缺点


要开辟一个新空间,使得空间复杂度提高,典型的 以时间换空间


🟡结语


归并排序利用了分治思想和递归的思路,所以要先掌握这两个知识点才能掌握这种算法

相关文章
|
23天前
|
供应链 算法
【算法】——快排,分治算法合集
本文主要介绍排序中的快排思想的应用,做到一法通万法的效果
|
2月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
169 7
|
2月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
139 8
|
2月前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
71 2
|
3月前
|
搜索推荐 Shell
解析排序算法:十大排序方法的工作原理与性能比较
解析排序算法:十大排序方法的工作原理与性能比较
107 9
|
3月前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
65 1
|
3月前
|
算法 搜索推荐 Java
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
基数排序是一种稳定的排序算法,通过将数字按位数切割并分配到不同的桶中,以空间换时间的方式实现快速排序,但占用内存较大,不适合含有负数的数组。
49 0
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
|
3月前
|
算法
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
39 0
|
3月前
|
存储 搜索推荐 算法
【排序算法(二)】——冒泡排序、快速排序和归并排序—>深层解析
【排序算法(二)】——冒泡排序、快速排序和归并排序—>深层解析
|
3月前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
89 0

热门文章

最新文章