首页 > 编程语言 >排序算法-归并排序

排序算法-归并排序

时间:2023-04-16 13:23:12浏览次数:32  
标签:归并 递归 nums int 算法 序列 排序 left

归并排序Merge Sort

归并排序.gif

1. Merge Sort介绍

Merge Sort是利用归并的思想实现的排序算法,该算法采用经典的分治策略(divide-and-conquer),是一种稳定的排序算法。分治法是将问题分(divide)为一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各个答案“修补”在一起,即分而治之。归并排序对待排序序列的元素进行逐层折半分组,然后从最小分组开始比较排序合并成一个大的分组,逐层进行,最终使得所有元素都是有序的。

Merge Sort的基本思想是:递归地将原始序列对半分割,直至不能再分割(即只剩下一个元素时),开始从最小的序列向上合并排序。

  • 首先将待排序序列从中间位置(mid = (left + right) / 2)的位置拆开,拆分为两个,并通过递归逐层拆分
  • 分别从左右子序列中选择较小的元素放入到建立的临时空间temp,并移动下标到下一位置
  • 重复上一步骤直至左子序列或右子序列中的某一下标达到末尾;
  • 另一序列剩余的元素依次放入临时空间temp
  • 将临时空间temp的数据依次放入原序列中。
归并排序思想.png

1.2 图解说明Merge Sort步骤

举一个例子来具体说明Merge Sort的过程。给出一个无序数列:8,4,5,7,1,3,6,2使用归并排序将其排列成一个从小到大的有序数列。

归并排序分阶段.png
  1. 分解的过程通过递归的方式进行,定义left,mid,right三个变量,分别表示序列的头部中间尾部位置。每一次递归都是将原来的mid作为新的right向左递归分解原来的mid + 1作为新的left向右递归分解,直至left >= right时递归终止
归并排序分阶段回溯.png
  1. 向左递归left == right时分离出第一个单独的元素(即nums[0] == 8),此时进行第一次回溯退回到上一轮继续执行向右递归,分离出第二个单独的元素(即nums[1] == 4),此时执行合并操作将nums[0]和nums[1]进行排序并合并。
  2. “治”的过程需要将两个有序的子序列合并成一个有序序列,也即如上一步中所述,在每一次左右递归结束后将左右两个子序列进行排序并合并,然后回溯到上一轮继续执行递归分解。此过程中需要定义一个临时空间,合并的结果先放入临时空间,再赋值给原nums序列的相应位置。下图为了方便仅演示最后一次合并的过程。
归并排序治阶段.png 归并排序治阶段2.png

1.3 代码实现

package com.algorithm;

import java.util.Arrays;

/**
 * @author SnkrGao
 * @create 2023-04-15 20:10
 */
public class MergeSort {

    public static void main(String[] args) {
        int[] nums = {6,5,3,1,8,7,2,4};
        System.out.println("排序前的数组为:");
        System.out.println(Arrays.toString(nums));

        mergeSort(nums, 0, nums.length - 1);

        System.out.println("排序后的数组为:");
        System.out.println(Arrays.toString(nums));
    }

    public static void mergeSort(int[] nums, int left, int right) {
        if (left >= right) { // 递归终止条件
            return;
        }

        int mid = (left + right) / 2; // 定义中间位置index
        mergeSort(nums, left, mid); // 向左递归分解
        mergeSort(nums, mid + 1, right); // 向右递归分解

        // 每一次左右递归结束后将左右两个子序列合并
        merge(nums, left, mid, right);
    }

