C语言,谁都能看得懂的归并排序

喜欢看排序算法动态效果的,可以看看这个网站

https://visualgo.net/zh/sorting

里面很多算法的动画解释,可以看到算法的排序效果,而且还附带了伪代码的实现过程。

本来想录制几张动图放上来,但是因为图片较大,传不上来,公众号对动态图片有限制,喜欢的同学可以点击我上面的链接,自己去尝试一下。

我画了一个图片,用来表示归并排序的运算过程

排序的过程

先把需要排序的数据分成两份。

把两份的数据依次进行排序并组合在一起。

再把排序后的两组数据进行并入一起排序。

好了,写代码吧

我们先实现,「把两份的数据依次进行排序并组合在一起

下面是实现这个的算法过程

/** r[] : 需要排序的数组* s[] : 排序后保存数据的数组* left: 排序的起始位置* mid : 排序的中间位置* right:排序的最右边位置*/
int merge(int r[],int s[],int left,int mid,int right)
{int i,j,k;i=left;j=mid+1;k=left;for(;i <= mid && j<=right;){if(r[i]<=r[j])s[k] = r[i++];elses[k] = r[j++];k++;}for(;i<=mid;)s[k++]=r[i++];for(;j<=right;)s[k++]=r[j++];return 0;
}

如果我们对两个数进行排序

经过上面的那个函数排序后,我们会把[3,1]排序成[1,3]。

——

那,如果我们需要对4个数字进行排序呢?

我们需要先把4个数字分成2组

然后,我们需要依次对上面的两组数据进行排序,得到下面新的两组数据

然后,我们需要把已经排序的两个数组进行排序

s[] 是保存的排序结果,r[] 是需要排序的数组。

left,mid,right 是排序数组中的三个位置。

left = 0;

right = 3;

mid = ( left + right )/2 = 1;

进入函数体,我们需要三个变量来协助我们进行运算

i = left = 0;

j = mid +1 = 1 +1 = 2;

k = left = 0;

它们看起来是这样子的

把r[i] 和 r[j] 两个数进行比较,把小的那个数放到s[k] 里面,然后再移位

比较之后变成

然后再执行下面的代码

for(;i <= mid && j<=right;){if(r[i]<=r[j])s[k] = r[i++];elses[k] = r[j++];k++;
}

这时候 j = 4

这时候就退出了 for 循环

退出for 循环后 就开始执行下面的 for 循环

 for(;i<=mid;)s[k++]=r[i++];for(;j<=right;)s[k++]=r[j++];

这样后,会变成这样

这样就退出 merge 函数

经过上面的过程,我们需要应该有点悟性,我们需要使用递归来解决这些问题

可以看下面的文章了解啥是递归

C 语言,你真的懂递归了吗?

然后呢,我们就写了一个这样的递归函数,放心吧,在学习树的时候,也是需要这种递归操作的。

/** r[] : 需要排序的数组* s[] : 排序后保存数据的数组* left: 排序的起始位置* right:排序的最右边位置*/
int merge_sort(int r[],int s[],int left,int right)
{int mid;int t[20];if(left==right)s[left]=r[right];else{mid=(left+right)/2;merge_sort(r,t,left,mid);/*sort left~mid*/merge_sort(r,t,mid+1,right);/*sort mid+1~right*/merge(t,s,left,mid,right);/*merge sort left,mid,right*/}return 0;
}

这个函数就是递归函数,递归最后退出机制是 

left == right 

再然后,我们需要一个 main 函数

完整的代码实现如下

#include <stdio.h>
#include <stdlib.h>/** r[] : 需要排序的数组* s[] : 排序后保存数据的数组* left: 排序的起始位置* mid : 排序的中间位置* right:排序的最右边位置*/
int merge(int r[],int s[],int left,int mid,int right)
{int i,j,k;i=left;j=mid+1;k=left;for(;i <= mid && j<=right;){if(r[i]<=r[j])s[k] = r[i++];elses[k] = r[j++];k++;}for(;i<=mid;)s[k++]=r[i++];for(;j<=right;)s[k++]=r[j++];return 0;
}/** r[] : 需要排序的数组* s[] : 排序后保存数据的数组* left: 排序的起始位置* right:排序的最右边位置*/
int merge_sort(int r[],int s[],int left,int right)
{int mid;int t[20];if(left==right)s[left]=r[right];else{mid=(left+right)/2;merge_sort(r,t,left,mid);/*sort left~mid*/merge_sort(r,t,mid+1,right);/*sort mid+1~right*/merge(t,s,left,mid,right);/*merge sort left,mid,right*/}return 0;
}int main()
{int a[8] = {6,5,3,1,8,7,2,4};int i;merge_sort(a,a,0,7);for(i=0;i<sizeof(a)/sizeof(a[0]);i++)printf("%d ",a[i]);printf("\n");return 0;
}

