什么是归并排序?
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。(来自百度,其实这里看不看也行…)
嗯,下面才是正文。
如何对一组数进行归并排序…
先假设那组数是 { 3 , 2 , 4 , 1 , 5 , 9 , 6 }
还有几个要点..
- 单独的一个数具有 有序性 。
- 归并排序的执行步骤为拆分,然后合并。
- 归并排序的核心是将两个有序数组合并为一个有序数组。
思路分析
一,使用分治策略不断拆分得到有序数组。
拆分的顺序:
- { 3 , 2 , 4 , 1 } , { 5 , 9 , 6 }
- { 3 , 2 } , { 4 , 1 } , { 5 , 9 } , { 6 }
- { 3 } , { 2 } , { 4 } , { 1 } , { 5 } , { 9 } , { 6 }
二,将两个有序数组合并为一个有序数组。
因为单独的一个数可以看作为有序的.所以在拆分到第三步的时候,每个数组只有一个数,也就是说它们都是有序数组。
然后,用A和B分别表示两个待合并的有序数组。
待合并的有序数组 |
---|
A = { 3 } |
B = { 2 } |
显然,这里我们可以直接对比两个数的大小,得出一个有序数组{ 2 , 3 }。
下一步,我们再将 { 4 } 和 { 1 } 合并,得出 { 1 , 4 },再将 { 2 , 3 }和{ 1 , 4 }进行合并..
这里需要定义几个变量…
- int a :用于标记数组A中的数.
- int b :用于标记数组B中的数.
- int[] t :一个新的数组,用于数组合并,其长度为 数组A的长度与数组B的长度的和..
a=0;b=0 | a=0;b=1; | a=1;b=1; | a=2;b=1; |
---|---|---|---|
A={ 2 , 3 } | A={ 2,3 } | A={3} | A={} |
B={ 1 , 4 } | B={4} | B={4} | B={4} |
A[a] > B[b] | A[a] < B[b] | A[a] < B[b] | A为空数组 |
t[0]=B[b],b++ | t[1] = A[a],a++ | t[2] = A[a],a++ | t[3] = B[b],b++ |
/*这是用于合并数组的代码..
isEmpty方法返回一个数组是否为空..
*/
for( int index = 0 ; index<t.length ; index++ )
if( isEmpty(A) || ( !isEmpty(B) && A[a]>B[b] )
t[index] = B[b++];
else
t[index] = A[a++];
唔,然后我随手画了一张总流程图….用于观察..
要相信,这图是有意义的。
我们可以观察到,在合并的时候,才会发生数的交换,所以根据此特性,我们可以忽略拆分的步骤,直接进行合并操作。
下面是核心代码…这是我第三次优化后的实现…我认为比网上的代码都要优美和直观多了….
/*
Nums为需要进行排序的数组..
*/
private void sort(){
for(int i = 1 ; i<Nums.length ; i*=2){
for(int j = 0 ; j<Nums.length ; j+=(i*2) ){
//如果i+j>Nums.length,那么就不需要执行,因为已经是有序。
//关于这里为什么是有序的,我觉得值得大家去思考。
if(i+j < Nums.length){
if( 2*i+j > Nums.length )
merge(j,j+i,Nums.length-j);
else
merge(j,j+i,2*i);
}
}
}
}
private void merge(int a,int b,int size){
int N = a;//标记数组t在原数组Nums的位置,
int A_Length = b;//标记数组A的长度
int B_length = a+size;//标记数组B的长度
int[] t = new int[size];//创建数组t来构建有序数组..
for(int index = 0; index < size ;index++)
if( a == A_Length || ( b != B_length && Nums[a]>Nums[b] ) ){
t[index] = Nums[b++];
}else{
t[index] = Nums[a++];
}
for(int i = 0;i<t.length;i++){
Nums[N++] = t[i];
}
}