归并排序详解

目录

一.归并排序介绍

二.归并排序算法的特点

三.归并算法的实现介绍 


一.归并排序介绍

      归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列。

二.归并排序算法的特点

        排序算法有很多,插入,冒泡,选择,希尔,快速等等,我们通过上面的这张图会发现,归并算法的时间复杂度是非常稳定的,不论是在哪种情况下,归并算法的时间复杂度都不变,而且,归并算法计算效率相比其他算法也是非常快的。

        上面我们提到了归并算法的优点,世无完物,拥有较快的效率和极高的稳定性的归并算法,想必也有自己的缺点,没错,归并算法的缺点就是他的空间复杂度比较大,而产生这样的缺点就是因为他的分治思想导致的。

三.归并算法的实现介绍 

 上面的这张图就是归并算法的大体排序过程,可以看到归并算法就是要把一个有n个元素的数组,分成n个有1个元素的数组。然后再进行排序的。而具体的过程,我将以上图中5 ,7, 1, 8,这四个元素的排列来介绍。

 上面的这个就是我们在进行把两个有序数组合并成一个有序数组的简单图解,下面是以代码的形式来书写这个过程。

void merge_sort(int* arr, int left, int right, int middle)
{
	int* aux;
	int i = left;//i表示的是middle前面的数组的元素
	int j = middle+1;//j表示的是middle之后的数组的元素
	int k = 0;//k表示的是aux数组中的元素
	aux = (int*)malloc((right-left+1)*sizeof(int));//为了开辟够足够的空间开存放数组各元素的内容
	for (k= left; k <= right; k++)
	{
		*(aux + k - left) = *(arr + k);//先将两个子数组中的元素全部输入进aux数组中
	}
	for (k = left; k <= right; k++)
	{
		if (i > middle)
		{
			*(arr + k) = *(aux + j - left);
			j++;
		}
		else if (j > right)
		{
			*(arr + k) = *(aux + i - left);
			i++;
		}
		else if (*(aux + i - left) > *(aux + j - left))
		{
			*(arr + k) = *(aux + j - left);
			j++;
		}
		else
		{
			*(arr + k) = *(aux + i - left);
			i++;
		}
	}
}

       这个就是具体的合并过程。

      在前面的八个元素的大体排序图中,我们发现归并排序的分治法的治是前面分的倒序过程,通过我们之前学习的知识,不难想到,这个归并的过程其实是一个递归的过程具体代码如下:

void mergesort(int* arr, int left, int right)
{
	if (left >= right)
	{
		return ;
	}
	int middle = (left + right) / 2;
	mergesort(arr, left, middle);
	mergesort(arr, middle + 1, right);
	merge_sort(arr, left, right, middle);
}

除此之外,我们还需要编写一个函数,用来确定数组的首元素的编号和最后一个元素的编号。

void Mergesort(int* arr, int left, int right)
{
	mergesort(arr, left, right - 1);
}

接下来再书写用来接收输入的数据的main函数

int main()
{
	int* arr;
	int n = 0;
	int i = 0;
	scanf("%d", &n);
	arr = (int*)malloc(n * sizeof(int));
	for (i = 0; i < n; i++)
	{
		scanf("%d", arr + i);
	}
	Mergesort(arr, 0, n);
	for (i = 0; i < n; i++)
	{
		printf("%d ", *(arr + i));
	}
	return 0;
}

下面就是由四个函数拼接而成的归并排序

#include <stdlib.h>
#include <stdio.h>
void Mergesort(int* arr, int left, int right);
void mergesort(int* arr, int left, int right);
void merge_sort(int* arr, int left, int right, int middle);

int main()
{
	int* arr;
	int n = 0;
	int i = 0;
	scanf("%d", &n);
	arr = (int*)malloc(n * sizeof(int));
	for (i = 0; i < n; i++)
	{
		scanf("%d", arr + i);
	}
	Mergesort(arr, 0, n);
	for (i = 0; i < n; i++)
	{
		printf("%d ", *(arr + i));
	}
	return 0;
}

void Mergesort(int* arr, int left, int right)
{
	mergesort(arr, left, right - 1);
}

