八大排序算法之归并排序(Java实现)

参考链接:b站韩顺平老师的数据结构

思路:归并排序整个思路是首先递归拆解数组,每一次对数组相当于对半拆分,首先对左边递归拆分,再对右边递归拆分。这里用到了分治思想,先分再治(合并)

递归的思路都是先推公式再找终止条件

公式描述:merge(q.....r)=merge(merge(q....p)+merge(p+1.....r))///公式的意思就是把一个数组对半拆,拆到只剩一个元素

终止条件:p>=r,递归拆解结束,然后开始合并

q是头元素索引,r是尾元素索引,p是中间元素索引=(q+r)/2

八大排序算法之归并排序(Java实现)_第1张图片

代码描述和实现:

代码思路:【先捋思路再写代码】先写合并merge方法,以最后一次合并为例,需要的参数有原数组(待排序数组)首、尾、中间索引、临时数组(存放当前合并数据),中间索引是左序列的尾索引,加1为右序列的头索引

                  接着根据公式和终止条件写递归拆分以及调用合并(mergeSort)方法,左递归时,中间索引往“左边”走,到右递归时中间索引会往“右边”走【结合代码注释进行理解,merge中的第三步比较难】

                   最后写main方法测试

package Sort;

import java.util.Arrays;

public class MergeSort {
	public static void main(String[] args) {
		int arr[] = {10,1,5,4,2,7,3,9};
		int temp[] = new int[arr.length];//额外空间,临时数组
		mergeSort(arr, 0, arr.length-1, temp);
		System.out.println();
		System.out.println("归并完成:"+Arrays.toString(arr));
	
}
	/**
	 * 
	* Description:分+合方法  
	* @param: @param arr
	* @param: @param left
	* @param: @param right
	* @param: @param temp
	* @author Jeason  
	* @date 2021年6月14日  
	* @version 1.0
	 */
	public static void mergeSort(int[] arr,int left ,int right ,int[] temp)
	{
		if(left < right)
		{
			
			int mid = (left + right)/2;//中间索引
			mergeSort(arr, left, mid, temp);//左递归进行分解
			mergeSort(arr, mid+1, right, temp);//右递归进行分解
			merge(arr, left, mid, right, temp);//合并
		}
	}
	/**
	 * 
	* Description:合并的方法 
	* @param: @param arr 待排序数组
	* @param: @param left 左边有序序列的初始索引
	* @param: @param right 右边有序序列的初始索引
	* @param: @param right 中间索引,(也是左边数组的尾元素索引)
	* @param: @param temp  中转临时数组
	* @author Jeason  
	* @date 2021年6月13日  
	* @version 1.0
	 */
public static void merge(int[] arr,int left,int mid,int right,int[] temp)
{
	int i = left;//初始化i,左边有序序列的初始索引
	int j = mid+1;//初始化j,右边有序序列的初始索引
	int t = 0;//temp数组当前索引
	//第一步
	//先把左右两边的(有序)数组一次填充到temp数组
	//直到左右两边的有序序列,有一边处理完成(意思:任意单边数据已填入数组中)
	while(i<=mid && j<=right)//未合并完
	{
		if(arr[i] <= arr[j])//“左”边小,左边先入,temp数组往后
		{
			temp[t] = arr[i];
			t += 1;
			i += 1;
		}
		else//“右”边小,右边入,temp数组往后
		{
			temp[t] = arr[j];
			t += 1;
			j += 1;
		}
	}
	//第二步
	//把未处理完成得另一边数组剩余的元素全部填入temp数组尾部
	while(i<=mid)//左边未处理完,剩余压入
	{
		temp[t] = arr[i];
		t += 1;
		i += 1;
	}
	while(j<=right)//右边剩余压入
	{
		temp[t] = arr[j];
		t += 1;
		j += 1;
	}
	//第三步
	//将temp数组全部拷贝到arr原数组回去
	//注意,并不是每次都拷贝所有,我把每一次合并都打印出来了,这里我们看到第四次打印是2 7 5 10,这是对的,因为我们没有擦除上次合并的数据 5 和 10
	t = 0;
	int tempLeft = left;
	while(tempLeft<=right)//
	{
		arr[tempLeft] = temp[t];
		t += 1;
		tempLeft += 1;
	}
	System.out.println(Arrays.toString(temp));
}

}


结果:

八大排序算法之归并排序(Java实现)_第2张图片

第三遍:

package Sort;

import java.util.Arrays;

public class MergeSort {
	public static void main(String[] args) {
		MergeSort sort = new MergeSort();
		int arrs[] = {3,2,5,1,6};
		sort.mergeSort(arrs, 0, arrs.length-1, new int[arrs.length]);
		System.out.println(Arrays.toString(arrs));
	}
	
	public void mergeSort(int arrs[],int left,int right,int[] tempList)
	{
		if(left>=right)//一个数,不用拆解
			return;
		int mid=left+(right-left)/2;
		//左递归
		mergeSort(arrs, left, mid, tempList);
		//右递归
		mergeSort(arrs, mid+1, right, tempList);
		//合并
		merge(arrs,left,right,mid, tempList);
	}
	private void merge(int arrs[],int left,int right,int mid,int[] tempList)
	{
		if(left>=right)//一个数,不用合并
			return;
		int i=left;
		int j=mid+1;
		int t=left;//可以为0,这里是为了和原数组索引对应起来
		while(i<=mid&&j<=right)
		{
			if(arrs[i]<=arrs[j])
				tempList[t++]=arrs[i++];
			else
				tempList[t++]=arrs[j++];
		}
		//左边剩余压入
		while(i<=mid)
		{
			tempList[t++]=arrs[i++];
		}
		//右边剩余压入
		while(j<=right)
		{
			tempList[t++]=arrs[j++];
		}
		//拷贝回去
		t=left;
		while(left<=right)
		{
			arrs[left]=tempList[left];
			left++;
		}
	}
}

递归实现

注意点:tempLeft从未排序原数组开始,可以用left代替,tempList[t++]=arrs[i++];【经常写错的地方】

时间:由完全二叉树的深度可知,整个归并排序需要进行O(log2^n)次,每次进行n个数的合并     总时间复杂度为O(nlogn)

空间:在归并过程中需要一个与原始序列相同长度的临时数组,以及递归栈O(log2^n),因此空间复杂度为(n+logn)即O(N)

归并排序的时间复杂度与数组是否有序无关,这是从代码得出来的,所以时间复杂度稳定,最好最坏平均都是O(nlogn),即使是快速排序其最坏时间复杂度也为O(N^2),所以是非常优秀的,那为什么归并没有广泛应用?因为它不是原地排序算法,需要借助O(N)的辅助空间

 归并排序需要两两比较,可以保证值相等的元素保持原来的顺序不变,也就是不存在跳跃,因此它是稳定的算法

综上:归并排序是稳定高效,比较占用内存的算法

你可能感兴趣的:(八大排序算法,排序算法,分治算法)