【数据结构与算法】归并排序详解:归并排序算法,归并排序非递归实现

一、归并排序

归并排序是一种经典的排序算法,它使用了分治法的思想。下面是归并排序的算法思想:

  1. 递归地将数组划分成较小的子数组,直到每个子数组的长度为1或者0。
  2. 将相邻的子数组合并,形成更大的已排序的数组,直到最终得到一个完全排序的数组。

归并排序的过程可以分为三个步骤:拆分(Divide)、合并(Merge)和排序(Sort)。

  1. 拆分:将待排序的数组不断地划分为两个子数组,直到每个子数组的长度为1或者0。
  2. 合并:将相邻的子数组合并为一个较大的已排序数组,通过比较两个子数组的首元素,按照从小到大的顺序逐个将元素放入一个辅助数组。
  3. 排序:重复进行合并的过程,直到最终得到完全排序的数组。

归并排序的时间复杂度为O(nlogn),其中n是待排序数组的长度。空间复杂度为O(n),主要是由于需要使用一个大小与原始数组相同的辅助数组来存储合并的结果。

归并排序是一种稳定的排序算法,即相等元素的相对顺序在排序前后保持不变。在合并的过程中,如果遇到两个相等的元素,我们会先将来自前一个子数组的元素放入辅助数组,这样可以确保相等元素的相对顺序不会改变。

代码实现:

// 归并排序具体功能实现函数
void MergeSortFun(int* a, int* temp, int begin, int end)
{
    // 如果数组大小为1或者空,直接返回上一层
    if (begin >= end)
    {
        return;
    }
    
    // 划分数组,递归调用 MergeSortFun 对左右子数组进行排序
    int mid = (begin + end) / 2;
    MergeSortFun(a, temp, begin, mid);
    MergeSortFun(a, temp, mid + 1, end);
    
    // 合并两个有序子数组
    int begin1 = begin;
    int end1 = mid;
    int begin2 = mid + 1;
    int end2 = end;
    int i = begin;
    
    // 依次比较两个子数组的元素,将较小的元素放入辅助数组 temp 中
    while (begin1 <= end1 && begin2 <= end2)
    {
        if (a[begin1] < a[begin2])
        {
            temp[i++] = a[begin1++];
        }
        else 
        {
            temp[i++] = a[begin2++];    
        }
    }
    
    // 将剩余的元素放入辅助数组 temp 中
    while (begin1 <= end1)
    {
        temp[i++] = a[begin1++];
    }
    while (begin2 <= end2)
    {
        temp[i++] = a[begin2++];
    }
    
    // 将辅助数组 temp 中的元素拷贝回原数组
    for (i = begin; i <= end; i++)
    {
        a[i] = temp[i];
    }
}

// 归并排序入口函数
void MergeSort(int* a, int n)
{
    int begin = 0;
    int end = n - 1;
    
    // 创建大小为 n 的辅助数组 temp
    int* temp = (int*)malloc(sizeof(int) * n);
    
    // 调用 MergeSortFun 对数组 a 进行归并排序
    MergeSortFun(a, temp, begin, end);
    
    // 释放辅助数组 temp 的内存空间
    free(temp);
}

二、归并排序非递归实现 

归并排序可以使用非递归的方式实现,其算法思想如下:

  1. 将待排序的数组划分为多个大小为1的子数组。
  2. 分别对这些子数组进行两两合并,形成新的有序子数组。
  3. 不断重复步骤2,直到得到一个有序的数组。

具体的非递归实现过程如下:

  1. 首先,定义一个大小为n的辅助数组temp用于存储合并后的有序子数组。
  2. 设置一个变量gap初始值为1,表示每次合并的两个子数组的大小。
  3. 进行多轮合并,直到gap大于等于n。
    • 在每一轮合并中,将数组分为多个大小为gap的子数组,将相邻的两个子数组合并为一个有序子数组。合并时,使用双指针i和j分别指向两个子数组的起始位置,比较两个子数组对应位置上的元素大小,较小的元素放入temp数组中,同时移动指针,直到一个子数组遍历完成。将未遍历完的子数组中剩余的元素直接放入temp数组中。
    • 更新gap的值为2倍,继续下一轮合并。
  4. 最后一轮合并时,gap可能大于n,因此需要额外的判断和处理。
  5. 将temp数组中的元素拷贝回原数组中。

通过不断调整gap的大小,将待排序数组进行分组和合并操作,直到得到一个完全有序的数组。非递归实现的归并排序避免了递归带来的额外开销,提高了算法的效率。、

 代码实现:

