归并排序

一、需求

  • 利用归并排序实现一个数组的升序排列,一般来说要求数组满足[左数组 | 右数组];
  • 其中左、右数组是有序的,例如[2,8,9,10,4,5,6,7],其中左数组为[2,8,9,10],右数组为[4,5,6,7];

二、归并排序

2.1  思路分析

  1. 原理就是合并两个有序数组,可以利用三指针来解决;

2.2  代码实现

class Solution {
	
	public static void merge(int[] arr,int left,int mid,int right) {
		//初始化左、右子数组长度
		int leftSize = mid - left;
		int rightSize = right - mid + 1;
		//新建左、右子数组
		int[] leftArr = new int[leftSize];
		int[] rightArr = new int[rightSize];
		//初始化左、右子数组
		for(int i = 0; i < leftSize; i++) {
			leftArr[i] = arr[i];
		}
		for(int j = 0; j < rightSize; j++) {
			rightArr[j] = arr[j+mid];
		}
		//新建三指针
		int i = 0;
		int j = 0;
		int k = 0;
		//开始合并有序数组
		while(i < leftSize && j < rightSize) {
			if(leftArr[i] < rightArr[j]) {
				arr[k] = leftArr[i];
				i++;
				k++;
			} else {
				arr[k] = rightArr[j];
				j++;
				k++;
			}
		}
		while(i < leftSize) {
			arr[k] = leftArr[i];
			i++;
			k++;
		}
		while(j < rightSize) {
			arr[k] = rightArr[j];
			j++;
			k++;
		}
	}
	
	public static void main(String[] args) {
		int[] arr = {2,8,9,10,4,5,6,7};
		merge(arr,0,4,7);
		for(int i = 0; i < arr.length; i++) {
			System.out.println(arr[i]);
		}
	}
}

三、归并排序+分治法

3.1  思路分析

  1. 上面的实现中要求待排序数组的左、右子数组是有序的,能不能去除这个限制条件,即能不能利用归并排序使得任意一个无序数组是有序的;
  2. 这就需要用到分治思想,如图所示,通过将无序数组逐步分解成子数组,一直分解到数组中只有一个值为止,然后就合并子数组,一直返回到最上层;
  3. 归并排序的时间复杂度为O(nlog_2n),空间复杂度为O(n)

                                                                            

3.2  代码实现

class Solution {
	/**
	 * 该方法是合并两个有序数组,即归并思想
	 * 假定左子数组区间[left,mid),右子数组区间[mid,right]
	 * @param arr
	 * @param left
	 * @param mid
	 * @param right
	 */
	public static void merge(int[] arr,int left,int mid,int right) {
		//初始化左、右子数组长度
		int leftSize = mid - left;
		int rightSize = right - mid + 1;
		//新建左、右子数组
		int[] leftArr = new int[leftSize];
		int[] rightArr = new int[rightSize];
		//初始化左、右子数组
		for(int i = left; i < mid; i++) {
			leftArr[i-left] = arr[i];
		}
		for(int j = mid; j <= right; j++) {
			rightArr[j-mid] = arr[j];
		}
		//新建三指针
		int i = 0;
		int j = 0;
		int k = left;
		//开始合并有序数组
		while(i < leftSize && j < rightSize) {
			if(leftArr[i] < rightArr[j]) {
				arr[k] = leftArr[i];
				i++;
				k++;
			} else {
				arr[k] = rightArr[j];
				j++;
				k++;
			}
		}
		while(i < leftSize) {
			arr[k] = leftArr[i];
			i++;
			k++;
		}
		while(j < rightSize) {
			arr[k] = rightArr[j];
			j++;
			k++;
		}
	}
	/**
	 * 该方法用来实现对无序数组的排序
	 * 假定左子数组区间[left,mid],右子数组区间[mid+1,right]
	 * @param arr
	 * @param left
	 * @param right
	 */
	public static void mergeSort(int[] arr,int left,int right) {
		if(left == right) return;
		int mid = left + (right - left)/2;
		mergeSort(arr,left,mid);
		mergeSort(arr,mid+1,right);
		merge(arr,left,mid+1,right);
	}
	
	public static void main(String[] args) {
		int[] arr = {6,8,9,10,1,5,2,7};
		mergeSort(arr,0,7);
		//merge(arr,0,4,7);
		for(int i = 0; i < arr.length; i++) {
			System.out.println(arr[i]);
		}
	}
}

四、归并排序+分治法2

4.1  思路分析

  1. 这一次修改边界条件做一下,将M前移一位;

4.2  代码实现

