归并排序

一)算法介绍

归并排序是采用分治法的一个非常典型的应用,是一种稳定排序

基本操作:将一个无序的序列分割成若干个子序列,再把子序列进行比较和排序,得到完全有序的子序列,再把有序的子序列合并成一个新的有序列表。

备注:归并排序时间复杂度始终是固定O(log2N),代价是需耗费额外的存储空间。

稳定排序:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;

 

二)算法原理

基本原理

第一步:申请一个和无序序列一样长度的空间,用来存放合并后的序列。

第二步:申请两个指针,分别指向两个子序列的起始位置。

第三步:比较两个指针所指向的元素,选择相对小的元素放置到合并空间,并移动指针到下一位置。

第四步:重复第三步操作,直到一个指针超出序列尾部,再将另一序列剩下的所有元素复制到合并序列尾部。

算法步骤图解

源数据:int[] nums = {29, 10, 14, 37, 15, 18, 30};

先把源数据进行分组,一直细分成1个元素1组。

[29]、[10]、[14]、[37]、[15]、[18]、[30]

 

第一遍排序:先比较29>10,交换29和10的位置,再比较14<37,14和37位置不变,比较15<18,15和18位置不变,30不比较。然后把比较之后的子序列合并成2个元素1组。

合并后:[10, 29]、[14, 37]、[15,18]、[30]

 

第二遍排序:先比较10<14<37,10和14、37位置不变,再比较29>14,交换29和14的位置,比较29<37,29和37位置不变,再比较15<30,15和30位置不变,比较18<30,18和30位置不变。然后把比较之后的子序列合并成4个元素1组。

合并后:[10, 14, 29, 37]、[15, 18, 30]

 

第三遍排序:先比较10<15<18<30,10和15、18、30位置都不变,比较14<15<18<30,14和15、18、30位置都不变,再比较29>15,交换15和29的位置,比较29>18,交换29和18的位置,比较29<30,29和30位置不变,比较37>29,交换37和29的位置,比较37>30,交换37和30的位置,比较29<30,29和30位置不变。然后把比较之后的子序列合并成一个有序序列。

合并后:[10, 14, 15, 18, 29, 30, 37]

 

算法排序效果图:

算法复杂度:

最差情况:T(n) = O(log2N)

最好情况:T(n) = O(log2N)

O(log2N)的含义:将一个数据集分成两半,然后将分开的每一半再分成两半,依此类推。

O(Nlog2N)的含义将一个数据集分成两半,然后将分开的每一半再分成两半,依此类推,在此过程中同时遍历每一半数据。

 

三)算法源码

步骤简介:先申请一个临时空间,再把无序序列分成若干个子序列,对每个子序列进行比较和排序,再把有序的子序列合并成一个新的有序列表。再把临时空间的数据存放到源数据中。

/**
 * 归并排序
 */
public static void mergeSort(int[] nums, int left, int right) {
	if (left < right) {
		// 得到左中位数,推荐写法
		int center = (left + right) >>> 1;
			
		// 对左边数据进行排序
		mergeSort(nums, left, center);
			
		// 对右边数据进行排序
		mergeSort(nums, center + 1, right);
			
		// 把左边和右边的数据合并
		merge(nums, left, center, right);
	}
}
	
private static void merge(int[] nums, int left, int center, int right) {
	// 申请临时空间
	int[] tempArr = new int[nums.length];
		
	int tempLeft = left;
		
	// 左边数组第一个起始指针
	int leftFirst = left;
				
	// 右边数组第一个起始指针
	int rightFirst = center + 1;
		
	// 比较子序列的元素, 把数据存放到临时空间, 并移动指针
	while (left <= center && rightFirst <= right) {
		if (nums[left] <= nums[rightFirst]) {
			tempArr[tempLeft++] = nums[left++];
		} else {
			tempArr[tempLeft++] = nums[rightFirst++];
		}
	}
		
	// 把多余序列的元素复制到临时空间序列尾部
	while (rightFirst <= right) {
		tempArr[tempLeft++] = nums[rightFirst++];
	}
		
	while (left <= center) {
		tempArr[tempLeft++] = nums[left++];
	}
		
	// 把临时空间数据复制到源数据中
	while (leftFirst <= right) {
		nums[leftFirst] = tempArr[leftFirst++];
	}
}

 

识别二维码关注个人微信公众号

本章完结,待续,欢迎转载!
 
本文说明:该文章属于原创,如需转载,请标明文章转载来源!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值