归并排序(Merge Sort)
基本思想:
归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
归并排序示例:
合并方法:
设r[i…n]由两个有序子表r[i…m]和r[m+1…n]组成,两个子表长度分别为n-i +1、n-m。
- j=m+1;k=i;i=i; //置两个子表的起始下标及辅助数组的起始下标
- 若i>m 或j>n,转⑷ //其中一个子表已合并完,比较选取结束
- //选取r[i]和r[j]较小的存入辅助数组rf
如果r[i]<r[j],rf[k]=r[i]; i++; k++; 转⑵
否则,rf[k]=r[j]; j++; k++; 转⑵ - //将尚未处理完的子表中元素存入rf
如果i<=m,将r[i…m]存入rf[k…n] //前一子表非空
如果j<=n , 将r[j…n] 存入rf[k…n] //后一子表非空 - 合并结束。
/*
* 两个有序子列的归并,两个子列的长度都相等,为length
* 两个有序子列归并后,存入在数组temp中
*/
public static void merge(int[] a,int[] temp,int length,int l,int r){
int begin = l;
int leftend = r -1;
int rightend = r+length-1;
while(l<=leftend && r<=rightend){
if(a[l] > a[r]){
temp[begin++] = a[r++];
}else{
temp[begin++] = a[l++];
}
}
while(r<=rightend){
temp[begin++] = a[r++];
}
while(l<=leftend){
temp[begin++] = a[l++];
}
}
一个无序的序列可以采用分而治之的思想:
(1)从长度为1的子序列开始归并,则变成了都是长度为2的有序子序列;
(2)按长度为2的子序列开始归并,则变成了都是长度为4的有序子序列;
(3)。。。。
(4)归并结束。
序列归并的非递归算法
/*
* 6、归并排序
* 非递归归并实现
* 把一个序列,从0下标开始,先对1对数进行归并,然后再对2对数进行归并。。。
*/
public static void merge_sort(int[] a,int n){
int length = 1;//归并子序列的长度
int[] temp = new int[n];
while(length<n){
merge_pass(a, temp, n, length);
length *= 2;
merge_pass(temp, a, n, length);
length *= 2;
}
}
/*
* 完成一躺子序列归并
* length为归并子序列的长度
*/
public static void merge_pass(int[] a,int[] temp,int n,int length){
int i = 0;
for (; i <= n-2*length; i=2*length+i) {
merge(a, temp, length, i, i+length);
}
if(i+length<n){//最后还剩下大于等于一个子列长度
merge(a, temp, n-i-length, i, i+length);
}else{//最后只剩下小于一个子列长度,则直接赋值
for (int j = i; j < n; j++) {
temp[j] = a[j];
}
}
System.out.print("子列长为"+length+"归并: ");
display(temp);
}
/*
* 两个有序子列的归并,两个子列的长度都相等,为length
* 两个有序子列归并后,存入在数组temp中
*/
public static void merge(int[] a,int[] temp,int length,int l,int r){
int begin = l;
int leftend = r -1;
int rightend = r+length-1;
while(l<=leftend && r<=rightend){
if(a[l] > a[r]){
temp[begin++] = a[r++];
}else{
temp[begin++] = a[l++];
}
}
while(r<=rightend){
temp[begin++] = a[r++];
}
while(l<=leftend){
temp[begin++] = a[l++];
}
}
测试代码:
public static void main(String[] args) {
int[] a = {3,2,4,6,11,3,34,27,2,1,22,9,45,6};
int[] temp = new int[a.length];
System.out.print("子序列归并之前: ");
display(a);
merge_sort(a, a.length);
}
结果为:
子序列归并之前: 3 2 4 6 11 3 34 27 2 1 22 9 45 6
子列长为1归并: 2 3 4 6 3 11 27 34 1 2 9 22 6 45
子列长为2归并: 2 3 4 6 3 11 27 34 1 2 9 22 6 45
子列长为4归并: 2 3 3 4 6 11 27 34 1 2 6 9 22 45
子列长为8归并: 1 2 2 3 3 4 6 6 9 11 22 27 34 45