class Solution {
	/**
	 * 该方法是合并两个有序数组,即归并思想
	 * 假定左子数组区间[left,mid],右子数组区间[mid+1,right]
	 * @param arr
	 * @param left
	 * @param mid
	 * @param right
	 */
	public static void merge(int[] arr,int left,int mid,int right) {
		//初始化左、右子数组长度
		int leftSize = mid - left + 1;
		int rightSize = right - mid ;
		//新建左、右子数组
		int[] leftArr = new int[leftSize];
		int[] rightArr = new int[rightSize];
		//初始化左、右子数组
		for(int i = left; i <= mid; i++) {
			leftArr[i-left] = arr[i];
		}
		for(int j = mid+1; j <= right; j++) {
			rightArr[j-mid-1] = arr[j];
		}
		//新建三指针
		int i = 0;
		int j = 0;
		int k = left;
		//开始合并有序数组
		while(i < leftSize && j < rightSize) {
			if(leftArr[i] < rightArr[j]) {
				arr[k] = leftArr[i];
				i++;
				k++;
			} else {
				arr[k] = rightArr[j];
				j++;
				k++;
			}
		}
		while(i < leftSize) {
			arr[k] = leftArr[i];
			i++;
			k++;
		}
		while(j < rightSize) {
			arr[k] = rightArr[j];
			j++;
			k++;
		}
	}
	/**
	 * 该方法用来实现对无序数组的排序
	 * 假定左子数组区间[left,mid],右子数组区间[mid+1,right]
	 * @param arr
	 * @param left
	 * @param right
	 */
	public static void mergeSort(int[] arr,int left,int right) {
		if(left == right) return;
		int mid = left + (right - left)/2;
		mergeSort(arr,left,mid);
		mergeSort(arr,mid+1,right);
		merge(arr,left,mid,right);
	}
	
	public static void main(String[] args) {
		int[] arr = {6,8,9,10,1,5,2,7};
		mergeSort(arr,0,7);
		//merge(arr,0,4,7);
		for(int i = 0; i < arr.length; i++) {
			System.out.println(arr[i]);
		}
	}
}

4.3  重载merge方法试一试

class Solution {
	/**
	 * 该方法是合并两个有序数组,即归并思想
	 * 假定左子数组区间[left,mid],右子数组区间[mid+1,right]
	 * @param arr
	 * @param left
	 * @param mid
	 * @param right
	 */
	public static void merge(int[] arr,int left,int mid,int right) {
		//初始化左、右子数组长度
		int leftSize = mid - left + 1;
		int rightSize = right - mid ;
		//新建左、右子数组
		int[] leftArr = new int[leftSize];
		int[] rightArr = new int[rightSize];
		//初始化左、右子数组
		for(int i = left; i <= mid; i++) {
			leftArr[i-left] = arr[i];
		}
		for(int j = mid+1; j <= right; j++) {
			rightArr[j-mid-1] = arr[j];
		}
		//新建三指针
		int i = 0;
		int j = 0;
		int k = left;
		//开始合并有序数组
		while(i < leftSize && j < rightSize) {
			if(leftArr[i] < rightArr[j]) {
				arr[k] = leftArr[i];
				i++;
				k++;
			} else {
				arr[k] = rightArr[j];
				j++;
				k++;
			}
		}
		while(i < leftSize) {
			arr[k] = leftArr[i];
			i++;
			k++;
		}
		while(j < rightSize) {
			arr[k] = rightArr[j];
			j++;
			k++;
		}
	}
	/**
	 * 该方法更具一般性,不用传入中间值mid
	 * @param arr
	 * @param left
	 * @param right
	 */
	public static void merge(int[] arr, int left, int right) {
		//获取中间值
		int mid = left + (right - left) / 2;
		// 初始化左、右子数组长度
		int leftSize = mid - left + 1;
		int rightSize = right - mid;
		// 新建左、右子数组
		int[] leftArr = new int[leftSize];
		int[] rightArr = new int[rightSize];
		// 初始化左、右子数组
		for (int i = left; i <= mid; i++) {
			leftArr[i - left] = arr[i];
		}
		for (int j = mid + 1; j <= right; j++) {
			rightArr[j - mid - 1] = arr[j];
		}
		// 新建三指针
		int i = 0;
		int j = 0;
		int k = left;
		// 开始合并有序数组
		while (i < leftSize && j < rightSize) {
			if (leftArr[i] < rightArr[j]) {
				arr[k] = leftArr[i];
				i++;
				k++;
			} else {
				arr[k] = rightArr[j];
				j++;
				k++;
			}
		}
		while (i < leftSize) {
			arr[k] = leftArr[i];
			i++;
			k++;
		}
		while (j < rightSize) {
			arr[k] = rightArr[j];
			j++;
			k++;
		}
	}
	/**
	 * 该方法用来实现对无序数组的排序
	 * 假定左子数组区间[left,mid],右子数组区间[mid+1,right]
	 * @param arr
	 * @param left
	 * @param right
	 */
	public static void mergeSort(int[] arr,int left,int right) {
		if(left == right) return;
		int mid = left + (right - left)/2;
		mergeSort(arr,left,mid);
		mergeSort(arr,mid+1,right);
		merge(arr,left,right);
	}
	
	public static void main(String[] args) {
		int[] arr = {6,8,9,10,1,5,2,7};
		mergeSort(arr,0,7);
		//merge(arr,0,4,7);
		for(int i = 0; i < arr.length; i++) {
			System.out.println(arr[i]);
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值