程序输出

1 2 3 4 5 6 7 8

算法复杂度,翻开以前写的文章

时间复杂度和空间复杂度,一看就懂,面试前必过一遍

中间是 mid = (left+right)/2 

可以猜到是 O(logN) ,也就是排序的时间是用logN时间去拆分的,而且拆分的时候,我们还需要进行排序,也就是代码里面提到的,排序的时间是O(n),所以在拆分和排序中需要花费的时间是 O(NlogN)。

拆分需要花费 O(logN) ,那合并的时候自然也需要花费O(logN)

总的算法时间是

O(NlogN + logN)  = O(NlogN)


推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

关注公众号,后台回复「1024」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

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

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

相关文章

一份详细的服务器安全解决方案

一、操作系统配置 1.安装操作系统(NTFS分区)后&#xff0c;装杀毒软件&#xff0c;我选用的是卡巴。 2.安装系统补丁。扫描漏洞全面杀毒 3.删除Windows Server 2003默认共享 首先编写如下内容的批处理文件&#xff1a; echo off net share C$ /del net share D$ /del net …

GetModuleFileName

GetModuleFileName 获取当前进程已加载模块的文件的完整路径&#xff0c;该模块必须由当前进程加载。如果想要获取另一个已加载模块的文件路径&#xff0c;可以使用GetModuleFileNameEx函数。 声明GetModuleFileName(VB) Declare Function GetModuleFileName Lib “kernel32”…

jQuery load() 中文乱码

1、使用editplus创建了demo.txt (ANSI保存的)&#xff0c; $("#div1").load("demo.txt");//div显示中文乱码--->html5中定义<meta charset"utf-8"/>,编码解码不一致造成中文乱码&#xff0c;将文本文件demo.txt另存为utf-8格式&#xf…

内核链表list.h文件剖析

内核链表list.h文件剖析 一、内核链表的结构【双向循环链表】 内核链表的好主要体现为两点&#xff0c;1是可扩展性&#xff0c;2是封装。可以将内核链表复用到用户态编程中&#xff0c;以后在用户态下编程就不需要写一些关于链表的代码了&#xff0c;直接将内核中list.h中的代…

CAN总线很难吗?CAN总线看不懂是不可能的!

CAN&#xff08;Controller Area Network&#xff09;即控制器局域网&#xff0c;是一种能够实现分布式实时控制的串行通信网络。想到CAN就要想到德国的Bosch公司&#xff0c;因为CAN就是这个公司开发的&#xff08;和Intel&#xff09;CAN有很多优秀的特点&#xff0c;使得它能…

GetDlgItem

GetDlgItemText() GetDlgItemText是C中的函数&#xff0c;调用这个函数以获得与对话框中的控件相关的标题或文本。GetDlgItemText成员函数将文本拷贝到lpStr指向的位置并返回拷贝的字节的数目。 函数说明 CWnd类的成员函数。 函数原型 int GetDlgItemText( HWND hDlg , int n…

开放课程管理系统(Moodle)的介绍(转)

一、虚拟学习环境 关于虚拟学习环境&#xff0c;很难用一个简单的定义来描述。可以说是&#xff0c;支持和管理教与学的各项活动的基于网络的环境。也可以认为是学习管理系统的组成部分。当应用于远程教育时&#xff0c;通常认为它包括“任何用于创造一个统一的、类似于面对面的…

C语言必须写main函数?最简单的 Hello world 你其实一点都不懂!

我们在刚写程序的时候&#xff0c;第一个都是 hello world&#xff0c;而在这里&#xff0c;完整的代码就是&#xff1a;我们打眼一看&#xff0c;其实很简单&#xff0c;就是引入头文件&#xff0c;写一个主函数&#xff0c;然后输出一句话&#xff0c;但是当我们编译出来ELF的…

内核链表使用举例