    public static void merge(int[] nums, int left, int mid, int right) {
        // 定义一个临时空间,用于存放合并的结果
        // 注意temp的长度并非固定,而是根据每次要合并的序列长度决定
        int[] temp = new int[right - left + 1];
        int tempLeft = left; // 用于在左子序列移动的左指针
        int tempMid = mid + 1; // 用于在右子序列移动的右指针
        int index = 0; // temp的当前位置索引

        // 从两个子序列中选择最小的放入temp,并移动相应的指针,直至有一个序列处理完毕全部放入temp中
        while (tempLeft <= mid && tempMid <= right) {
            temp[index++] = nums[tempLeft] <= nums[tempMid] ? nums[tempLeft++] :nums[tempMid++];
        }

        // 若左子序列仍有剩余,全部依次放入temp
        while (tempLeft <= mid) {
            temp[index++] = nums[tempLeft++];
        }

        // 若右子序列仍有剩余,全部依次放入temp
        while (tempMid <= right) {
            temp[index++] = nums[tempMid++];
        }

        // 将temp赋值给原序列nums的相应位置
        for (int i = 0; i < temp.length; i++) {
            nums[i + left] = temp[i];
        }
    }
}

1.4 Merge Sort时间复杂度分析

Merge Sort每次都将待排序序列折半分组,其时间复杂度可以用递归树来求解,共需要\(logn\)轮。

最坏情况时间复杂度:O(\(nlogn\))

平均时间复杂度:O(\(nlogn\))

标签:归并,递归,nums,int,算法,序列,排序,left
From: https://www.cnblogs.com/SnkrGao/p/17323139.html

相关文章

  • 算法-二叉树的构造
    namespaceBinary;publicclassBinaryTree{publicNode<char>Head{get;privateset;}privatestringcStr{get;set;}publicBinaryTree(stringconstructStr){this.cStr=constructStr;th......
  • 【LBLD】带权重的随机选择算法
    带权重的随机选择算法528.按权重随机选择不使用二分法:classSolution{private:vector<int>preSum;intN=0;public:Solution(vector<int>&w){srand(time(0));preSum.push_back(0);for(inti=1;i<=w.size();i++){......
  • Java中常用排序算法及示例-冒泡排序、希尔排序、选择排序、插入排序、合并排序、基数
    场景Java中需要对数据进行排序处理,常用的排序算法以及示例进行归纳整理。注:实现1、冒泡排序冒泡排序法又称为交换排序法,原理是从第一个元素开始,比较相邻元素的大小,若大小顺序有误,则对调后再进行下一个元素的比较。如此扫描一次之后就可以确保最后一个元素位于正确的顺序,接着逐步进......
  • Java中常用算法及示例-分治、迭代、递归、递推、动态规划、回溯、穷举、贪心
    场景1、分治算法的基本思想是将一个计算复杂的问题分成规模较小、计算简单的小问题求解,然后综合各个小问题,得到最终答案。2、穷举(又称枚举)算法的基本思想是从所有可能的情况中搜索正确的答案。3、迭代法(IterativeMethod)无法使用公式一次求解,而需要使用重复结构(即循环)重复执......
  • C++冒泡排序简单讲解
    什么是冒泡排序冒泡排序(BubbleSort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢......
  • 算法-回文链表-24
    /***Definitionforsingly-linkedlist.*publicclassListNode{*publicintval;*publicListNodenext;*publicListNode(intx){val=x;}*}*/publicclassSolution{publicListNodeReverseList(ListNodehead){i......
  • 期望最大化算法(EM)简介
    ExpectationMaximization,EM算法是带有隐变量的概率模型参数的极大似然估计(MLE为给定参数,观测数据出现/生成的可能性)。如下为《统计机器学习》中对应EM算法的笔记。观测数据Y和隐变量X合称,完全数据观测数据Y称,不完全数据E步:(期望步)求Q函数(上一轮参数固定,模型参数为变量的......
  • 加密算法
    #include<stdio.h>#include<stdlib.h>#include<stdint.h>#include<string.h>#include<openssl/rsa.h>#include<openssl/err.h>#include<openssl/objects.h>#pragmacomment(lib,"libssl.lib")#pragmac......
  • 24、桶排序
    1、MSD与Bucket2、桶排序原理......
  • 二叉树遍历算法分析
    二叉树遍历算法分析前/中/后序遍历算法可以发现这三种遍历算法只有一行代码,也就是输出结点数据域的位置不同前序遍历是先输出数据域再递归到左孩子和右孩子中序遍历是先递归到左孩子等返回的时候输出数据域再递归到右孩子后序遍历是指先递归到左孩子,然后递归到右孩子,最后......