c语言归并排序

简介

记录一下归并排序的学习,在csdn上找了半天感觉没有特别详细的,所以就想着自己来写一个

归并排序介绍

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

归并排序原理介绍

        我相信大部分人可能都没看懂归并排序到底是个什么东西,其实上面一段话,最主要的就是最后一句:即先使每个子序列有序,再使子序列段间有序。

        什么意思呢?我们先看后半句,使子序列段间有序。其实就是把两个子序列合并在一起并且这个新的序列是有序的,就比如我们要让他从小到大排序,那我就首先把两个序列的第一个进行比较,把更小的那个放进新序列里面,然后从前往后一个一个比较,这样得到的序列就会也有序,但是如果你这么去写,你就会发现一个问题:加入两个序列中最小的数在比较靠后的位置,那我就会先比较了大的数再比较小的数,也就是前面更大的数先比较放在前面,后面才比较到更小的数,才放进去,那么结果就是小的数反而再后面了,给大家画图演示一遍

这是开始的两个序列,现在我们开始一个一个比较;

第一次比较完

第二次比较完

……

第四次比较完

第五次……、

        于是我们就会发现,哎,出错了,我们想让他从小到大排序,但是2却出现在了后面。因此,我们如果想要他按照我们的想法来排列,这两个子序列就必须从小到大排列,也就是子序列必须得有序,那怎么让子序列有序呢?是不是就得让这个子序列的子序列有序,是不是有点像套娃,只不过里面可以放几个娃,但是得按顺序,知道最里面只剩下一个娃,那肯定是有序的,也就是说当我把一个序列分成每个只有一个数的序列那我就可以不用管子序列有序这个限制了,直接把他们两个两个合起来,直到合成为一个序列,就比如我分成了四个只有一个数的子序列,那我先两个两个同时合成,就有了两个有序的序列,这两个序列里都有两个数,我再把这两个有序的序列合成,最后就成了一个有序的含有四个数的序列。

        这就是归并排序法的原理,总结来说就是先分再治,先分成单个的子序列,再慢慢合称为一个大的序列,这样就全部排序好了。

代码实现

那知道了归并排序的原理,那我们就来看看怎么用代码来实现他:

主函数的书写

首先我,我们来写主函数,首先我们先想好我们需要什么,首先,主角不能缺席,我们得定义一个数组来储存需要排序的序列,并且得先告诉编译器这个序列有几个数才能给他分配空间,然后就可以开始执行我们归类并序的函数,最后再打印出来

int main()
{
	//输入需要输入的个数
	printf("需要输入数的个数:");
	int n = 0;
    scanf_s("%d", &n);
	printf("输入数据:");
	//创建一个动态数组来储存数据
	int* arr = (int*)malloc(sizeof(int) * n);
	//输入数据
	for (int i = 0; i < n; i++)
		scanf_s(" %d", &arr[i]); 

	/*归并排序函数*/

	printf("按升序排序的结果:");
    //打印数组
	for (int i = 0; i < n; i++)
		printf(" %d ", arr[i]);
	printf("\n");

    //释放空间
	free(arr);

	return 0;
}

mergesort函数的书写

接下来就是最主要的也是最核心的mergesort函数的书写,首先先定义一个函数,那么这个函数需要传入什么参数呢,首先肯定得把数组传进去吧,第二,左端右端得传吧,你可以理解为下标,我想了一下,让他左取又不取应该是最简单并且好理解的(相当于是给他一个下标,便于每个序列归并)那么我们先把函数定义出来

void mergesort (ina* arr,int left,int right)
{

}

我们首先是要拆分这个函数,但是不能一直拆, 当他只剩一个数,就应该停止拆分,所以第一件事应该是给他一个条件,当right - left <= 1时,就直接给他退出了,就不往下执行了。

void mergesort (ina* arr,int left,int right)
{
    if(left - right <= 1)
        return;
}

 接下来开始写函数的内容,首先拆成两个数组,那么就还需要一个中间值来表示拆分之后第一个序列的右端和第二个序列的左端也就是定义一个mid = (right + left) / 2,接下来就开始递推,那第一个序列的左端跟原序列的左端一样,右端就变成了mid。

void mergesort(int* arr, int left, int right)
{
	if (right - left <= 1)
		return;
	int mid = (left + right) / 2;
	//先拆分
	mergesort(arr, left, mid);
	mergesort(arr, mid, right);

}

这样,我们就把一个序列拆成了一个个子序列,接下来就可以进行合并了

merge函数的书写

首先定义函数,第一个,数组肯定是要传进去的,然后因为我们是把两个子序列合并,就要把两个子序列的左右端点都传入,也就是比拆分多传一个mid

void merge(int* arr,int left,int mid,int right)
{
}

接下来就开始比较,首先先创建一个新数组,再一个一个比较,把小的放进新数组里,然后分别定义一个从左端开始走的下标,以及临时数组的下标

void merge(int* arr,int left,int mid,int right)
{
	int i = left, j = mid,k = 0;
	int* temp = (int*)malloc(sizeof(int) * (right - left));
	while (i < mid && j < right)
	{
		if (arr[i] <= arr[j])
			temp[k++] = arr[i++];
		else
			temp[k++] = arr[j++];
	}
	
}

但是比来比去最终至少会剩下一个,甚至可能某个数列全部剩下,那就得把剩下的也放进去。最后再把临时数组传给原数组。

void merge(int* arr,int left,int mid,int right)
{
	int i = left, j = mid,k = 0;
	int* temp = (int*)malloc(sizeof(int) * (right - left));
	while (i < mid && j < right)
	{
		if (arr[i] <= arr[j])
			temp[k++] = arr[i++];
		else
			temp[k++] = arr[j++];
	}
	
	while (i < mid)
		temp[k++] = arr[i++];
	while (j < right)
		temp[k++] = arr[j++];
	for (int x = 0; x < k; x++)
		arr[left + x] = temp[x];
	free(temp);
}

好了,这样函数就写完了,最后把主函数完善一下,数据传一下。整理完之后就是这样

全部代码

#include<stdio.h>
#include<stdlib.h>

void merge(int* arr, int left, int mid, int right)
{
	int i = left, j = mid, k = 0;
	int* temp = (int*)malloc(sizeof(int) * (right - left));
	while (i < mid && j < right)
	{
		if (arr[i] <= arr[j])
			temp[k++] = arr[i++];
		else
			temp[k++] = arr[j++];
	}

	while (i < mid)
		temp[k++] = arr[i++];
	while (j < right)
		temp[k++] = arr[j++];
	for (int x = 0; x < k; x++)
		arr[left + x] = temp[x];
	free(temp);
}

void mergesort(int* arr, int left, int right)
{
	if (right - left <= 1)
		return;
	int mid = (left + right) / 2;
	//先拆分
	mergesort(arr, left, mid);
	mergesort(arr, mid, right);
	//再合并
	merge(arr, left, mid, right);
}

int main()
{
	//输入需要输入的个数
	printf("需要输入数的个数:");
	int n = 0;
	scanf_s("%d", &n);
	printf("输入数据:");
	//创建一个动态数组来储存数据
	int* arr = (int*)malloc(sizeof(int) * n);
	//输入数据
	for (int i = 0; i < n; i++)
		scanf_s(" %d", &arr[i]);
	mergesort(arr, 0, n);
	printf("按升序排序的结果:");
	for (int i = 0; i < n; i++)
		printf(" %d ", arr[i]);
	printf("\n");
	free(arr);



	return 0;
}

运行结果

最后我们来运行一下试试

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花果山-YYC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值