尚硅谷数据结构与算法(Java)--17--归并排序

:归并排序 

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

 图片链接https://www.runoob.com/wp-content/uploads/2019/03/mergeSort.gif

 

package com.atguigu.sort;

import java.text.SimpleDateFormat;
import java.time.Clock;
import java.util.Arrays;
import java.util.Date;

//归并排序
public class MergeSort {

	public static void main(String[] args) {
		// 
		int[] arr = {8,4,5,7,1,3,6,2};//8->merge 7 // 80000 -> 80000-1
		int temp[] = new int[arr.length];//归并排序需要一个额外空间
		System.out.println("归并排序前:"+Arrays.toString(arr));
		mergeSort(arr, 0, arr.length-1, temp);
		System.out.println("归并排序后:"+Arrays.toString(arr));
		
		timeSort();
	}

	//分+合 方法
	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);
		}
	}
	
	
	//合并的方法
	/**
	 * @param arr 排序的原始数组
	 * @param left 左边有序序列的初始索引
	 * @param mid 中间索引
	 * @param right 右边索引
	 * @param temp 作为中转的数组
	 */
	public static void merge(int[] arr,int left,int mid,int right,int[] temp) {
//		System.out.println("xxx");
		int i = left;//初始化i,左边有序序列的初始索引
		int j = mid + 1;//初始化j,右边有序序列的初始索引
		int t = 0;// 指向temp数组的当前索引
		
		//(一) 先把左右两边(有序)的数据按照规则填充到temp数组
		//直到左右两边的有序数组,有一边被处理完毕(全部插入到了临时数组temp)
		while(i<=mid && j<=right) {
			//如果左边的有序序列的当前元素,小于右边有序序列的当前元素
			//则将左边的当前元素,添加到temp数组,然后 t++ ,i++
			if(arr[i]<=arr[j]) {
				temp[t] = arr[i];
				i++;
				t++;
			}else {//反之,将右边的当前元素,添加到temp数组,然后 t++ ,j++
				temp[t] = arr[j];
				j++;
				t++;
			}
		}
		//(二)
		//把剩余数据一边数据依次填充到temp
		while(i<=mid) {//左边的有序序列还有剩余
			temp[t] = arr[i];
			t++;
			i++;
		}
		while(j<=right) {//右边的有序序列还有剩余
			temp[t] = arr[j];
			t++;
			j++;
		}
		//(三)
		//将temp数组的元素拷贝到arr
		//注意:并不是每次都拷贝所有
		t = 0;
		int tempLeft = left;//
		//第一次合并tempLeft=0,right=1 // 第二次tL=2, right=3 //第三次 tL=0,right=3
		//最后一次合并 templeft =0,right =7;
//		System.out.println("tempLeft:"+tempLeft+"right:"+right);
		while(tempLeft <= right) {
			arr[tempLeft] = temp[t];
			t += 1;
			tempLeft += 1;
		}
	}

	// 耗时测试
	public static void timeSort() {
		// 测试排序的速度(O(n^2)),给80000个数据
		// 创建一个80000个随机数的数组
		int[] arr = new int[8000000];
		int temp[] = new int[arr.length];//归并排序需要一个额外空间
		for (int i = 0; i < 8000000; i++) {
			arr[i] = (int) (Math.random() * 8000000);// 生成一个【0,8000000】数
		}

		Date data1 = new Date();
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String date1Str = simpleDateFormat.format(data1);
		System.out.println("800万个随机数据-排序前的时间是: " + date1Str);
		//获取排序前时间
	    long s = Clock.systemDefaultZone().millis();
		mergeSort(arr,0,arr.length-1,temp);
		//打印 八万个随机数据【希尔排序-交换法】 总耗时间
	    System.out.println("800万个随机数据【归并排序】耗时: " + (Clock.systemDefaultZone().millis() - s) + " ms");
		Date data2 = new Date();
		
		String date2Str = simpleDateFormat.format(data2);
		System.out.println("800万个随机数据-排序后的时间是: " + date2Str);
		
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值