归并排序采用的是分——合的策略,什么是分?什么是合?我们举个例子,例如要对长度为n的序列a排序,我们可以将序列a均分成两个部分,并且对着两个部分分别进行排序,这便是分。将排好序的两个部分按顺序整合到一起,这便是合。这样通过先分再合,就对序列a进行了排序。
归并序列的难点在于合,两个排好序的序列如何合并成一个序列呢?(本文采用小到大的排序)通过比较两个序列的第一个数得到较小的一个,取该数赋值给合并序列的第1个数,并删除该数,然后再比较两个序列的第一个数,并取得较小的一个,取该数赋值给合并序列的第2个数,并删除该数。依次类推直到合并序列被填满。
static int[] b=new int[100000];
static void mergeArray(int l,int r)
{
//第一个序列为a[l]~a[mid],第二个序列为a[mid+1]~a[l]
if(l==r) return;
int mid=(l+r)/2;
for(int i=l;i<=r;i++)
{
b[i]=a[i];
}
int x=l;int y=mid+1;
for(int i=l;i<=r;i++)
{
if(x>mid)
{
a[i]=b[y++];
}else if(y>r)
{
a[i]=b[x++];
}else if(b[x]<b[y])
{
a[i]=b[x++];
}else
{
a[i]=b[y++];
}
}
}
从上面的代码可以分析出,要合并一个长度为N的序列,复杂度为O(N)。
合是在两个已经排好序的序列的基础上进行的,假设A、B两个序列都已经排好序,那么很容易将这两组序列合并。那么如何让A、B有序呢?我们可以采用同样的策略分别对A、B进行排序,即将A、B分别均分成两个部分。依次类推,知道序列中只剩下一个数,我们就认为该序列是有序的。然后再讲这些有序序列两两合并。
static void mergeSort(int l,int r)
{
if(r==l) return;
int mid=(l+r)/2;
mergeSort(l, mid);//l——>mid排好了序
mergeSort(mid+1, r);//mid+1——>r排好了序
mergeArray(l, r);//合并上面已经排序好的两个序列
}