void mergesortnr(int* a, int* temp, int begin, int mid, int end)
{
    // 定义指针和索引
    int head1 = begin;
    int tail1 = mid;
    int head2 = mid + 1;
    int tail2 = end;
    int i = begin;

    // 合并两个有序子数组
    // [head1,tail1] 和 [head2,tail2] 归并
    while (head1 <= tail1 && head2 <= tail2)
    {
        // 比较两个子数组对应位置上的元素大小,较小的元素放入temp数组中
        if (a[head1] < a[head2])
        {
            temp[i++] = a[head1++];
        }
        else
        {
            temp[i++] = a[head2++];
        }
    }

    // 将第一个子数组中剩余的元素放入temp数组中
    while (head1 <= tail1)
    {
        temp[i++] = a[head1++];
    }

    // 将第二个子数组中剩余的元素放入temp数组中
    while (head2 <= tail2)
    {
        temp[i++] = a[head2++];
    }

    // 将temp数组中的元素拷贝回原数组中
    memcpy(a + begin, temp + begin, sizeof(int) * (end - begin + 1));
}

void MergeSortNR(int *a, int n) 
{
    // 创建辅助数组
    int* temp = (int*)malloc(sizeof(int) * n);
    int gap = 1;

    // 不断调整gap的大小,分组合并
    for (gap = 1; gap < n; gap *= 2)
    {
        // 对每一组进行合并
        for (int i = 0; i < n - gap; i += 2 * gap)
        {
            // 计算子数组的起始索引、中间索引和结束索引
            int begin = i;、
/*如果i + 2 * gap - 1大于等于数组长度n,说明当前的子数组已经超出了数组的范围,此时将结束索引end赋值为n - 1,即最后一个元素的索引。

如果i + 2 * gap - 1小于数组长度n,说明当前的子数组还在数组的范围内,此时将结束索引end赋值为i + 2 * gap - 1。*/
            int end = i + 2 * gap - 1 >= n ? n - 1 : i + 2 * gap - 1;
            int mid = i + gap - 1;

            // 调用mergesortnr函数合并子数组
            mergesortnr(a, temp, begin, mid, end);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/338044.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Android12】Android Framework系列---Adb和PMS安装apk源码流程

Adb和PMS安装apk源码流程 adb install命令 通过adb install命令可以将apk安装到Android系统&#xff08;注意&#xff1a;特定类型的apk&#xff0c;比如persist类型是无法通过adb安装的&#xff09; 下述命令中adb解析install命令&#xff0c;并调用Android PackageManagerS…

KAGGLE · GETTING STARTED CODE COMPETITION 图像风格迁移 示例代码阅读

本博文阅读的代码来自于I’m Something of a Painter Myself | Kaggle倾情推荐&#xff1a; Monet CycleGAN Tutorial | Kaggle 数据集说明 I’m Something of a Painter Myself | Kaggle Files monet_jpg - 300 Monet paintings sized 256x256 in JPEG formatmonet_tfrec -…

go语言(十一)----面向对象继承

一、面向对象继承 写一个父类 package mainimport "fmt"type Human struct {name stringsex string }func (this *Human) Eat() {fmt.Println("Human.Eat()...") }func (this *Human) Walk() {fmt.Println("Human.Walk()...") }func main() {h…

B(l)utter:一款针对Flutter移动端应用程序的逆向工程分析工具

关于B(l)utter B(l)utter是一款针对Flutter移动端应用程序的逆向工程分析工具&#xff0c;当前版本的B(l)utter仅支持Android libapp.so&#xff08;ARM64&#xff09;&#xff0c;可以帮助广大研究人员对基于Flutter开发的移动端应用程序进行逆向工程分析。 环境搭建 该应用…

dpdk网络转发环境的搭建

文章目录 前言ip命令的使用配置dpdk-basicfwd需要的网络结构测试dpdk-basicfwddpdk-basicfwd代码分析附录basicfwd在tcp转发时的失败抓包信息DPDK的相关设置 前言 上手dpdk有两难。其一为环境搭建。被绑定之后的网卡没有IP&#xff0c;我如何给它发送数据呢&#xff1f;当然&a…

全国各省市上市公司数量数据,Shp、excel格式,含上市企业数量、行政区划中心点位经纬度等字段

基本信息. 数据名称: 全国各省市上市公司数量数据 数据格式: Shp、excel 数据时间: 2023年1月 数据几何类型: 面 数据坐标系: WGS84 数据来源&#xff1a;网络公开数据 数据字段&#xff1a; 序号字段名称字段说明1province省份名称2provin_dm省份代码3city城市名…

学习CANopen --- [12] Abort报文

当我们使用SDO进行读写操作时&#xff0c;有时device会返回abort报文&#xff0c;意味着本次SDO读写失败。本文使用例子来讲解Abort报文&#xff0c;以及如何解读失败原因。 一 Device例子 下面是device的python代码&#xff0c;文件名叫device.py&#xff0c;device的CANopen…

02. VBA从入门到精通——基础语法

数据类型 常用数据类型 Integer&#xff1a;整数&#xff0c;-32,768到32,767之间的整数 Long&#xff1a;较长长整数&#xff0c;-2,147,483,648到2,147,483,647之间的整数 Single:浮点数&#xff0c;它可以存储大约&#xff1a;6到7位小数的精度。 Double&#xff1a;较长浮…

免费的WordPress插件大全

在当今数字化的时代&#xff0c;拥有一个强大的在线存在变得至关重要。而对于使用WordPress建站的用户来说&#xff0c;插件是提高网站功能的关键。在这篇文章中&#xff0c;我们将为您推荐三款免费的WordPress插件&#xff0c;它们不仅是147SEO软件中的佼佼者&#xff0c;而且…

【Leetcode】接雨水(双指针、单调栈)

目录 &#x1f4a1;题目描述 &#x1f4a1;双指针解法 &#x1f4a1;单调栈解法 &#x1f4a1;题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 提示&#xff1a; n height.length1 < n…

this.$set的用法

作用&#xff1a; 在data里面绑定的数据具有响应式的效果,也就是我们说的V-Model 数据更新视图,视图也能更新数据&#xff0c;如果不是data里面的数据如何添加响应式呢&#xff1f; this.$Set这个方法能够实现 用法&#xff1a; this.$Set(要添加的对象,要添加的属性’,要添…

为什么C++17要引入std::string_view?

目录 1.引言 2.原理分析 2.1.结构 2.2.构造函数 2.3.成员函数 2.4.std::string_view字面量 3.实例 3.1.std::string_view和std::string的运算符操作 3.2.查找函数使用 3.3.std::string_view和临时字符串 4.总结 1.引言 在C/C日常编程中&#xff0c;我们常进行数据的…

Offer必备算法_双指针_八道力扣OJ题详解(由浅到深)

目录 双指针算法原理 ①力扣283. 移动零 解析代码 ②力扣1089. 复写零 解析代码 ③力扣202. 快乐数 解析代码 ④力扣11. 盛最多水的容器 解析代码 ⑤力扣611. 有效三角形的个数 解析代码 ⑥剑指 Offer 57. 和为s的两个数字 解析代码&#xff1a; ⑦力扣15. 三数之…

最通俗易懂的JVM内存管理与对象创建原理

前言 对于Java程序员来说&#xff0c;在虚拟机自动内存管理机制的帮助下&#xff0c;不再需要像 C/C程序为每一个new操作去写配对 的delete/free代码&#xff0c;不容易出现内存泄漏和内存溢出问题。也正是因为Java程序员把控制内存的权力交给了Java虚拟机&#xff0c;一旦出现…

SpringMVC基础知识学习笔记

Universe Infinity Inc. 目录 一、学习SpringMVC主要是学什么1、SpringMVC的基本原理2、SpringMVC学习串联 二、快速体验SpringMVC的开发1、新建项目&#xff0c;转成web项目2、引入依赖3、编写Spring的配置类4、配置web启动类&#xff0c;替代web.xml5、编写Handler&#xff…

都在卷鸿蒙开发,那就推荐 几个鸿蒙开源项目

如果要问2024年最火的技术是什么,那鸿蒙开发必须占据一些位置,HarmonyOS是华为自主研发的物联网操作系统,自2019年8月正式发布以来便受到了广大开发者的追崇。为了方便大家学习鸿蒙开发,本文分享 12 个开源的鸿蒙实战项目,希望能从这些项目中获得启发和实用经验。 小狐浏…

IDEA的database使用

一、数据据库 在使用database之前&#xff0c;首先你的电脑要安装好了数据库并且启动。 MySQL卸载手册 链接&#xff1a;https://pan.baidu.com/doc/share/AVXW5SG6T76puBOWnPegmw-602323264797863 提取码&#xff1a;hlgf MySQL安装图解 链接&#xff1a;https://pan.baidu.…

Win10/11中VMware Workstation设置网络桥接模式

文章目录 一、添加VMware Bridge Protocol服务二、配置桥接参数1.启用系统Device Install Service服务2.配置VMware 需要确认物理网卡是否有添加VMware Bridge Protocol服务 添加VMware Bridge Protocol服务 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参…

艾比森的“增长炼金术”:从四力驱动到三层面增长

在技术驱动的LED显示行业&#xff0c;产品迭代快、周期波动大&#xff0c;企业经营时时承压。 但是&#xff0c;市场上总不乏打破“传统”的个例。根据2023年业绩预告&#xff0c;艾比森预计2023年实现归母净利润3.10亿-3.50亿元&#xff0c;同比增长52.70%-72.40%&#xff1b…

HttpServletRequest getServerPort()、getLocalPort() 、getRemotePort() 区别

getRemotePort() 、getServerPort()、getLocalPort() request.getServerPort()、request.getLocalPort() 和 request.getRemotePort() 这三个方法都是获取与HTTP请求相关的端口信息的 客户端(如浏览器)通过某个随机分配的网络连接端口(7070) 向服务器发送HTTP请求( http://exam…