分治递归
在求解一个输入规模为n,而n的取值又很大的问题时,直接求解往往非常困难。这时,可以先分析问题本身所具有的某些特性,然后从这些特性出发,把复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。这种方法,就是所谓的分治法。而分成的小问题类型相同的话可以用递归来实现,这就是分治递归。
三个基本步骤:
分:把大问题分解成若干个小问题。
治:把分解后的小问题求解。
合:将各个小问题的解合并。
结合实例:
归并排序 :
就是将一个数字序列从中间分成两个长度差不多的子序列,之后又对两个子序列分别执行归并排序的算法,当两个子序列变为两个有序序列之后,再将两个有序的子序列合并成一个有序的序列。
分析:我们用mergesort函数来将数字序列分为两个子序列来排序,之后用merge函数来将两个子序列合并成一个有序序列。
在merge函数中
先用b[j]来存储要合并的两个子序列的总情况
之后用m1代表左边子序列长度,m2代表两个子序列总长度;
让i遍历左边子序列的情况,j遍历右边子序列的情况,然后比大小,哪边小就把哪边输入到a数组中,因为两个子序列是有序的,所以这样对比并输入a数组后,a数组就是两个有序子序列组合成的有序序列。
之后要保证两边的子序列都遍历完了,这样得到的合成的序列才是完整的。
最后一将其输出即可。
完整代码:
#include<iostream>
#include<stdio.h>
using namespace std;
int a[100]={};
void merge(int l,int mid,int r)
{
int k=l,i=l,j=1;
int b[100]={};
for(;i<=r;i++,j++)
{
b[j]=a[i];
}
int m1=mid-l+1;
int m2=r-l+1;
i=1;
j=m1+1;
while(i<=m1&&j<=m2)
{
if(b[i]<=b[j])
{
a[k++]=b[i++];
}
else
{
a[k++]=b[j++];
}
}
while(i<=m1)
{
a[k++]=b[i++];
}
while(j<=m2)
{
a[k++]=b[j++];
}
}
void mergesort(int l,int r)
{
if(l==r) return;
int mid=(l+r)/2;
mergesort(l,mid);
mergesort(mid+1,r);
merge(l,mid,r);
}
int main()
{
int i=1,j,m,k,l,r,n;
cout<<"请输入要排序的数字序列"<<endl;
while(1)
{
cin>>a[i++];
if(getchar()=='\n')
{
break;
}
}
l=1;
r=i-1;
mergesort(l,r);
cout<<"排序后的数字序列为"<<endl;
for(i=1;i<=r;i++)
{
cout<<a[i]<<" ";
}
}
运行结果: