归并排序

归并排序与原地归并排序 归并排序的思想:假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2]个长度为2或1的有序子序列;再两两归并,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2-路归并排序。其核心操作是将一个一维数组的前后相邻的两个子序列合并为一个有序序列。下图为一个2路归并排序的例子。 阅读详情

归并排序:

和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(n log n)的时间复杂度。代价是需要额外的内存空间。

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序是一种稳定的排序方法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

算法描述

  • 把长度为n的输入序列分成两个长度为n/2的子序列;

  • 对这两个子序列分别采用归并排序;

  • 将两个排序好的子序列合并成一个最终的排序序列。

递归方法:

package com.zy.base.class003;

public class Code01_MergeSort {
    public static void main(String[] args) {
        int[] arr = {10, 2, 5, 6, 1, 3, 9};
        new Code01_MergeSort().mergeSort(arr);
        System.out.println();
    }
    public static void mergeSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        procss(arr, 0, arr.length - 1);

    }

    private static void procss(int[] arr, int start, int end) {
        if (start == end) {
            return;
        }
        int mid = start + (end - start) / 2;
        procss(arr, start, mid);
        procss(arr, mid + 1, end);
        merge(arr, start, mid, end);
    }

    private static void merge(int[] arr, int start, int mid, int end) {
        int[] helper = new int[end - start + 1];
        int left = start;
        int right = mid + 1;
        int helperIndex = 0;
        while (left <= mid && right <= end) {
            helper[helperIndex++] = arr[left] <= arr[right] ? arr[left++] : arr[right++];
        }

        while (left <= mid) {
            helper[helperIndex++] = arr[left++];
        }

        while (right <= end) {
            helper[helperIndex++] = arr[right++];
        }

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

非递归方法:

package com.zy.base.class003;

public class Code01_MergeSort1 {
    public static void main(String[] args) {
        int[] arr = {10, 2, 5, 6, 1, 3, 9};
        new Code01_MergeSort1().mergeSort(arr);
        System.out.println();
    }

    public static void mergeSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        procss(arr, 0, arr.length - 1);
    }

    private static void procss(int[] arr, int start, int end) {
        if (start == end) {
            return;
        }
        int len = arr.length;
        int mergeSize = 1;
        while (mergeSize < len) {
            int left = 0;
            while (left < len) {
                int m = left + mergeSize - 1;
                if (m >= len) {
                    break;
                }
                int right = Math.min(m + mergeSize, len - 1);
                merge(arr, left, m, right);
                left = right + 1;
            }
            if (mergeSize > len / 2) {
                break;
            }
            mergeSize <<= 1;
        }



    }

    private static void merge(int[] arr, int start, int mid, int end) {
        int[] helper = new int[end - start + 1];
        int left = start;
        int right = mid + 1;
        int helperIndex = 0;
        while (left <= mid && right <= end) {
            helper[helperIndex++] = arr[left] <= arr[right] ? arr[left++] : arr[right++];
        }

        while (left <= mid) {
            helper[helperIndex++] = arr[left++];
        }

        while (right <= end) {
            helper[helperIndex++] = arr[right++];
        }

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

常见面试题:

在一个数组中,一个数左边比它小的数的总和,叫数的小和,所有数的小和累加起来,叫数组小和。求数组小和。

例如:[1, 3, 4, 2, 5]

1左边比1小的数:

3左边比3小的数:1

4左边比4小的数:1、3

2左边比2小的数:1

5左边比5小的数:1、3、4、2

所以数组的小和为1+1+3+1+1+3+4+2=16

上代码:

package com.zy.base.class003;

public class Code02_SmallSum {
    public static void main(String[] args) {
        int[] arr = {1, 3, 4, 2, 5};
        int i = Code02_SmallSum.smallSum(arr);
        System.out.println(i);
    }
    public static int smallSum(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }
        return process(arr, 0, arr.length - 1);
    }

    private static int process(int[] arr, int left, int right) {
        if (left == right) {
            return 0;
        }
        int mid = left + (right - left) / 2;
        return process(arr, left, mid) + process(arr, mid + 1, right) + merge(arr, left, mid, right);
    }

    private static int merge(int[] arr, int start, int mid, int end) {
        int[] helper = new int[end - start + 1];
        int res = 0;
        int left = start;
        int right = mid + 1;
        int helperIndex = 0;
        while (left <= mid && right <= end) {
            res += arr[left] < arr[right] ? (end - right + 1) * arr[left] : 0;
            helper[helperIndex++] = arr[left] < arr[right] ? arr[left++] : arr[right++];
        }
        while (left <= mid) {
            helper[helperIndex++] = arr[left++];
        }
        while (right <= end) {
            helper[helperIndex++] = arr[right++];
        }

        for (int i = 0; i < helper.length; i++) {
            arr[start + i] = helper[i];
        }
        return res;
    }
}

求逆序对

剑指 Offer 51. 数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

 

示例 1:

输入: [7,5,6,4]
输出: 5
 

限制:

0 <= 数组长度 <= 50000

package com.zy.offer;

/**
 * 剑指 Offer 51. 数组中的逆序对
 * 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
 *
 *
 *
 * 示例 1:
 *
 * 输入: [7,5,6,4]
 * 输出: 5
 *
 *
 * 限制:
 *
 * 0 <= 数组长度 <= 50000
 */
public class Offer51 {
    public int reversePairs(int[] nums) {
        if (nums == null || nums.length < 2) {
            return 0;
        }
        return process(nums, 0, nums.length - 1);

    }

    private int process(int[] nums, int start, int end) {
        if (start == end) {
            return 0;
        }
        int mid = start + (end - start) / 2;

        return process(nums, start, mid) + process(nums, mid + 1, end) + merge(nums, start, mid, end);

    }

    private int merge(int[] nums, int start, int mid, int end) {
        int[] help = new int[end - start + 1];
        int left = start;
        int right = mid + 1;
        int index = 0;
        int res = 0;
        while (left <= mid && right <= end) {
            res += nums[left] > nums[right] ? (mid - left + 1) : 0;
            help[index++] = nums[left] > nums[right] ? nums[right++] : nums[left++];
        }
        while (left <= mid) {
            help[index++] = nums[left++];
        }

        while (right <= end) {
            help[index++] = nums[right++];
        }

        for (int i = 0; i < help.length; i++) {
            nums[start + i] = help[i];
        }
        return res;
    }
}

 

 

 

 

 

 

《恋上数据结构与算法》排序(五):归并排序 转载自 : https://blog.youkuaiyun.com/weixin_43734095/article/details/105127138 相关 : https://juejin.cn/post/6844904094235426830 一、经典十大排序算法 前言 请务必看一下这个:排序算法前置知识+代码环境准备。 当上面的内容都准备好以后,那就开始归并排序吧! 归并排序 归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策. 阅读详情

相关推荐

AD620仪表放大器模块实战:从双电源切换到单电源供电的完整指南(附原理图)

本文深入探讨了AD620仪表放大器模块从双电源切换到单电源供电的常见陷阱与正确方案。通过解析AD620的内部架构与电气特性,指出其“天生”依赖双电源,简单的跳线改装会导致芯片损坏或失效。文章提供了基于AD623芯片的真正单电源替代方案,并附有原理图与实战波形对比,为便携式设备设计提供了完整指南。

weixin_29231027的博客 368

算法16:LeetCode_归并排序_相关面试题 (超难)

假设初始序列含义n个记录,则可以看成是n个有序子序列,每个序列的长度为1,然后两两归并,得到【n/2】([x]表示不小于x的最小整数)个长度为2或1的有序咨询;1. 普通两层遍历肯定是可以解出这道题的,但是两层遍历的时间的复杂度是O(N^2). 而归并排序的时间复杂度是 N*logN, 性能上更优。思考: 面试题一是最小和,假设数组为 {5,2,3,4,1},而你使用降序,猜猜得到的最小和会是多少?在一个数组中,一个数左边比它小的数的总和,叫数的小和,所有数的小和累加起来,叫数组小和。

街头小瘪三的专栏 937

Python爬虫(一)京东商品价格及详情页抓取

这是一个以http://item.jd.com/2957726.html为例的单网页抓取案例 import urllib.request; #载入urllib.request,用于获取页面html源代码 from pandas import Series; #载入series包 from pandas import DataFrame; #载入dataframe包 from bs4 impo

Data Proc 1万+

归并排序(MergeSort) Java实现及解析

package class03; public class Code01_MergeSort { // 递归方法实现 public static void mergeSort1(int[] arr){ if(arr == null || arr.length < 2){ return; } process(arr, 0, arr.length - 1); } // 递归函数的定义:让arr在[L

HLComet_Bay_WC的博客 2191

SPL06气压温度传感器SPI驱动与补偿算法详解

气压传感器与温度传感器是嵌入式环境感知系统的核心组件,其测量精度高度依赖于MEMS芯片的校准参数与非线性补偿机制。SPL06作为集成式高精度数字传感器,采用24位Σ-Δ ADC与片内补偿引擎,需结合唯一出厂校准系数(即‘芯片指纹’)进行多阶数学修正,才能将原始ADC值转化为符合计量要求的帕斯卡(Pa)与摄氏度(℃)物理量。该过程涵盖SPI通信协议解析、寄存器时序控制、大端数据拼接、二进制补码处理及浮点/定点混合运算等典型嵌入式工程实践。广泛应用于无人机高度计、智能穿戴海拔监测与IoT气象终端中。

weixin_34640289的博客 143

价值投资/指标选股(akshare)

利用akshare的数据源,可以获取所有的股票数据以及公开的财务数据,可以进行条件筛选,获取满足条件的股票。 这套模板可以用于价值投资,指标选股。选股周期为日线级别。然后结果可以邮箱发送。 import time import akshare as ak ## A 股上市公司的实时行情数据 stock_zh_a_spot_df = ak.stock_zh_a_spot() #print(stock_zh_a_spot_df) ##取前300测试 ##取前300测试 df_stock =...

qq_26742269的博客 1万+

归并排序详解

摘要:归并排序是我们常用的八大排序中的一种,其排序思路中和快速排序算法一样使用到了递归的思想,同时在归并排序中还用到了一个算法,就是有序数组合并算法。配合递归与有序数组合并算法,归并排序能够高效且稳定的完成排序,归并排序的优点在于其时间复杂度低,稳定性高,但是缺点也是有的,那就是空间复杂度很高。

云杉木屋 2万+

MultiOTP Credential Provider避坑指南:从安装到RDP双因素认证的全流程解析

本文详细解析了MultiOTP Credential Provider从安装到实现RDP双因素认证(MFA)的全流程,重点分享了Docker部署、Active Directory集成及网络级认证(NLA)兼容性等环节的实战避坑经验,旨在帮助运维人员高效、稳定地部署离线双因素认证方案,提升Windows远程桌面安全性。

weixin_29255731的博客 642

常见排序算法之归并排序——归并排序

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

保护小周ღ的博客 2403

【OS】AUTOSAR OS Alarm实现原理

AUTOSAR OS Alarm实现原理

qq_36056498的博客 1022

第03章 Hermes Agent 核心原理

环境跑通之后,读者会很自然地想问:Hermes 的内部到底是怎么转起来的?为什么它能做到"越用越聪明"?长对话不会忘记上下文吗?这一章用尽量短的篇幅把核心原理讲清楚。理解原理不是为了纸上谈兵,而是为了在第7章实战时能判断"为什么 Hermes 这么响应"以及"我应该把哪类任务交给它"。

亢少军的博客 141

归并排序与自然归并排序

1.归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题2.时间复杂度:O(N * logN)3.空间复杂度:O(N)4.稳定度:稳定.1.这玩意的思路相比于其它排序其实特别恶心,在生产环境中非常不建议使用,你的项目组成员可能会骂街(除非是这种情况:就比如你的数据结构老师心血来潮让你讲这个,那你也没办法...)2.时间复杂度:遍历了一次:O(n)3.空间复杂度:O(n)

asdssadddd的博客 1145

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

归并排序-自底向上的归并排序算法

归并排序 归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 算法描述 分解: 将原序列分解成length长度的若干子序列 求解子问题: 将相邻的两个子序列调用Merge算法合并成一个有序子序列 合并: 由于整个序列存放在数字a中,排序过程是就地进行的,合并步骤不需要执行

qq_45727976的博客 2990

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

归并排序的一些拓展应用

归并排序的一些拓展问题, 包含小和问题, 逆序对问题, 翻转对问题, 区间和的个数问题.

trong_ 的烂笔头 870

排序算法 归并排序(普通归并排序、自然归并排序)

自然归并排序:对于初始给定的数组,通常存在多个长度大于1的已自然排好序的子数组段.例如,若数组a中元素为{4,8,3,7,1,5,6,2},则自然排好序的子数组段有{4,8},{3,7},{1,5,6},{2}.用一次对数组a的线性扫描就足以找出所有这些排好序的子数组段.然后将相邻的排好序的子数组段两两合并,构成更大的排好序的子数组段({3,4,7,8},{1,2,5,6}).继续合并相邻排好序的子数组段,直至整个数组已排好序。(1)申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列。

qq_36511401的博客 1万+

归并排序及模板

文章目录归并排序理解归并排序模板 归并排序理解 归并排序的主要操作如下: (1)分解。把初始序列分成长度相同的左、右两个子序列,然后把每个子序列再分成更小的两个子序列,直到子序列只包含一个数。这个过程用递归实现。 (2)求解子问题,对子序列排序。最底层的子序列只包含一个数,其实不用排序。 (3)合并。归并两个有序的子序列,这是归并排序的主要操作。比如下面举例,把a[ ]分成两个子序列,比较后存进b...

ker的博客 2050

链表的归并排序

链表的归并排序是一种高效、稳定的排序算法,非常适合链表这种数据结构。通过分治思想,将链表不断分割并合并,实现了对链表的排序。

2401_86909484的博客 1173

数组排序之归并排序

归并排序(Merge Sort)是数组排序算法中一种常见的算法,其主要思想为经典的“分治思想”。本文将介绍数组排序算法中的归并排序,并介绍其相关应用。

山阴少年 2486

归并排序算法、多路归并排序

base case:if(left>=right) return; 归并排序左半边,归并排序右半边,合并 void merge_sort(vector<int> &nums,vector<int> reg,int start,int end){ if(start>=end) return ; int mid=(end-start)/2+start; int start1=start,end1=mid; int start2=mid+

大灰狼吃树皮 4002

C++ 归并排序

归并排序的原理: (1)首先,把一个数组以中间元素为界限分成两组; (2)然后“左边数组”和“右边数组”中的元素分别进行比较; (3)最后合并两个已经排好顺序的数组,我们称之为归并排序。 #include &lt;iostream&gt; #include &lt;stdlib.h&gt; using namespace std; /**************************...

辛旭东小小工作室 1316
上一篇: 设计模式之模板方法模式
下一篇: 快速排序
给自己加加油
博客等级 码龄8年 302粉丝 110原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值