排序算法之归并排序
归并排序介绍
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer )策略,分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案”修补”在一起,即分而治之
将两个的有序数列合并成一个有序数列,称之为”归并”
归并排序基本思想
(1)分(分解):一开始对当前数组一分为二,并求出当前数组的中间索引 int middleIndex = (startIndex + endIndex) / 2;
(2)求解:递归地对两个子数组array[startIndex …middleIndex ]、array[middleIndex +1…endIndex]进行归并排序,递归的结束条件是子数组的长度为1
(3)治(合并):将已排序的两个子数组array[startIndex …middleIndex ]、array[middleIndex +1…endIndex]合并为一个有序的子数组array[startIndex …endIndex]
归并排序图解过程
将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终有序序列[1,2,3,4,5,6,7,8],步骤 如下
代码实现
package com.zzb.sort;
import java.util.Arrays;
/**
* @Auther: Administrator
* @Date: 2020/3/10 12:41
* @Description: 归并排序
*/
public class MergeSort {
public static void main(String[] args) {
int[] array = {8, 4, 5, 7, 1, 3, 6, 2};
// 每次合并时,存放有序序列的临时数组
int[] tempArray = new int[array.length];
mergeSort(array, 0, array.length - 1, tempArray);
System.out.println(Arrays.toString(array));
/*[1, 2, 3, 4, 5, 6, 7, 8]*/
}
/**
* 归并排序算法(题外话:整个算法类似于二叉树的节点的后序遍历操作)
* @param array 将要被拆分的数组
* @param startIndex 将要被拆分数组的头部索引
* @param endIndex 将要被拆分数组的尾部索引
* @param tempArray 每次合并时,存放有序序列的临时数组
*/
private static void mergeSort(int[] array, int startIndex, int endIndex, int[] tempArray) {
// 对数组进行递归拆分,直到每一个子数组中只有一个元素时递归拆分结束
if(startIndex < endIndex) {
// 被拆分数组的中间索引
int middleIndex = (startIndex + endIndex) / 2;
// 左递归拆分数组(题外话:整个算法类似于二叉树的节点的后序遍历操作)
mergeSort(array, startIndex, middleIndex, tempArray);
// 右递归拆分数组(题外话:整个算法类似于二叉树的节点的后序遍历操作)
mergeSort(array, middleIndex + 1, endIndex, tempArray);
// 合并排序
merge(array, startIndex, middleIndex, endIndex, tempArray);
}
}
/**
* 归并排序算法 合并两个有序序列为一个有序序列(题外话:整个算法类似于二叉树的节点的后序遍历操作)
* @param array 被拆分后的待排序数组
* @param startIndex 被拆分后的待排序数组的头部索引
* @param middleIndex 被拆分后的待排序数组的中间索引
* @param endIndex 被拆分后的待排序数组的尾部索引
* @param tempArray 每次合并时,存放有序序列的临时数组
*/
private static void merge(int[] array, int startIndex, int middleIndex, int endIndex, int[] tempArray) {
// startIndex 至 endIndex(包括startIndex与endIndex)索引之间的元素被拆分为两个子数组后,左边子数组的开始索引
// 初始值为startIndex
int left = startIndex;
// startIndex 至 endIndex(包括startIndex与endIndex)索引之间的元素被拆分为两个子数组后,左边子数组的结束索引
int right = middleIndex;
// startIndex 至 endIndex(包括startIndex与endIndex)索引之间的元素被拆分为两个子数组后,右边子数组的开始索引
// 初始值为middleIndex+1
int l = middleIndex+1;
// startIndex 至 endIndex(包括startIndex与endIndex)索引之间的元素被拆分为两个子数组后,右边子数组的结束索引
int r = endIndex;
// 临时数组tempArray初始值
int tempArrayIndex = 0;
// 左右子数组中的元素比较大小进行排序
while(left <= right && l <= r) {
if(array[left] < array[l]) {
tempArray[tempArrayIndex] = array[left];
left ++;
tempArrayIndex ++;
}
if(array[left] > array[l]) {
tempArray[tempArrayIndex] = array[l];
l ++;
tempArrayIndex ++;
}
}
// 存在左边子数组或者右边子数组有剩余元素的可能
while(left <= right) {
tempArray[tempArrayIndex] = array[left];
left ++;
tempArrayIndex ++;
}
while(l <= r) {
tempArray[tempArrayIndex] = array[l];
l ++;
tempArrayIndex ++;
}
// 把临时数组tempArray已排序好的元素复制到原数组array中的相应索引位置
tempArrayIndex = 0;
while(startIndex <= endIndex) {
array[startIndex] = tempArray[tempArrayIndex];
startIndex ++;
tempArrayIndex ++;
}
}
}
还没有评论,来说两句吧...