在上一篇文章中,我们提到QuickSort是基于分治法的,那么这一篇来介绍下分治法和归并排序。
分治法,就是把一个复杂的问题分割成两个或多个子问题,直到各个子问题的规模可以简单地求解,从而各个击破,然后再把结果整合。一般来讲,复杂度随问题规模上升的速度经常是N2、N3 甚至是 2N这种指数级别,而把结果整合起来大多数可以达到N甚至是常数(如选择TOP1)。
确切的说,分治法应该算作一种思想,而不是具体的算法,随着海量数据时代的到来,分治法的重要性越来越明显。
分治法思想有几种描述,但都大同小异,一般分为以下三步:
1、分解:将原问题分解为若干规模较小,相互独立,与原问题形式相同的子问题。
2、解决:判断子问题是否可以直接解决,若可以则直接解决,若不能则继续分解。
3、合并:将子问题的解合并为原问题的解。
显然,快速排序是完全符合的基本排序算法(2)——快速排序。
现在来看一个问题,对于数组a[n],他的0-k和k+1到n-1部分分别有序,对整个数组进行排序,这是典型的归并排序,算法比较简单,直接上代码:
void Merge(int *a,int startIndex,int firstEnd,int endIndex)
{
int i,j=0,k;
int len1=firstEnd-startIndex+2;
int len2=endIndex-firstEnd+1;
int *larray=new int[len1];
int *rarray=new int[len2];
larray[len1-1]=INFINITY;
rarray[len2-1]=INFINITY;
for(i=0;i<len1-1;i++)
{
larray[i]=a[i+startIndex];
}
for(i=0;i<len2-1;i++)
{
rarray[i]=a[i+firstEnd+1];
}
i=0;
for(k=startIndex;k<=endIndex;k++)
{
if(larray[i]<=rarray[j])
{
a[k]=larray[i];
i++;
}
else
{
a[k]=rarray[j];
j++;
}
}
delete[] larray;
delete[] rarray;
}
void MergeSort(int *a,int startIndex,int endIndex)
{
if(startIndex<endIndex)
{
int mid=(startIndex+endIndex)/2;
MergeSort(a,startIndex,mid);
MergeSort(a,mid+1,endIndex);
Merge(a,startIndex,mid,endIndex);
}
}
我擦泪,在这段代码参数搞错了,报了个莫名其妙的错误,还去论坛打了个酱油求助,结果没人鸟我。。。还好被我发现了,果然代码是要自己写出来才直到有什么问题
for(i=0;i<len1-1;i++)
{
larray[i]=a[i+startIndex];
}
for(i=0;i<len2-1;i++)
{
rarray[i]=a[i+firstEnd+1];
}