void mergesort(int* arr, int left, int right)
{
	if (left >= right)
	{
		return ;
	}
	int middle = (left + right) / 2;
	mergesort(arr, left, middle);
	mergesort(arr, middle + 1, right);
	merge_sort(arr, left, right, middle);
}

void merge_sort(int* arr, int left, int right, int middle)
{
	int* aux;
	int i = left;//i表示的是middle前面的数组的元素
	int j = middle+1;//j表示的是middle之后的数组的元素
	int k = 0;//k表示的是aux数组中的元素
	aux = (int*)malloc((right-left+1)*sizeof(int));//为了开辟够足够的空间开存放数组各元素的内容
	for (k= left; k <= right; k++)
	{
		*(aux + k - left) = *(arr + k);//先将两个子数组中的元素全部输入进aux数组中
	}
	for (k = left; k <= right; k++)
	{
		if (i > middle)
		{
			*(arr + k) = *(aux + j - left);
			j++;
		}
		else if (j > right)
		{
			*(arr + k) = *(aux + i - left);
			i++;
		}
		else if (*(aux + i - left) > *(aux + j - left))
		{
			*(arr + k) = *(aux + j - left);
			j++;
		}
		else
		{
			*(arr + k) = *(aux + i - left);
			i++;
		}
	}
}

这么长的代码再加上递归,别说是用肉眼看,就是通过调试,也会不小心的把人绕进递归递归,所以这边博主以简单的三元素数组{3,2,1}来解释这个代码:

        这里的一个难点是递归的过程,程序员需要时刻清楚递归的环节,在{3,2,1}的第一次递归后,将这个数组分成了{3,2}和{1},通过代码,我们知道先把前面的数组拆分,即{3,2}会被拆分为{3},{2},这时前面的数组就算是完成了拆分,而{2}的数组本身就只有一个元素,所以不需要进行{2}数组的递归,进入后面的{3},{2}的排序,在{3,2}变成{2,3}后,我们终于跳出了前面数组两层递归的里面一层,再次跳入后面{1}数组的递归,{1}数组本身就只有一个元素,所以不需要进行{1}数组的递归,进入{2,3}和{1}的排序,排序完成后,我们也跳出了全部的递归,完成了排序。

这就是我对归并排序的讲解,如有问题,欢迎你的斧正。

  • 27
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
Java归并排序是一种排序算法,它将数组切分为较小的部分,然后递归地对这些部分进行排序,并最后将它们合并起来。在Java中,归并排序是通过底层的Arrays.sort()方法实现的[1]。下面是Java归并排序的一般步骤和代码实现。 1. 定义一个mergeSort()方法,该方法接受一个数组a和两个整数lo和hi作为参数。这个方法用来进行递归调用,对数组的指定部分进行排序。 2. 在mergeSort()方法中,首先创建一个与数组大小相同的临时数组temp,用于存放排序后的元素。 3. 然后,调用另一个mergeSort()方法,该方法接受一个数组a和四个整数lo、hi、mid作为参数。这个方法用来进行归并操作,将数组的两个子数组合并成一个有序数组。 4. 在mergeSort()方法中,首先计算切分点mid,然后判断子数组的长度是否大于1,如果大于1则继续拆分子数组。 5. 接下来,递归地调用mergeSort()方法对两个子数组进行排序,分别传入参数a、temp、lo、mid和a、temp、mid+1、hi。 6. 最后,在mergeSort()方法中调用merge()方法将两个子数组合并成一个有序数组。 Java归并排序的核心是merge()方法,该方法将两个有序子数组合并成一个有序数组。 总结起来,Java归并排序通过递归地将数组划分为较小的部分,并合并这些部分以获得最终的排序结果。这种排序算法在Java中被广泛应用,并且可以在源码中找到其实现。 参考文献: 麦田怪圈 (Crop Circle), 维基百科, https://zh.wikipedia.org/wiki/麥田怪圈 人为制作麦田怪圈的方法, 百度百科, https://baike.baidu.com/item/人为制作麦田怪圈的方法 归并排序, 维基百科, https://zh.wikipedia.org/wiki/归并排序<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [归并排序详解,Java版描述。](https://blog.csdn.net/weixin_30539625/article/details/97734524)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值