排序算法——归并排序以及非递归实现

一、归并排序思想

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

我们现在要树立这么一个思路,分解数组并不是真的分解数组,而是可以通过下标的形式来区分数组。归并排序实际上就是将一个数组分解到不能子啊分解的部分,两两经行比较排序,再将数据更新到新的数组中去。这非常类似于我们学的数的后序遍历。

二、代码实现

1、单趟:

我们先写单趟,因为归并排序是对半分组,所以最后为两个区间经行比较,思路转化为之前我们学过的两个数组的合并

int mid = (rigt + left) / 2;
int begin1 = left;
int end1 = mid-1;
int begin2 = mid;
int end2 = rigt;
int i = left;
while (begin1 <= end1 && begin2 <= end2)
{if (a[begin1] > a[begin2]){tmp[i++] = a[begin2++];}else{tmp[i++] = a[begin1++];}
}
while (begin1<=end1)
{tmp[i++] = a[begin1++];
}
while (begin2 <= end2)
{tmp[i++] = a[begin2++];
}
memcpy(a+left, tmp+left, sizeof(int) * (rigt - left + 1));

这里要注意两个问题:1、区间怎么划分合适,2、为什么每排序一次就得将数组拷贝回去

 2、单趟问题解释

首先我们先解决第一个问题:区间怎么划分合适?

我们这里以下面图为例:

因为有-1的存在很容易导致下标为负数,最后导致数组的违法访问。同时可能还会有死循环的问题:

具体原因如下:

但是如果改为区间为 

int begin1 = left;
int end1 = mid;
int begin2 = mid+1;
int end2 = rigt;就不会出现这个问题:

所以正确代码如下:

int mid = (rigt + left) / 2;
int begin1 = left;
int end1 = mid;
int begin2 = mid+1;
int end2 = rigt;
int i = left;
while (begin1 <= end1 && begin2 <= end2)
{if (a[begin1] > a[begin2]){tmp[i++] = a[begin2++];}else{tmp[i++] = a[begin1++];}
}
while (begin1<=end1)
{tmp[i++] = a[begin1++];
}
while (begin2 <= end2)
{tmp[i++] = a[begin2++];
}
memcpy(a+left, tmp+left, sizeof(int) * (rigt - left + 1));

第二个问题:因为比较的时候是在原数组经行比较如果不及时将数组内容更新,可能会导致再排序时经行错误的大小比较,最后导致结果错误 

3、总体代码实现

结束条件当分割区间等于1或者小于1的时候。

void _MergeSort(int* a, int* tmp, int left, int rigt)
{if (left >= rigt){return;}int mid = (rigt + left) / 2;_MergeSort(a, tmp, left, mid);_MergeSort(a, tmp, mid + 1, rigt);int begin1 = left;int end1 = mid;int begin2 = mid+1;int end2 = rigt;int i = left;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] > a[begin2]){tmp[i++] = a[begin2++];}else{tmp[i++] = a[begin1++];}}while (begin1<=end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a+left, tmp+left, sizeof(int) * (rigt - left + 1));
}
void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){return;}else{_MergeSort(a, tmp, 0, n - 1);free(tmp);tmp = NULL;}
}

三、非递归

对于归并排序我们实现非递归用循环更好一点,非递归我们可以直接从递归回去那出发,定义一个组个数,通过控制组的个数实现“并”这个过程:

还是我们先写一个数组只有一个数的情况:

