详解八大排序(四)------(归并排序)

文章目录

  • 前言:
  • 1 递归版本(MergeSort)
    • 1.1 核心思路
    • 1.2 实现代码
  • 2 非递归版本(MergeSortNonR)
    • 2.1 核心思路
    • 2.2 实现代码
  • 3.完整代码

前言:

归并排序的核心思路是把数组里面的数两两分成一组,组内比较完大小之后,再把组外的融合进组内进行比较。
以下两个版本的核心思路也是这样。只是分组的方法不同。

1 递归版本(MergeSort)

1.1 核心思路

递归版本利用递归的思路,来实现对数组的分组。

在这里插入图片描述

以上述待排序数组为例。将第一个数定义为left,最后一个数定义为right,再将(left + right)/ 2定义为mid。
以mid为中心,把数组分为[left,mid][mid + 1,right]两个数组。得到:

在这里插入图片描述

重复上面的步骤,再次二分。得到:

在这里插入图片描述

将数组分成剩下2个数时,开始比较。从第一个数组开始比较,也就是[6,1]。比较完成后,再将[2,7]与第一个数组融合,再次进行比较。得到:

在这里插入图片描述

重复上面的步骤,将第一个数组的内容比较完成,再将第二个数组与第一个数组融合。得到:

在这里插入图片描述

继续重复上面的步骤,直到数组排序完成。得到:

在这里插入图片描述

1.2 实现代码

// 归并排序递归实现
void _MergeSort(int* arr, int left, int right, int* tmp)
{if (left >= right)//递归终止的信号---当数组里只剩下一个数时,就应该返回递归{return;}int mid = (left + right) / 2;//定义mid_MergeSort(arr, left, mid, tmp);//数组二分之后,先从左边接着二分_MergeSort(arr, mid + 1, right, tmp);//左边二分完成后,再看数组的右边int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int index = begin1;//运用双指针的思维,来对数组进行排序while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2]){tmp[index++] = arr[begin1++];}else {tmp[index++] = arr[begin2++];}}//循环退出,说明begin1和begin2有一个大于end2//另一个没有比较完while (begin1 <= end1){tmp[index++] = arr[begin1++];}while (begin2 <= end2){tmp[index++] = arr[begin2++];}//收尾工作,确保两个组都能比较完for (int i = left; i <= right; i++){arr[i] = tmp[i];}//把比较好的数放回原数组。本来上述程序比较好的数本来放在tmp这个临时数组
}//核心思路是把数组分成两个数一组,一组一组比较,比较完再把下一个组融合进来比较
void MergeSort(int* arr, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);_MergeSort(arr, 0, n - 1, tmp);free(tmp);
}

2 非递归版本(MergeSortNonR)

2.1 核心思路

非递归版本的核心思路就是利用区间的思维,来对数组进行区间的划分。

在这里插入图片描述

以上述数组为例。已知数组的大小为7。那么可以将区间的划分次数定义为n / 3 + 1。也就是3次。定义一个gap = 1。每次比较完,gap都会 *= 2。直到gap > n。再定义一个i,i是确保能把数组的比较数量。得到:

在这里插入图片描述

i是数组比较的区间。我们第一次比较是在区间[0,2),比较完成后,再比较区间[2,4),再比较[4,6)。直到数组里所有成员两两比较完之后。得到:

在这里插入图片描述

此时进入下一个gap,也就是gap = 2。重新开始比较。得到:

在这里插入图片描述

此时,再次比较数组里的成员。得到:

在这里插入图片描述

这里比较完成,再把数组合在一起进行比较。得到:

在这里插入图片描述

剩下的就是对整个数组进行比较。得到最终排序好的数组:

在这里插入图片描述

2.2 实现代码

// 归并排序非递归实现
void MergeSortNonR(int* arr, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);for (int gap = 1; gap < n; gap *= 2)//将数组的区间划分成gap组{int index = 0;for (int i = 0; i < n; i += 2 * gap)//确保比较的成员是从两两开始的{int begin1 = i, end1 = i + gap;int begin2 = i + gap, end2 = i + 2 * gap;if (end1 > n) break;if (end2 > n) end2 = n;//end1 和 end2 的定义存在越界的风险,所以在开始比较之前,确认end1 和 end2 没有越界//双指针法进行比较并记录在tmp中while (begin1 < end1 && begin2 < end2){if (arr[begin1] < arr[begin2]){tmp[index++] = arr[begin1++];}else{tmp[index++] = arr[begin2++];}}//循环结束,说明此时begin1和begin2有一个等于end//确保begin1和begin2能比较完所有的数while (begin1 < end1){tmp[index++] = arr[begin1++];}while (begin2 < end2){tmp[index++] = arr[begin2++];}//将比较好的数从tmp中移植到原数组arrfor (int j = i; j < end2; j++){arr[j] = tmp[j];}}}free(tmp);tmp = NULL;
}

3.完整代码

