归并排序的原理、图解、代码实现、时间复杂度分析

归并排序概述

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

排序原理

排序原理:

  1. 尽可能的将一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组 的元素个数是1为止。
  2. 将相邻的两个子组进行合并成一个有序的大组。
  3. 不断的重复步骤2,直到最终只有一个组为止。

排序图解

{8,4,5,7,1,3,6,2}进行从小到大排序
在这里插入图片描述

代码实现

实现的api:

  1. public static boolean greater( int a,int b) 比较a与b的大小,返回true/false
  2. public static void exch(int[] a,int i,int j) 交换索引i处和索引j处的值的位置
  3. public static void sort(int[] a) 对数组a进行排序
  4. public static void sort(int[] a,int lo,int hi) 对数组指定索引lo到指定索引hi处的值进行排序
  5. public static void merge(int[] a,int lo,int mid,int hi) 将索引lo到索引mid的数组和索引mid+1到索引hi的数组合并成一个数组
具体实现合并的图解

在这里插入图片描述

代码实现
import java. util .Arrays;

public class SortMerge {
	//定义辅助数组
	private static int[] help;

	public static void main(String[] args) {

		int[] array=new int[]{8,4,5,7,1,3,6,2};
		sort(array);
		System. out. println(Arrays . toString(array));

	}

	/**
	 * 比较两个数之间的大小
	 * @param a
	 * @param b
	 * @return
	 */
	public static boolean greater( int a,int b){
		return a>b;
	}

	/**
	 * 交换两个数的位置
	 * @param a
	 * @param i
	 * @param j
	 */
	public static void exch(int[] a,int i,int j){
		int temp=a[i];
		a[i]=a[j];
		a[j]=temp;
	}

	/**
	 * 对元素进行排序
	 * @param a
	 */
	public static void sort(int[] a){
		//初始化辅助数组
		help=new int[a. length];
		
		int lo=0;
		int hi=a.length-1;
		
		//从lo索引处到hi所引处进行排序
		sort(a,lo,hi);
	}

	/**
	 * 对数组元素从索引到索引的排序
	 * @param a
	 * @param lo
	 * @param hi
	 */
	public static void sort(int[] a,int lo,int hi){
		if(hi<=lo){
			return;
		}
		//对lo-hi之间数据进行分组
		int mid=(lo+hi)/2;

		//分别每一组数据进行排序
		sort(a,lo,mid);
		sort(a,mid+1,hi);

		//排完序后对两个数组进行归并
		merge(a,lo,mid,hi);
	}

	/**
	 * 再把两个组中数组进行归并
	 * 从索引1o- mid是一个数组, mid+1- hi又是一-个数组 ,将两个数组合并
	 * @param a
	 * @param lo
	 * @param mid
	 * @param hi
	 */
	public static void merge(int[] a,int lo,int mid,int hi){
		int i=lo;//辅助数组的指针
		
		//左子数组的指针
		int p1=lo;
		//右子数组的指针
		int p2=mid+1;
		
		//归并的时候,当左子数组和右子数组都还没有遍历完的时候
		while(p1<=mid && p2<=hi){
			//比较两个索引处的值的大小,如果左子数组的当前索引处的值大于右子数组当前索引处的值,则将右子数组索引处的值放到辅助数组中,并且右子数组的指针右移,否则相反
			if(greater(a[p1],a[p2])){
				help[i++]=a[p2++];
			}else{
				help[i++]=a[p1++];
			}
		}

		//当上面while循环结束后,左子数组还没有遍历完,则直接按顺序放入到辅助数组中
		while(p1<=mid){
			help[i++]=a[p1++];
		}
		
		//当上面while循环结束后,右子数组还没有遍历完,则直接按顺序放入到辅助数组中
		while(p2<=hi){
			help[i++]=a[p2++];
		}
		
		//将辅助数组的值放到数组张
		for(int index=lo;index<=hi ;index++){
			a[index]=help[index];
		}
	}

}



时间复杂度分析

时间复杂度为O(nlogn)
缺点就是,需要申请额外的空间数组,当待排序的数量较多时,会导致空间复杂度复杂

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值