for (int i = 0; i < end - begin + 1; i += 2 * gap)//每次比较两组,所以加2gap
{int begin1 = i;int end1 = begin1 + gap - 1;int begin2 = begin1 + 2 * gap - 1;//第二组的开头与第一组的开头差2倍int end2 = begin2 + gap - 1;int k = i;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] > a[begin2]){tmp[k++] = a[begin2++];}else{tmp[k++] = a[begin1++];}}while (begin1 <= end1){tmp[k++] = a[begin1++];}while (begin2 <= end2){tmp[k++] = a[begin2++];}memcpy(a + i, tmp + i, sizeof(int) * (2 * gap));//同理这里也得排序一次就拷贝回去}

那么后面就是gap*2控制即可:

void _MergeSortNonR(int* a, int* tmp,int begin, int end)
{int gap = 1;for (int j = gap; j < end-begin+1; j *= 2){for (int i = 0; i < end - begin + 1; i += 2 * gap)//每次比较两组,所以加2gap{int begin1 = i;int end1 = begin1 + gap - 1;int begin2 = begin1 + 2 * gap - 1;//第二组的开头与第一组的开头差2倍int end2 = begin2 + gap - 1;int k = i;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] > a[begin2]){tmp[k++] = a[begin2++];}else{tmp[k++] = a[begin1++];}}while (begin1 <= end1){tmp[k++] = a[begin1++];}while (begin2 <= end2){tmp[k++] = a[begin2++];}memcpy(a + i, tmp + i, sizeof(int) * (2 * gap));}}
}

但是上面的代码仍然存在问题,和快排类似这里会存在数组越界问题:这里我们打印数组下标区间来观察一下:、

大致我们可以分为这两种情况:

 如果end1越界,那么说明分为了只有这一组数据,不用排了直接跳出循环,如果end2越界我们就需要给end2修改值。

所以改进代码如下:

void _MergeSortNonR(int* a, int* tmp,int begin, int end)
{int gap = 1;for (int j = gap; j < end-begin+1; j *= 2){for (int i = 0; i < end - begin + 1; i += 2 * gap)//每次比较两组,所以加2gap{int begin1 = i;int end1 = begin1 + gap - 1;int begin2 = begin1 + 2 * gap - 1;//第二组的开头与第一组的开头差2倍int end2 = begin2 + gap - 1;int k = i;// 第二组都越界不存在,这一组就不需要归并if (begin2 >= end - begin + 1)break;// 第二的组begin2没越界,end2越界了,需要修正一下,继续归并if (end2 >= end - begin + 1)end2 = end - begin + 1 - 1;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] > a[begin2]){tmp[k++] = a[begin2++];}else{tmp[k++] = a[begin1++];}}while (begin1 <= end1){tmp[k++] = a[begin1++];}while (begin2 <= end2){tmp[k++] = a[begin2++];}memcpy(a + i, tmp + i, sizeof(int) * (2 * gap));}}
}
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){return;}else{_MergeSortNonR(a, tmp, 0, n - 1);free(tmp);tmp = NULL;}
}

可能有人会想如果只剩一组数据了,我直接return行不行?实际上是可以的,因为break跳出循环后在gap*2还是只有一组数据,所以直接return即可。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

重新ysyx

一、克隆仓库 1.创建ssh key ssh-keygen -t rsa cd ~/.ssh ls 查看里面是否有id_rsa id_rsa.pub ssh-keygen -t rsa -C "xiantong15834753336outlook.com" cat id_rsa.pub***********查看里面的内容&#xff0c;复制到下图中绿色的按钮 git init ssh -T g…

Marin说PCB之Max parallel知多少?

今天是个阳光明媚&#xff0c;万里乌云的好日子。小编我一如既往地到家打开电脑准备看腾讯视频的五十公里桃花坞的第四季&#xff0c;在看到汪苏泷汪台说650电台要解散的时候小编我差点也哭了。650电台之于桃花坞就像乐队的鼓手一样&#xff0c;都是一个团队的灵感啊&#xff0…

C语言分支和循环(2)

我的相关博客&#xff1a; C语言的分支与循环&#xff08;1&#xff09; 1.switch语句 除了 if 语句外&#xff0c;C语⾔还提供了 switch 语句来实现分⽀结构。 switch 语句是⼀种特殊形式的 的 if...else 结构&#xff0c;⽤于判断条件有多个结果的情况。它把多重 else if…

亿发:制造型企业信息化规划——从破冰到全面落地

在制造型企业中&#xff0c;信息化规划的落地是一个复杂而关键的过程。尽管规划和蓝图可能已经制定完毕&#xff0c;但如何成功地实施信息化才是关键所在。本文将详细介绍制造型企业信息化规划的落地过程&#xff0c;通过三个周期逐步推进&#xff0c;最终实现信息化与自动化的…

深度学习知识与心得

目录 深度学习简介 传统机器学习 深度学习发展 感知机 前馈神经网络 前馈神经网络&#xff08;BP网络&#xff09; 深度学习框架讲解 深度学习框架 TensorFlow 一个简单的线性函数拟合过程 卷积神经网络CNN&#xff08;计算机视觉&#xff09; 自然语言处理NLP Wo…

OpenAI助手API接入-问答对自动生成

支持GPT-3.5-Turbo, GPT-4o, GPT-4-Turbo import json import openai from pathlib import Path import os client openai.OpenAI(base_urlbase_url, api_keyapi_key) file client.files.create( fileopen("H3.pdf", "rb"), purposeassistants ) …

成功解决“ModuleNotFoundError: No Module Named ‘utils’”错误的全面指南

成功解决“ModuleNotFoundError: No Module Named ‘utils’”错误的全面指南 在Python编程中&#xff0c;遇到ModuleNotFoundError: No Module Named utils这样的错误通常意味着Python解释器无法找到名为utils的模块。这可能是由于多种原因造成的&#xff0c;比如模块确实不存…

念念不忘,必有回响 的 echo

念念不忘&#xff0c;必有回响 的 echo 念念不忘&#xff0c;必有回响 的 echo几个示例更多信息 念念不忘&#xff0c;必有回响 的 echo echo命令用于在终端设备上输出字符串或变量的值&#xff0c;类似于Python的print和C语言的printf&#xff0c;是Linux系统中最常用的命令…

深度学习笔记:0.cuda安装,成功

B站上说&#xff1a;cs上骗子太多。文章太久&#xff0c;我深以为然。用了一天。才装好。其实很简单。 CUDA安装教程&#xff08;超详细&#xff09;-CSDN博客文章浏览阅读1w次&#xff0c;点赞5次&#xff0c;收藏56次。windows10 版本安装 CUDA &#xff0c;首先需要下载两个…

【并发程序设计】总篇集(八万字)

11_Concurrent_Programing 1.进程概念 在Linux中&#xff0c;进程是操作系统分配资源和调度运行的基本单位。 Linux中的进程有以下用处&#xff1a; 提高CPU利用率&#xff1a;通过进程的并发执行&#xff0c;可以让多个程序同时利用计算机的资源&#xff0c;这样每个用户都…

部署metrics-server

kubeadm部署metrics-server 需求&#xff1a;生产环境是kubeadm部署的v1.22.2版本的k8s&#xff0c;统计资源时发现这套环境没有部署metrics-server这个服务&#xff0c;今天来部署一下 1、在github社区找到这个项目并下载 rootjumpserver-cmcc:~# wget https://github.com/…

你需要知道关于 Java 线程一些最基本的事情

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

《SpringBoot3+Vue3实战》系列文章目录

前后端分离&#xff08;Frontend-Backend Separation&#xff09;是一种软件架构设计模式&#xff0c;它将传统的Web应用中的前端&#xff08;用户界面&#xff09;和后端&#xff08;服务器逻辑和数据存储&#xff09;从应用层面进行解耦&#xff0c;使得两者可以独立地开发、…

Linux CFS调度器简介

文章目录 前言一、概要二、实现2.1 简介2.2 算法实现2.3 内核源码 三、特点四、调度策略五、调度类参考资料 前言 早期的Linux调度器采用了简化的设计&#xff0c;显然并不针对具有许多处理器甚至超线程的大规模架构。Linux 1.2调度器使用循环队列对可运行任务进行管理&#x…

昆仑万维官宣开源2000亿稀疏大模型Skywork-MoE

6月3日&#xff0c;昆仑万维宣布开源2千亿稀疏大模型Skywork-MoE&#xff0c;性能强劲&#xff0c;同时推理成本更低。 据「TMT星球」了解&#xff0c;Skywork-MoE基于之前昆仑万维开源的Skywork-13B模型中间checkpoint扩展而来&#xff0c;是首个完整将MoE Upcycling技术应用…

北京Profinet转Modbus网关配置调试详解

一、背景&#xff1a;在工业自动化系统中&#xff0c;PLC&#xff08;可编程逻辑控制器&#xff09;与流量计之间的通信是非常重要的&#xff0c;以确保数据准确传输并实现控制功能。然而&#xff0c;由于PLC和流量计可能采用不同的通信协议&#xff08;如Profinet和Modbus&…

探索Java的DNA-JVM字节码深度解析

引言 在Java的世界里&#xff0c;JVM&#xff08;Java虚拟机&#xff09;是我们程序运行的心脏。而字节码&#xff0c;作为JVM的血液&#xff0c;携带着程序的执行指令。今天&#xff0c;我们将深入探索Java字节码的奥秘&#xff0c;一窥JVM如何将人类可读的代码转化为机器可执…

【小白向】微信小程序解密反编译教程

# 前言 最近笔者有做到微信小程序的渗透测试&#xff0c;其中有一个环节就是对微信小程序的反编译进行源码分析&#xff0c;所谓微信小程序反编译&#xff0c;就是将访问的小程序进行反向编译拿到部分源码&#xff0c;然后对源码进行安全审计&#xff0c;分析出其中可能存在的…

图形学初识--颜色混合

文章目录 前言正文为什么要有颜色混合&#xff1f;颜色混合常见实现方式&#xff1f;上述颜色混合注意点 结尾&#xff1a;喜欢的小伙伴点点关注赞哦! 前言 本章节补充一下颜色混合的内容&#xff0c;主要包含&#xff1a;为什么要有颜色混合&#xff1f;颜色混合常实现方式&a…

Centos 7 安装刻录至硬件服务器

前言 在日常测试中&#xff0c;会遇到很多安装的场景&#xff0c;今天给大家讲一下centos 7 的安装&#xff0c;希望对大家有所帮助。 一.下载镜像 地址如下&#xff1a; centos官方镜像下载地址https://www.centos.org/download/ 按照需求依次点击下载 二.镜像刻录 镜像刻…