当前位置: 首页 > article >正文

数据结构:排序—归并排序(四 )

一、归并排序

基本思想:归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

基本思路:根据上述的说法,我们要将一组数据分成一个一个的子序列,然后让这些子序列有序,最后将这些有序的子序列合并,并将他排序,形成一个有序的序列。

我们要将一组数据分成子序列,而当我们把这组数据都分成一个一个的单个数据的时候,我们发现他一定是有序的。这时我们就可以进行两组之间的合并了,对于他们的合并,我们完全可以根据我们要合并数据的个数创建一个数组,并将数据进行排序,按照从小到大的顺序放入数组中,在这样的不断重复的过程中我们就实现了归并排序。

分割方法:我们先创建两个指针,分别指向一组数据的头和尾,然后我们按照对半的方式得到中间结点mid,然后再利用递归的方式分割左右两边,每次传入新的头和尾,左边的头尾分别为left和mid,右边的头尾分别为mid+1和right

排序方法:我们先要根据传入数据的头和尾,根据他们的差值+1得到要创建数组的长度,然后再创建五个指针,k作为指针指向数组下标),s1(指向left),e1(指向中间结点mid),s2(指向中间结点mid+1处),e2(指向right),此时我们发现我们的s1和e1就是,我们左边的第一个数据和最后一个数据,s2和e2就是,我们右边边的第一个数据和最后一个数据,而我们知道左边和右边已经是有序的了,如果s1的值比s2小,我们就将s1的值放入数组中,并让s1和k向后移动一位,如果s2的值比s1小,我们就将s2的值放入数组中并让s2和k向后移动一位。如果移动完后发现一边已经都进入数组中了即s1和s2的指向超过了e1和e2,我们就将另一边的剩余数据放入数组中。最后我们循环这个数组,更新临时数组的数据,为了防止每次递归,后更新的是同一个位置,我们要将原数组的下标更新位置设置为i+left,这样就能防止更新的是同一个位置。

  public static void mergeSort(int[] arr){
        mergeSortChild(arr,0,arr.length-1);
    }

    public static void mergeSortChild(int[] arr, int left, int right) {
        if(left >= right){
            return;
        }
        int mid = (left+right)/2;
        mergeSortChild(arr,left,mid);
        mergeSortChild(arr,mid+1,right);
        merge(arr,left,right,mid);
    }

    public static void merge(int[] arr,int left,int right,int mid){
        int[] keyArr = new int[right-left+1];
        int k = 0;
        int s1 = left;
        int e1 = mid;
        int s2 = mid+1;
        int e2 = right;
        while(s1 <= e1 && s2<= e2){
            if(arr[s1] < arr[s2]){
                keyArr[k++] = arr[s1++];
            }else{
                keyArr[k++] = arr[s2++];
            }
        }
        while(s1 <= e1){
            keyArr[k++] = arr[s1++];
        }
        while(s2 <= e2){
            keyArr[k++] = arr[s2++];
        }
        for (int i = 0; i < keyArr.length; i++) {
            arr[i+left] = keyArr[i];
        }
    }

二、归并排序的非递归实现

基本思路:我们可以先让一组数据,一个一个的有序(gap= 1),然后再让他们两个两个的有序(gap=2),最后如果我们的gap>arr.length了就代表我们的数组已经有序了。因此我们可以利用一个循环,我们还是要的到一个中间位置而这个中间位置就等于left + gap - 1,每次left = i,right= mid+gap每次合并排位两组数后我们要让i跳到跳到另一边因此要i +=gap*2。

public static void merge(int[] arr,int left,int right,int mid){
        int[] keyArr = new int[right-left+1];
        int k = 0;
        int s1 = left;
        int e1 = mid;
        int s2 = mid+1;
        int e2 = right;
        while(s1 <= e1 && s2<= e2){
            if(arr[s1] < arr[s2]){
                keyArr[k++] = arr[s1++];
            }else{
                keyArr[k++] = arr[s2++];
            }
        }
        while(s1 <= e1){
            keyArr[k++] = arr[s1++];
        }
        while(s2 <= e2){
            keyArr[k++] = arr[s2++];
        }
        for (int i = 0; i < keyArr.length; i++) {
            arr[i+left] = keyArr[i];
        }
    }

    //归并排序非递归
    public static void mergeSortNor(int[] arr) {
        int gap = 1;
        while (gap < arr.length) {
            for (int i = 0; i < arr.length; i += 2 * gap) {
                int left = i;
                int mid = left + gap - 1;
                if (mid >= arr.length) {
                    mid = arr.length - 1;
                }
                int right = mid + gap;
                if (right >= arr.length) {
                    right = arr.length - 1;
                }
                merge(arr, left, right, mid);
            }
            gap *= 2;
        }
    }

好了,今天的分享就到这里了,还请大家多多关注,我们下一篇见!


http://www.kler.cn/a/542641.html

相关文章:

  • 2025.2.8——二、Confusion1 SSTI模板注入|Jinja2模板
  • 防火墙安全综合实验
  • 网络工程师 (31)VLAN
  • 跨平台开发利器:UniApp 全面解析与实践指南
  • (篇六)基于PyDracula搭建一个深度学习的软件之新版本ultralytics-8.3.28调试
  • JavaScript 在 VSCode 中的优势与应用
  • 矩阵 NFC 碰一碰发视频源码搭建技术解析,支持OEM
  • STM32 HAL库 PWM程序(C语言)
  • 【02】RUST项目(Cargo)
  • 第六篇:数字逻辑的“矩阵革命”——域控制器中的组合电路设计
  • 如何将网站提交百度收录完整SEO教程
  • Ubuntu 安装 NVIDIA 驱动实操指南(含卸载)
  • 【pytest】获取所有用例名称并存于数据库
  • python tkinter实现deepseek的连接访问
  • 新一代高性能无线传输模块M-GATEWAY3
  • Flink-序列化
  • 生产环境超实用Shell脚本三
  • JAVA (Springboot) i18n国际化语言配置
  • JVM 中的各种收集器总结
  • 为什么用源码搭建体育比分直播系统更高效
  • 线上HBase client返回超时异常分析 HBase callTimeout=60000
  • Docker 安装指南:Windows、Mac、Linux
  • Java+vue前后端分离项目集群部署
  • Redis集群的拓扑常用的几种
  • springcloud html5
  • 堆排序