归并排序

剖析递归行为和递归行为时间复杂度

master公式

归并排序

1)就是一个简单的递归,左边排好序,右边排好序,让其整体有序。
2)分治算法,先分,再合

在这里插入图片描述
已知数组[3,4,5,7,9.6,2,1]
在这里插入图片描述
首先将数组拆分,得到多干个长度为2的数组,首先比较左边部分第一个分裂点。

将数组按照mid切割,一个从左端0出发一个从mid+ 1出发,比较谁小就复制谁,3比4小 ,拷贝3,继续走发现3再走就超过mid了要越界了,跳出循环。
把4那一半全部拷贝下来。3 4 依然是3 4

在这里插入图片描述
将数组按照mid切割,一个从左端0出发一个从mid+ 1出发,比较谁小就复制谁,5比7小 ,拷贝5,继续走发现5再走就超过mid了要越界了,跳出循环。
把4那一半全部拷贝下来。5 7依然是5 7

在这里插入图片描述
分裂点结果合并。
将数组按照mid切割,一个从左端L出发一个从mid+ 1出发,比较谁小就复制谁,3比5小 ,拷贝3,L + 1,4和5比,4小,拷贝4,然后发现L继续向右走就超过mid了要越界了,跳出循环。
把mid + 1 到R那一半全部拷贝下来。3 4 5 7依然是3 4 5 7

在这里插入图片描述
比较右边部分第一个分裂点。
接下来就进行比较了
将数组按照mid切割,一个从左端0出发一个从mid+ 1出发,比较谁小就复制谁,6比9小 ,拷贝6,继续走发现6越界了,跳出循环。
直到一个过界了,把9那一半全部拷贝下来。9 6 变成6 9

在这里插入图片描述
比较右边部分第二个分裂点。
接下来就进行比较了
将数组按照mid切割,一个从左端0出发一个从mid+ 1出发,比较谁小就复制谁,1比2小 ,拷贝1,继续走发现1越界了,跳出循环。
直到一个过界了,把2那一半全部拷贝下来。2 1 变成 1 2

在这里插入图片描述
合并结果
将数组按照mid切割,一个从左端0出发一个从mid+ 1出发,比较谁小就复制谁,1比6小 ,拷贝1,L继续向右走发现2 比9小拷贝2,接着L打算向右走发现超过mid了越界了,跳出循环。
把6 9 那一半全部拷贝下来。12 6 9 仍为1 2 6 9

在这里插入图片描述

合并结果
将数组按照mid切割,一个从左端0出发一个从mid+ 1出发,比较谁小就复制谁,1比3小 ,拷贝1,mid + 1 继续向右走发现2 比3小拷贝2,接着mid + 1 发现3 比 6 小向L 右走,拷贝3,L向右走发现4 比6小,拷贝4,L向右走,5比6小,拷贝5,L向右走7比6大,拷贝6,6向右走发现7比9小,拷贝7,L向右走,发现再有 就超过mid了越界了,跳出循环。

1   2  3   4   5   6    7   9

排好序了。

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



  private static void mergeSort(int[] arr, int L, int R) {
        int mid = L + (R - L) / 2;
        int k = mid + 1;
        int i = L;
        int[] temp = new int[R - L + 1];
        int size = 0;
        while (k <= R && i <= mid) {
            if (arr[k] < arr[i]) {
                temp[size++] = arr[k++];
            } else {
                temp[size++] = arr[i++];
            }
        }

        while (k <= R) {
            temp[size++] = arr[k++];
        }

        while (i <= mid) {
            temp[size++] = arr[i++];
        }
        System.arraycopy(temp, 0, arr, L, temp.length);
    }

归并排序的思想延申问题

  1. 小和问题,在一个数组中,每一个数左边比当前数小的数添加起来,叫做这个数组的小和,求一个数组的小和。例子:[1,3,4, 2,5]左边比1小的数没有,3左边比3小的数1,4 左边比4小的数1,3,2,2 左边比2小的数1,5左边比1的数,1、3、4,所以小和1 +1 + 3 + 1 + 1+ 3 + 4 + 2 =16。左数比当前数小的数累加起来,可以理解为右数有几个比我大的与我相乘的和
private static int minorSum(int[] arr, int L, int R) {
        if (L == R) {
            return 0;
        }
        int mid = L + (R - L) / 2;
        return minorSum(arr, L, mid) +
                minorSum(arr, mid + 1, R) + sumLargerNum(arr,L, R);
    }

private static int sumLargerNum(int[] arr, int L, int R) {
        int mid = L + (R - L) / 2;
        int p = L;
        int p1 = mid + 1;

        int i = 0;
        int ret = 0;
        int[] temp = new int[R - L + 1];
        while (p <= mid && p1 <= R) {
            //小和运算,左边有多少个数比我小的累加之和等价于是右边有多少个比当前数大的数*当前数
            //如果当前p2比我大,p2往后直到R都比p大
            if (arr[p1] > arr[p]) {
                ret += arr[p] * (R - p1 + 1);
                temp[i++] = arr[p++];
            } else {
                temp[i++] = arr[p1++];
            }
        }
        while (p <= mid) {
            temp[i++] = arr[p++];
        }
        while (p1 <= R) {
            temp[i++] = arr[p1++];
        }
        System.arraycopy(temp, 0, arr, L, temp.length);
        return ret;
    }

逆序对问题

什么是逆序对?
如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 且 A[i] > A[j], 则 <A[i], A[j]> 这个有序对, 称为A的一个逆序对, 也称作逆序数。

数组a:2,3,8,6,1
从左边第一个数开始向右逐个数遍历,第一和第五个数可以组成一个逆序对<2,1>,即1<5,a[1]>a[5]。数组a共有5个逆序对,分别是:<2,1>   < 3, 1>   <8, 6> <8, 1> <6, 1>

在一个数组中,左边的数比右边的数大,则这两个数构成逆序对,请打印所有逆序对。

 private static int countReverse(int[] arr, int L, int R) {
        if (L == R) {
            return 0;
        }
        int mid = L + (R - L) / 2;
        return countReverse(arr, L, mid) +
                countReverse(arr, mid + 1, R) + reverse(arr,L, R);
    }

 private static int reverse(int[] arr, int L, int R) {
        int mid = (R - L) / 2 + L;
        int p = L;
        int p1 = mid + 1;
        int[] temp = new int[R - L + 1];
        int count = 0;
        int i = 0;
        while (p <= mid && p1 <= R) {
            //左边的数比右边的数大,则左半拉到mid都比右面这个p1值要大
            if (arr[p] > arr[p1]) {
                count += (mid - p + 1);
                temp[i++] = arr[p1++];
            } else {
                temp[i++] = arr[p++];
            }
        }

        while (p <= mid) {
            temp[i++] = arr[p++];
        }
        while (p1 <= R) {
            temp[i++] = arr[p1++];
        }

        System.arraycopy(temp, 0, arr, L, temp.length);
        return count;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值