#include<stdio.h>
#include<stdlib.h>
void Swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}//打印函数
void PrintArr(int* arr,int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}// 归并排序递归实现
void _MergeSort(int* arr, int left, int right, int* tmp)
{if (left >= right)//递归终止的信号---当数组里只剩下一个数时,就应该返回递归{return;}int mid = (left + right) / 2;//定义mid_MergeSort(arr, left, mid, tmp);//数组二分之后,先从左边接着二分_MergeSort(arr, mid + 1, right, tmp);//左边二分完成后,再看数组的右边int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int index = begin1;//运用双指针的思维,来对数组进行排序while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2]){tmp[index++] = arr[begin1++];}else {tmp[index++] = arr[begin2++];}}//循环退出,说明begin1和begin2有一个大于end2//另一个没有比较完while (begin1 <= end1){tmp[index++] = arr[begin1++];}while (begin2 <= end2){tmp[index++] = arr[begin2++];}//收尾工作,确保两个组都能比较完for (int i = left; i <= right; i++){arr[i] = tmp[i];}//把比较好的数放回原数组。本来上述程序比较好的数本来放在tmp这个临时数组
}//核心思路是把数组分成两个数一组,一组一组比较,比较完再把下一个组融合进来比较
void MergeSort(int* arr, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);_MergeSort(arr, 0, n - 1, tmp);free(tmp);
}// 归并排序非递归实现
void MergeSortNonR(int* arr, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);for (int gap = 1; gap < n; gap *= 2)//将数组的区间划分成gap组{int index = 0;for (int i = 0; i < n; i += 2 * gap)//确保比较的成员是从两两开始的{int begin1 = i, end1 = i + gap;int begin2 = i + gap, end2 = i + 2 * gap;if (end1 > n) break;if (end2 > n) end2 = n;//end1 和 end2 的定义存在越界的风险,所以在开始比较之前,确认end1 和 end2 没有越界//双指针法进行比较并记录在tmp中while (begin1 < end1 && begin2 < end2){if (arr[begin1] < arr[begin2]){tmp[index++] = arr[begin1++];}else{tmp[index++] = arr[begin2++];}}//循环结束,说明此时begin1和begin2有一个等于end//确保begin1和begin2能比较完所有的数while (begin1 < end1){tmp[index++] = arr[begin1++];}while (begin2 < end2){tmp[index++] = arr[begin2++];}//将比较好的数从tmp中移植到原数组arrfor (int j = i; j < end2; j++){arr[j] = tmp[j];}}}free(tmp);tmp = NULL;
}int main()
{//int arr[] = { 5,2,7,8,1,3,9,4,6 };int arr[] = { 4,2,1,8,5,6,9,5 };//int arr[] = { 2,3,6,5 };int sz = sizeof(arr) / sizeof(int);printf("排序前:");PrintArr(arr, sz);//MergeSort(arr, sz);MergeSortNonR(arr, sz);printf("排序后:");PrintArr(arr, sz);return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

商城小程序的流程渠道拓展

传统印象里&#xff0c;小程序的开发制作似乎很难&#xff0c;尤其是商城类型且功能体系完善的&#xff0c;事实也确实如此&#xff0c;没有较高的技术和成本投入或团队各个流程的专业人员合作&#xff0c;很难开发出来成品&#xff0c;或者质量较低。 当然对于大公司来说&…

小程序-基于java+SpringBoot+Vue的超市购物系统设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

Android开发-Pokémon界面设计

实现效果图&#xff0c;还没更新完 二、功能说明&#xff1a; 在上次实验的基础之上把recycleviewb列表完善并且增加点击效果&#xff0c;点击之后可以跳转到另外一个activity上&#xff0c;并且添加返回按钮&#xff0c;可以放回原列表页面&#xff0c;列表中的每一行都对应的…

jenkins的安装(War包安装)

‌Jenkins是一个开源的持续集成工具&#xff0c;基于Java开发&#xff0c;主要用于监控持续的软件版本发布和测试项目。‌ 它提供了一个开放易用的平台&#xff0c;使软件项目能够实现持续集成。Jenkins的功能包括持续的软件版本发布和测试项目&#xff0c;以及监控外部调用执行…

HopToDesk 安全加密、免费开源,远程桌面新选择!

远程桌面工具越来越成为现代工作生活的刚需。你是否还在为寻找一个既安全又免费的工具而苦恼&#xff1f;HopToDesk&#xff0c;一款支持安全加密、免费开源的远程桌面软件&#xff0c;或许正是你的不二之 HopToDesk与传统的远程桌面工具相比有哪些独特优势&#xff1f;它如何…

yum工具的学习

Linux下安装软件的方法 1.源代码安装 2.rmp包安装 3.包管理器进行安装 --- yum/apt Linux下载软件的过程 操作系统的好坏评估 -- 生态问题 yum具体操作 Linux软件安装所有人都能用&#xff0c;是以other的身份去执行可执行程序 文件拷贝&#xff08;sudo&#xff09;-- &g…

react 如何修改弹出的modal的标题

原来标题的样子&#xff1a; 修改为&#xff1a; 实现方式&#xff1a; <Modal title<span>股价趋势/{this.state.pccode}</span> visible{this.state.isPriceModalOpen} style{{ top: 20 }} width{1320} height{400} footer{null} onCancel{()>this.hideMo…

计算机网络-理论部分(一):概览

重点 计算机网络的重点是协议&#xff0c;各种协议&#xff0c;每种协议都有自己对应的应用场景以及对应功能&#xff0c;学好协议&#xff0c;就学好了计算机努网络。 协议分层 协议分层围绕数据的传递展开。数据的传递需要包括&#xff1a;打包数据&#xff0c;控制传递&a…

开源科学工程技术软件介绍 – EDA工具KLayout

link 今天向各位知友介绍的 KLayout是一款由德国团队开发的开源EDA工具。 KLayout是使用C开发的&#xff0c;用户界面基于Qt。它支持Windows、MacOS和Linux操作系统。安装程序可以从下面的网址下载&#xff1a; https://www.klayout.de/build.html KLayout图形用户界面&…

SpringMVC的视图

目录 一.视图分类 &#xff08;1&#xff09;转发视图&#xff08;Forward View&#xff09;&#xff1a; &#xff08;2&#xff09;重定向视图&#xff08;Redirect View&#xff09;&#xff1a; &#xff08;3&#xff09;其他视图技术 二.转发视图 三.重定向视图 四…

Spring IOCDI

1. 什么是Spring 前面介绍了Spring Boot&#xff0c;Spring MVC&#xff0c;那么Spring和他们之间有什么关系呢&#xff1f; Spring简单一句话总结就是&#xff1a;它是一个包含众多工具方法的IOC容器。前面我们也接触过容器&#xff0c;比如List/Map&#xff0c;他俩是数据存…

螺旋矩阵II(leetcode 59)

转圈过程&#xff08;边界处理&#xff09;遵循循环不变量的原则&#xff0c;坚持一个原则处理每一条边&#xff0c;左闭右开处理 class Solution { public:vector<vector<int>> generateMatrix(int n) {vector<vector<int>> num(n, vector<int>…

Vue 中的透传,插槽,依赖注入

1. 透传attributes 在组件上使用透传attribute&#xff1a; 当你在父组件中使用子组件时&#xff0c;你可以添加一些attribute到子组件上&#xff0c;即使这些attribute没有在子组件的props中声明。 父组件&#xff1a; <!-- 父组件&#xff0c;例如 ParentComponent.vue…

基于K8S1.28.2实验rook部署ceph

基于K8S1.28.2实验rook部署ceph 原文链接&#xff1a; 基于K8S1.28.2实验rook部署ceph | 严千屹博客 Rook 支持 Kubernetes v1.22 或更高版本。 rook版本1.12.8 K8S版本1.28.2 部署出来ceph版本是quincy版本 主机名ip1(NAT)系统新硬盘磁盘内存master1192.168.48.101Centos7.910…

node.js中express的基本了解

定义 Express是基于Node.js平台&#xff0c;快速、开放、极简的Web开发框架。 本质 Express是一个npm上的第三方包&#xff0c;提供了快速创建Web服务器的便捷方法。 作用 与Node.js内置的http模块类似&#xff0c;Express也是专门用来创建Web服务器的&#xff0c;但它极大地简…

容器运行时 AND Docker

容器运行时 and Docker 什么是Docker Docker 使用 Google 公司推出的 Go 语言 进行开发实现&#xff0c;基于 Linux 内核的 cgroup&#xff0c;namespace&#xff0c;以及 AUFS 类的 Union FS 等技术&#xff0c;对进程进行封装隔离&#xff0c;属于 操作系统层面的虚拟化技术…

基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络

一、介绍 垃圾识别分类系统。本系统采用Python作为主要编程语言&#xff0c;通过收集了5种常见的垃圾数据集&#xff08;‘塑料’, ‘玻璃’, ‘纸张’, ‘纸板’, ‘金属’&#xff09;&#xff0c;然后基于TensorFlow搭建卷积神经网络算法模型&#xff0c;通过对图像数据集进…

Scala-数据类型-概述(Scala 3.x 类型层次结构)

Scala Scala-数据类型 Scala1. Any — 顶级类型2. Matchable — 匹配类型3. AnyVal — 值类型的父类4. AnyRef — 引用类型的父类5. Null - 引用类型的子类型Tips: 为什么 null 不推荐使用&#xff1f; 6. Nothing - 底层类型 (Bottom Type)整理不易&#xff0c;对您有帮助的话…

Linux:权限相关知识详解

1.shell命令以及运行原理 1.1初步理解认识shell Linux严格意义上说的是一个操作系统&#xff0c;我们称之为“核心&#xff08;kernel&#xff09;“ &#xff0c;但我们一般用户&#xff0c;不能直接使用kernel。而是通过kernel的“外壳”程序&#xff0c;也就是所谓的shell&…

React中常用的钩子

在当今&#xff0c;React的钩子写法已经逐渐成为了一种主流开发模式&#xff0c;本文将介绍几种在React中常用的钩子 useState 可以用来双向绑定&#xff0c;创建需要监听变化并且使用的数据 使用该钩子定义时&#xff0c;参数可以是一个直接定义好的变量&#xff0c;也可以是…