内核链表使用举例#ifndef _EVENT_LIST_H_ #define _EVENT_LIST_H_#include "list.h" // 内核链表头文件typedef int (*event_cb)(void *data);typedef struct {void *params;event_cb handle;struct list_head list; } event_elem_t;int EventListAdd(event_elem_t *…

CObList

CObList CObList类支持非唯一的CObject指针&#xff0c;并可顺次访问或通过指针值访问有序列表。CObList列表的行为类似于双向链接列表。CObList是非常有用的集合类族的代表&#xff0c;具有诊断转储的特性并且能够包含混合的指针。 POSITION类型的变量为列表的键。使用POSITIO…

源码包安装

一、源码包和RPM包的区别 1、区别 安装之前的区别&#xff1a;概念上的区别 安装之后的区别&#xff1a;安装位置不同 2、RPM包安装位置 是安装在默认位置中 注&#xff1a;安装位置是写RPM包的作者决定的 注&#xff1a;RPM包支持指定安装位置&#xff0c;但是不建议指定位置安…

年轻10岁简单又易行的妙方

爱美的女性&#xff0c;谁不想使自己更年轻&#xff0c;并能留住一份健康的美?我们介绍的方法非常容易实现&#xff0c;只要你能够坚持。想要年轻10岁?没有想象中那么困难,但是也要持之以恒哦!这里推荐的都是价廉易置的)鉴借&#xff0c;愿能给大家有参考之用&#xff1a;1.一…

计算最后一个单词的字符串长度

题目 http://www.nowcoder.com/questionTerminal/8c949ea5f36f422594b306a2300315da 看了大家的答案&#xff0c;觉得还是稍微复杂。给一个比骄简单的解题思路。 只要是空格&#xff0c;就把计数置0&#xff0c;要不然就一直自增。 #include "stdio.h" #include …

strstrsubstr、AfxGetApp

1.strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是&#xff0c;则该函数返回str2在str1中首次出现的地址&#xff1b;否则&#xff0c;返回NULL。 2.substr是C语言函数&#xff0c;主要功能是复制子字符串&#xff0c;要求从指定位置开始&#xff0c;并具有…

Linux下修改SSH登录端口

Linux下修改SSH登录端口LINUX 的默认SSH 端口是 22。为了防止别人暴力破解&#xff0c;建议修改SSH 访问端口&#xff1a;vim /etc/ssh/sshd_config 找到Port 22 这一行&#xff0c;这是是默认端口22&#xff0c;现在改成Port 1234这个数字自己定&#xff0c;但是不要超过65536…

五岁的时候,你在干什么?

文章写在2021.2.7号——想不到啊想不到&#xff0c;这么快你就五岁了。今天是楠哥的生日&#xff0c;在五年前的今天&#xff0c;小伙子在深圳宝安妇幼出生&#xff0c;刚出生的时候&#xff0c;样子很丑&#xff0c;第一次见面&#xff0c;我心情很紧张&#xff0c;不怎么敢靠…

GetLocalTime

GetLocalTime是一个Windows API 函数&#xff0c;用来获取当地的当前系统日期和时间。 函数原型: VOID GetLocalTime( LPSYSTEMTIME lpSystemTime //address of system times structure ); 参数说明: lpSystemTime: 指向一个用户自定义包含日期和时间信息的类型为 SYSTEMTIME 的…

Java集合(7):散列与散列码

散列的价值在于速度。我们使用数组来保存键的信息&#xff0c;这个信息并不是键本身&#xff0c;而是通过键对象生成一个数字(散列码)&#xff0c;作为数组下标。由于数组的容量是固定的&#xff0c;而散列容器的大小是可变的&#xff0c;所以不同的键可以产生相同的数组下标(散…

301转向代码合集

教育资源网将SEO工作中所需要的301转向代码进行了整理&#xff0c;收藏并分享&#xff0c;以备查阅。 1、IIS下301设置 Internet信息服务管理器 -> 虚拟目录 -> 重定向到URL&#xff0c;输入需要转向的目标URL&#xff0c;并选择“资源的永久重定向”。 2、ASP下的301转向…

TQ210——核心板和底板

TQ210——核心板和底板 1、TQ210简介【TQ210_COREB核心板 TQ210_BOARD_V4底板】 三星Cortex-A8 S5PV210芯片&#xff0c;运行最大频率1GHZ&#xff0c;处理器内部为64/32位总线结构&#xff0c;32/32KB一级缓存&#xff0c;512KB二级缓存。自带3D加速引擎&#xff08;SGX540&a…