简介
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 —–百度百科
先红色的归并,再蓝色的,再紫色
代码
/**
* 归并函数
* @param array 数组
*/
public static void mergeSort(int[] array)
{
//每次每份的过程1 2 4 8 16 -------小于array.length
for (int i = 1; i < array.length; i= i *2) {
//根据份数归并排序
merge(array,i);
}
}
/**
* 归并
* @param array 数组
* @param i 每一个归并段的数据个数
*/
private static void merge(int[] array, int i) {
//指引变量
int s1,e1,s2,e2;
//指向第一份的头
s1 = 0;
//执向第二份的头
s2 = s1+i;
//指向第一份的尾
e1 = s1+i-1;
//指向第二份的尾,因为有可能第二份不完全,所以要进行判别
//如果s2本来的位置大于array.length
//所以当越界的时候需要将其拉回到数组的最后一个下标处
e2 = s2+i-1 > (array.length-1) ? array.length-1 : s2+i-1;
//一个临时数组用来放已经归并完成的数组段
int [] tempArr = new int[array.length];
//tempArr的下标
int temp = 0;
//循环直到第二份的头超越array.length及s2循环到整个数组最后
while(s2 < array.length)
{
//循环直到一份全部合并结束
while(s1<=e1&&s2<=e2)
{
//如果s1位置的比s2大,插入最小的s2
if(array[s1]>array[s2])
{
tempArr[temp++] = array[s2++];
}
//反之亦然
else{
tempArr[temp++] = array[s1++];
}
}
//因为有可能某个部分没全部插入,此处需要将剩下的补充进去
//当s1没合并完的时候
while(s1<=e1)
{
//将剩余的放进去
tempArr[temp++] = array[s1++];
}
//同上等s2没合并完的时候
while(s2<=e2)
{
tempArr[temp++] = array[s2++];
}
//重新设置s1 s2 e1 e2的指向下标
s1 = e2+1;
s2 = s1+i;
e1 = s1+i-1;
e2 = s2+i-1>(array.length-1)?array.length-1:s2+i-1;
}
//剩下的s1 --- e1直接的数
while(s1<array.length)
{
tempArr[temp++] = array[s1++];
}
//将临时数组的数放回到原数组
for (int j = 0; j <array.length; j++) {
array[j] = tempArr[j];
}
}
测试
public static void main(String[] args) {
int[] a = {3,43,546,76,34,13,673,31};
System.out.println("原数组为:"+Arrays.toString(a));
System.out.println();
mergeSort(a);
System.out.println(Arrays.toString(a));
}
结果
原数组为:[3, 43, 546, 76, 34, 13, 673, 31]
[3, 13, 31, 34, 43, 76, 546, 673]
逐步分析
第一次合并
i=2
第二次合并
i=4
第三次合并
i=8
相当于每次只合并于一段,使得一段有序。
合并的过程
以i=4为例子
设置指引下标
比较s1,s2根据不同情况进行移动直到某一个存放完毕
s1超越e1
s2未合并完,将s2剩余的合并回去
完成合并