归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并排序速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列
归并操作
归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11;
逆序数为14;
归并算法描述
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
归并排序原理
归并排序具体工作原理如下(假设序列共有n个元素):
将序列每相邻两个数字进行归并操作(merge),形成floor(n/2+n%2)个序列,排序后每个序列包含两个元素
将上述序列再次归并,形成floor(n/4)个序列,每个序列包含四个元素
重复步骤2,直到所有元素排序完毕
Java实现
/**
* <p>@filename MergeSort</p>
* <p>
* <p>@description 归并排序Java实现</p>
*
* @author Java猿人一枚
* @version 1.0
* @since 2019/4/4 11:04
**/
public class MergeSort {
public static void main(String[] args) {
//测试merge方法
//int[] arr = new int[]{3,5,7,9,1,4,8};
//merge(arr, 0, 4, 6);
//System.out.println(Arrays.toString(arr));
//arr = new int[]{3,5,7,9,1,4,8};
//merge(arr, 1, 4, 5);
//System.out.println(Arrays.toString(arr));
int[] nums = new int[]{100,34,52,6,8,78,95};
System.out.println("待排序数组:" + Arrays.toString(nums));
mergeSort(nums, 0, nums.length - 1);
System.out.println("已排序数组:" + Arrays.toString(nums));
}
/**
* mergeSort
*
* @param nums 数组
* @param left 开始位置
* @param rightBound 结束位置
*/
public static void mergeSort(int[] nums, int left, int rightBound){
int mid = left + (rightBound - left) / 2;
//递归结束条件
if(left == rightBound) {
return;
}
//左边
mergeSort(nums, left, mid);
//右边
mergeSort(nums, mid + 1, rightBound);
merge(nums, left, mid + 1, rightBound);
}
/**
* 二路归并
* 原理:将两个有序表合并和一个有序表
*
* @param nums 原数组
* @param left 左侧开始位置(第一个有序表开始位置)
* @param right 右侧开始位置(第二个有序表开始位置)
* @param rightBound 右侧结束位置(第二个有序表结束位置)
*/
public static void merge(int[] nums, int left, int right, int rightBound){
int[] temp = new int[rightBound - left + 1];
int i = left, j = right, k = 0;
while(i < right && j <= rightBound){
temp[k++] = nums[i] <= nums[j] ? nums[i++] : nums[j++];
}
while(i < right){
temp[k++] = nums[i++];
}
while(j <= rightBound){
temp[k++] = nums[j++];
}
System.arraycopy(temp, 0, nums, left, temp.length);
}
}