首页 > 编程语言 >基础算法篇——归并排序

基础算法篇——归并排序

时间:2022-11-02 10:00:56浏览次数:52  
标签:归并 int arr System 算法 排序 out

基础算法篇——归并排序

本次我们介绍基础算法中的快速排序,我们会从下面几个角度来介绍快速排序:

  • 归并排序思想
  • 归并排序代码
  • 归并排序拓展

归并排序思想

我们首先来介绍归并排序思想(分治思想):

  1. 确定分界点
我们首先确定整个数组的分界点
以我们的习惯而言还是以arr[l],arr[r],arr[(r+l)/2]为分界点
  1. 递归排序
我们首先需要将数组分界点两侧进行分组,这时他们会划分为左侧和右侧
我们再对已经划分的左侧和右侧进行分界点分组,这时就会划分为4个分组
依次类推,直到每个分组数为1时结束分组,然后我们才会开始进行归并操作
  1. 归并数组
这个方法需要额外空间:我们需要一个新数组来装排序完成的数组
我们首先对最后一次分组的左右侧进行归并,将两组个数为1的分组化为一个排序整齐的组
依次类推,我们从开始的一个数为一组变为两个数为一组,逐渐归并,直到最后所有数都变为一组

至于归并的方法:
我们目前左右两侧的数组是顺序排列,我们只需要依次比较左右两侧最小数的大小
我们依旧采用指针的方法,左侧指向l,右侧指向mid+1,同时比较两者大小,将较小的数拿出来放在数组中,并且将指针向后移动一位

归并排序代码

我们这里给出归并排序的代码展示:

import java.util.Scanner;

public class Main {

    public static final int N = 10000010;

    // 额外空间数组:这里也可以在归并方法中设置,设置大小为r-l+1即可满足条件
    public static int[] tmp = new int[N];

    public static void main(String[] args) {

        // 给出数组

        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt();

        int[] arr = new int[n];

        for (int i = 0; i < arr.length; i++) {
            arr[i] = scanner.nextInt();
        }

        // 打印数组
        System.out.print("排序前:");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]);
        }
        System.out.println(" ");

        // 进行归并排序
        merge_sort(arr,0,n-1);

        // 打印数组
        System.out.print("排序后:");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]);
        }
        System.out.println(" ");

    }

    private static void merge_sort(int[] arr,int l,int r) {

        // 判断还存在数组?
        if (l >= r) return;

        // 设置中间值
        int mid = (l+r)/2;

        // 先进行排序
        merge_sort(arr,l,mid);
        merge_sort(arr,mid+1,r);

        // 对左右两侧进行判断

        // k是目前排序的数,i,j为左右两侧指针
        int k = 0;
        int i = l,j = mid + 1;

        // 比较判断
        while (i <= mid && j <= r){
            if (arr[i] < arr[j]){
                tmp[k++] = arr[i++];
            }else {
                tmp[k++] = arr[j++];
            }
        }

        // 判断左右剩余?然后累加在最后
        while (i <= mid){
            tmp[k++] = arr[i++];
        }
        while (j <= r){
            tmp[k++] = arr[j++];
        }

        // 最后赋值回去
        for (i = l, j = 0; i <= r;i++,j++){
            arr[i] = tmp[j];
        }
    }
}

归并排序拓展

题目:

  • 给定一个长度为n的整数数列,请你计算数列中的逆序对的数量

逆序对定义:

  • 对于数列的第 i 个和第 j 个元素,如果满足 i < j 且 a[i] > a[j],则其为一个逆序对;否则不是。

解题思路:

  • 我们采用分治的思想,使用归并排序将逆序对的数量统计分为三部分
  • 第一部分:左半边逆序对数量meger_sort(L,mid)
  • 第二部分:右半边逆序对数量meger_sort(mid+1,R)
  • 第三部分:左右两侧逆序对数量

解题要点:

  • 实际上我们的第一部分和第二部分的数量计算都是基于第三部分的逆序对统计,所以我们只需要思考第三部分的计算

解题方法:

  • 我们左右两侧的数都是按照顺序排列
  • 所以我们只需要按顺序将大于右侧某个数的左侧的第一个数找出来,然后该数后面的数都会大于右侧的数
  • 我们通过简单的计算可以得知,该数所对应的逆序对的个数为mid - i + 1

解题代码:

import java.util.Scanner;

public class mmm {

    private static final int N = 1000010;

    private static int[] tmp = new int[N];

    // 逆序对个数
    private static int result = 0;

    public static void main(String[] args) {
        
        // 基本归并框架

        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt();

        int[] arr = new int[n];

        for (int i = 0;i < arr.length;i++){
            arr[i] = scanner.nextInt();
        }

        System.out.print("排序前:");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]);
        }
        System.out.println("");

        merge_sort(arr,0,n-1);


        System.out.print("排序后:");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]);
        }
        System.out.println("");

        System.out.println("逆序对共" + result + "个");
    }

    private static void merge_sort(int[] arr,int l,int r) {

        if (l >= r) return;

        int mid = (l+r)/2;

        merge_sort(arr, l, mid);
        merge_sort(arr,mid+1,r);

        int k = 0;
        int i = l,j = mid+1;

        while (i <= mid && j<= r){
            if (arr[i] < arr[j]){
                tmp[k++] = arr[i++];
            }else {
                tmp[k++] = arr[j++];
                // 我们找到了右侧该数的针对左侧最小的大于该数的值,并根据其计算逆序对
                result += mid - i + 1;
            }
        }

        while (i <= mid){
            tmp[k++] = arr[i++];
        }
        while (j <= r){
            tmp[k++] = arr[j++];
        }

        for (i=l,j=0;i<=r;i++,j++){
            arr[i] = tmp[j];
        }
    }
}

结束语

好的,关于基础算法篇的归并排序就介绍到这里,希望能为你带来帮助~

标签:归并,int,arr,System,算法,排序,out
From: https://www.cnblogs.com/qiuluoyuweiliang/p/16850051.html

相关文章

  • 基础算法篇——快速排序
    基础算法篇——快速排序本次我们介绍基础算法中的快速排序,我们会从下面几个角度来介绍快速排序:快速排序介绍暴力求解算法快速排序算法快速排序代码快速排序问题快......
  • 代码随想录算法训练营第七天|454、四数相加Ⅱ|383、赎金信|15、三数之和|18、四数之和
    454、四数相加Ⅱ·map哈希表当初不知四数相加的好,做完四数之和发现~oh这题真简单题目链接:https://leetcode.cn/problems/4sum-ii/前提:计算四个数组中多少个元组满......
  • 如何实现一个LRU算法
    ​ 首先,什么是LRU算法呢?全称是:Leastrecentlyused,也就是最近最旧未被使用的算法。其核心思想就是:最近被访问到的数据,在未来也可能被访问到。 所以按照LRU算法来说,数......
  • 代码随想录算法训练营第六天| 242.有效的字母异位词,349. 两个数组的交集 ,202. 快乐数,1
    哈希表:用来快速判断一个元素是否出现在集合里 哈希表是根据关键码的值而直接进行访问的数据结构。(关键码也就是数组的下标,元素通过计算生成一个标识,此标识就是数组的下......
  • 基数排序
    基数排序基数排序(桶排序)介绍:基数排序(radixsort)属于“分配式排序”(distributionsort),又称“桶子法”(bucketsort)或binsort,顾名思义,它是通过键值的各个位的值,将要......
  • 数据结构 二叉排序树的代码实现
    7.8、二叉排序树(BST)二叉排序树又称二叉查找树左子树上所有结点的值都小于根结点的值右子树上所有结点的值都大于根结点的值左子树和右子树又是一颗二叉排序树左子树......
  • 数据结构 玩转数据结构 5-6 递归算法的调试
    0课程地址https://coding.imooc.com/lesson/207.html#mid=13442 1重点关注1.1递归算法的调试打印日志层级调试参考3.1 2课程内......
  • Java实现优化版【快速排序】+四度优化详解
    参考书目:《大话数据结构》一:快速排序1.基本思想:通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续......
  • 数据结构中的七大排序算法—2
        今天为大家带来的是数据结构中的七大排序算法的其中两种:希尔排序和堆排序。本次的代码实现还是使用的C语言,编译器还是vs2013版本,希望接下来的内容可以帮助大家理......
  • 双线性差值算法实现RGB图像缩放-C语言
    实现一:存在栈溢出的风险,来自:https://blog.csdn.net/wangjiannuaa/article/details/65980411/**@funcgif_get_scale_rgb2*@brief双线性差值算法......