在使用二分法时必须保证数列是有序的,因此对应到数学问题上实际上解决的是单调函数的求解问题。通过二分法查找其中一个元素key,则转换为数学问题求f(x)=key的解。
但是一旦数列不是单调的,那么二分法就无法使用了,因为循环判断中不能确定左右区间的划分,于是对于函数有凹凸性的情况,便引入了三分法的使用场景。
欲求某个函数的极值点及极值,将区间[l,r]分为三部分,需要两个分界点m1和m2,如下
根据上述函数图像观察到f(m1)>f(m2),即m2离极小值点更近,为了让区间不断趋近极小值点,r不动,将l趋向m1,所以有l=m1。
当f(m1)<f(m2),即m1点离极小值点更近,此时缩小区间则应让l不动,r趋近到m2,有r=m2
若f(m1)=f(m2)则同理,为了简化代码,我们在这里将相等的情况与小于的情况合并
这里我们求函数的极小值即极小值点来试试,代码如下:
/**
* 函数方程(可自己定义)
* @param x
* @return
*/
private static double function(double x){
return x*x+3*x+6;
}
/**
* 三分法
* @param l:区间左边界
* @param r:区间右边界
* @return 极值点的位置
*/
private static double tripleSearch(double l,double r){
while(l+EIS<r){ //EIS=10e-6,即10的-6次方; 因为所有参数为双精度型,不能直接用l<r
double mid1=(l+r)/2;
double mid2=(mid1+r)/2;
if(function(mid1)<=function(mid2)){
r=mid2;
}else {
l=mid1;
}
}
return l;
}
main函数:
public static void main(String[] args) {
System.out.println(String.format("%.2f",tripleSearch(-2,1)));
System.out.println(String.format("%.2f",function(tripleSearch(-2,1))));
}
运行结果如下,经过验算,正确,over!