当我们面对复杂而庞大的问题时,寻找一种有效的解决方案显然是至关重要的。在计算机科学和算法设计领域,有一种被广泛运用的问题解决策略——分而治之(Divide and Conquer)。
分而治之的核心思想是将一个复杂的问题划分成一系列更小、更易解决的子问题,通过递归地解决这些子问题,最后将它们的解合并起来得到原问题的解。这种策略不仅在算法设计中占据着重要地位,而且在各个领域都有着广泛的应用。
分而治之算法设计策略包含三个关键步骤:分解、征服、合并
1. 分解(Divide):
- 目的: 将原问题分解成规模较小的、相似的子问题。
- 操作: 将原问题划分为若干个规模较小的子问题。这一步骤要求划分的子问题应该是相互独立的,且与原问题具有相同的结构。
- 实现: 通常通过递归的方式实现分解。每个子问题都是原问题的一个简化版本,继续应用分而治之策略,直至问题规模足够小以直接求解。
2. 征服(Conquer):
- 目的: 通过递归地解决子问题,得到它们的解。
- 操作: 对每个子问题应用相同的分而治之策略。当子问题规模足够小时,直接求解得到结果。
- 实现: 通过递归调用算法自身,将子问题分解为更小的子问题,直到达到基本情况,然后开始逐层向上合并解。
3. 合并(Combine):
- 目的: 将子问题的解合并成原问题的解。
- 操作: 将各个子问题的解按照一定规则合并,得到原问题的解。这可能涉及到对子问题的结果进行组合、比较或其他操作。
- 实现: 通过递归调用树的合并操作,将子问题的解逐步合并,直到最终得到整体问题的解。
分而治之的经典算法
- 归并排序
void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex){
int i = startIndex, j=midIndex+1, k = startIndex;
while(i!=midIndex+1 && j!=endIndex+1) {
if(sourceArr[i] > sourceArr[j])
tempArr[k++] = sourceArr[j++];
else
tempArr[k++] = sourceArr[i++];
}
while(i != midIndex+1) //对两个数组进行合并
tempArr[k++] = sourceArr[i++];
while(j != endIndex+1)
tempArr[k++] = sourceArr[j++];
for(i=startIndex; i<=endIndex; i++) //合并临时数组tempArr覆盖原数组sourceArr
sourceArr[i] = tempArr[i];
}
//内部使用递归
void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex) {
int midIndex;
if(startIndex < endIndex) {
midIndex = startIndex + (endIndex-startIndex) / 2;//避免溢出int
MergeSort(sourceArr, tempArr, startIndex, midIndex);
MergeSort(sourceArr, tempArr, midIndex+1, endIndex);
//不要用midIndex-1,因为midIndex可能等于0
Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
}
}
int main() {
int a[] = {50, 10, 20, 30, 70, 40, 80, 60};
int i, b[8];
MergeSort(a, b, 0, 7);
for(int i=0; i<8; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
- 快速排序
int Partition(int a[],int p,int r)
{
int i=p;
int j=r+1;
int x=a[p]; //以左端点的值作为分界值
while(1)
{
while(a[++i]<x&&i<=r); //i有可能越界
while(a[--j]>x);
if(i>=j)break;
int t=a[i];a[i]=a[j];a[j]=t;
}
int t=a[j];a[j]=a[p];a[p]=t;
return j;
}
void QuickSort(int a[],int p,int r)
{
if(p >= r)return; //等号不要忘记
int q=Partition(a,p,r); //核心在于找分界点
QuickSort(a,p,q-1);
QuickSort(a,q+1,r);
}
int main()
{
int a[N];
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
QuickSort(a,0,n-1);
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
}