分治——归并排序

归并排序:

核心思想:
  • 将一个序列划分为两个有序部分,一直分到左右只剩一个元素,此时就已经是排好队了,然后再一步步合并(每次合并的时候,新建左右数组,给其赋值,三个指针,i指向左数组的首元素,j指向右边数组的首元素,k指向原数组中此次排序的首元素,我们要做的就是依次将左右部分数组中最小的放入元素数组中去,直到左右数组其中一个全部放完就跳出循环,最后只有一个数组里面还未全部放完,所有对两个数组进行判断i,j的位置,若没放完就一直放到原始数组即可)。
详细步骤:
  • 对于一个杂乱序列,我们需要对将序列递归一直划分,直到两个子序列中都只有一个元素时(此时可以认为左右两部分都是有序的),然后合并这两个子序列为一个有序序列。然后返回上一层,此时上一层的子序列就也是有序的了,所以再合并,再返回上一层,直到最顶层时将整个序列合为一个有序序列。
时间复杂度:
  • O(nlog2^n)
  • (一直二分,也类似一棵树结构,所以复杂度为O(nlog2^n))
稳定性:
  • 稳定(在合并两个子序列时,只要注意左边和右边相等时,先放左边即可使该算法排序稳定)
适用场景:
  • 在对空间没限制的时候,可以选择归并排序
扩充理解:
  • 分治概念:
    采用分治法解决的问题一般具有的特征如下:
  1. 问题的规模缩小到一定的规模就可以较容易地解决。
  2. 问题可以分解为若干个规模较小的模式相同的子问题,即该问题具有最优子结构性质。
  3. 合并问题分解出的子问题的解可以得到问题的解。
  4. 问题所分解出的各个子问题之间是独立的,即子问题之间不存在公共的子问题
public class MergeSort {
	//和并方法,将左右两个有序部分合为一个有序部分
	public static void merge(int []a,int left,int right){
		int m=(right-left)/2+left;//中间值
		//左数组长度:left-m+1, 右数组长度:right-m
		int l[]=new int[m-left+1];
		int r[]=new int[right-m];
		//初始化左右数组
		for(int i=left;i<=m;i++){
			l[i-left]=a[i];
		}
		for(int i=m+1;i<=right;i++){
			r[i-m-1]=a[i];
		}
		int i=0,j=0,k=left;//i,j为左右指针,开始时分别指向左右数组的第一个元素。k指向原始数组中此次排序的首位置。我们要做的就是依次将左右部分数组中最小的放入元素数组中去,直到左右数组其中一个全部放完就跳出循环
		while(i<l.length&&j<r.length){
			if(l[i]<=r[j]){//这里一定记得时小于等于,若是小于的化,会导致排序不稳定(相同的数,右边的先放,就导致右边跟左边交换了位置)
				a[k]=l[i];
				i++;
				k++;
			}else{
				a[k]=r[j];
				j++;
				k++;
			}
		}
		//此时只有一个数组里面还未全部放完,所有对两个数组进行判断i,j的位置,若没放完就一直放到原始数组即可(因为左右数组已经排号序了)
		while(i<l.length){
			a[k]=l[i];
			i++;
			k++;
		}
		while(j<r.length){
			a[k]=r[j];
			j++;
			k++;
		}
	}
	//划分序列方法
	public static void mergeSort(int []a,int left,int right){
		if(left==right)return;//当划分到只有一个元素时跳出
		int m=(right-left)/2+left;//记录中间值
		//不断将序列划分 
		mergeSort(a,left,m);//一直递归将左半部分划分为左右两部分,每次返回该处时,左半部分都是有序的(第一次返回此处是只有一个元素,一个元素就直接是有序)
		mergeSort(a,m+1,right);	//同理,一直递归划分右部分为左右两部分,每次返回该处时,右半部分都是有序的(第一次返回此处是只有一个元素,一个元素就直接是有序)
		merge(a,left,right);//这个时候可以认为原序列被分为两部分,且两部分都已经排好序了,然后调用合并函数,将这两部分合并成一个有序序列。
		//执行完后返回上一层,此时上一层的左半序列(右半序列)也是有序的了
	}
	public static void main(String[] args) {
		//测试
				int []a={2,15,54,4,4,56,4,56,4,51,6,15,11,11,111,11,111,11,11,111,44,454,4554,4,548,};
				mergeSort(a,0,a.length-1);
				for(int t:a)System.out.println(t);
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值