在20级新生刷题组中我遇到了用分治法求最大值与最小值的算法题,初看一脸懵,深入 初步的了解中突然发现跟二分法(一次划分)有着惊人的相似,好吧qaq,其实二分法就是属于分治法的一种。
首先,分治法顾名思义,即为分而治之,把一个整理的多个数据,分成多块的少个数据来处理。
我们来演示:
输入五个数:9 5 7 3 10
根据首位数下标加上末尾数的下标除以2找到这组分组的中点mid,用i来表示每个分组的第一位下标,j表示每组最后一个数的下标。
9 5 7 3 10
i =0 mid =2 j=4
接下来就是分组啦~ 分别在9 5 7 和 7 3 10 这两组中找到最大值和最小值 。同理再分别找到中点mid,然后再进行分组找最大和最小数为:9 5 和5 7。当每组只有两个数的时候就可以进行比较啦,如果是找最大,就返回较大的值,如果是找最小,就返回较小的值 ,这时就能完成每两个数为一组的最值了,然后返回的那个最值返回到每三个数为一组 的那个函数也就是 9 5 7 这组数,当找最大值时返回的两个 数分别为9和7.然后再从这两个数中找到最值返回,(找最大值)返回即是9,这时候前三个的最值已经找到了,也就是一分为二的其中一组最值找到了,现在就剩下后面那组了,同理可得,7 3 10 (①7 3 ➡7,②3 10➡10,③7 10➡10)三次分组最终返回的最值也就是10 。在这里我们就得到了将整个数组中的所有数分成两组分别返回的两个最值为9和10,最后就剩下比较这两个值就能得到整个数组的最值啦。9 10➡ 10.所以整个数组的最大值为10。这就是分治法了呢,将数据的一个个分成块(分而治之)看到这你们是不是也与我一样有种跟二分法同根本源的感觉呢。
接下来就是源代码啦
int max(int a[],int i,int j) // 从主函数传来头和尾的地址 i, j
{
int mid,num1,num2; // mid 为这组数的中点下标.num1,num2分别来接受再两组数找到的最大值.将较大值的返回给上一层
mid=(i+j)/2; //这里(i+j)/2是找到了中点
if(i==j) //判断当只有一个数时,就返回它本身,即本身为较大值
return a[i];
else if(i+1==j) //i+1==j,表示的就是首尾,即为这组数只有两个数的时候就能够直接比较判断哪个较大,返回较大的数
return a[i]>a[j]?a[i]:a[j];
else
{
num1= max(a,i,mid); //如果前两种情况都不满足就是表示有多个数.将从第一个数开始到中点数归为一组,找到最值
num2=max(a,mid,j); //这里的就是从中点数一直到最后一个数归为一组来找最值。
return num1>num2?num1:num2; //接下来就是返回最值。
}
}
int min(int a[],int i,int j) //找最小值同理找最大值
{
int mid,num1,num2;
mid=(i+j)/2;
if(i==j)
return a[i];
else if(i+1==j)
return a[i]<a[j]?a[i]:a[j];
else
{
num1= min(a,i,mid);
num2=min(a,mid,j);
return num1<num2?num1:num2;
}
}