Algorithm 二进制搜索不具有遍历开销。是什么?
当我试图将二进制搜索应用于现实世界时,它让我失望了。情况如下 我需要测试通过无线电通信的设备的范围。 通信需要快速进行,但传输速度较慢 可以忍受,在一定程度上(比如说,大约3分钟)。我需要测试一下 传输是否每200英尺成功一次,直到失败,最多1600英尺 脚。每200英尺进行一次测试,需要3分钟才能完成 执行 <>我天真地假设二进制搜索将是找到故障点的最有效的方法,但是考虑到200英尺/分钟的行驶速度和3分钟的测试时间。如果在500英尺处发生传输故障,二进制搜索不是查找故障点的最有效方法,如下所示 简单地走过去测试每一个点就可以更快地找到解决方案,只需12分钟,而二进制搜索和测试则需要16分钟Algorithm 二进制搜索不具有遍历开销。是什么?,algorithm,big-o,traversal,binary-search,Algorithm,Big O,Traversal,Binary Search,当我试图将二进制搜索应用于现实世界时,它让我失望了。情况如下 我需要测试通过无线电通信的设备的范围。 通信需要快速进行,但传输速度较慢 可以忍受,在一定程度上(比如说,大约3分钟)。我需要测试一下 传输是否每200英尺成功一次,直到失败,最多1600英尺 脚。每200英尺进行一次测试,需要3分钟才能完成 执行 我天真地假设二进制搜索将是找到故障点的最有效的方法,但是考虑到200英尺/分钟的行驶速度和3分钟的测试时间。如果在500英尺处发生传输故障,二进制搜索不是查找故障点的最有效方法,如下所示
我的问题:当旅行时间很重要时,如何计算最有效的解决方案路径?这被称为什么(例如二进制旅行搜索等)?二进制搜索确实是基于
O(1)
访问时间;例如,在链表中进行二进制搜索几乎没有什么意义[但请参见注释1],这基本上就是您正在做的事情,因为您似乎假设只有离散区间值得测试。如果您正在寻找更准确的答案,您会发现二进制搜索允许任意精度,但每一位精度需要额外测试一次
假设您甚至不知道最大值可能是多少。然后你不能首先在中间测试,因为你不知道中间在哪里。相反,您可以对一个限制进行指数搜索(这是一种由内而外的二进制搜索);首先在x
处进行测试,然后在2x
处进行测试,然后在4x
处进行测试,直到达到大于最大值的点(信号没有到达那么远)。(x
是您感兴趣的最小答案;换句话说,如果在x
处的第一次测试显示信号未达到,您将停止。)在该阶段结束时,对于某个整数i
,您将处于2ix
,并且您将知道答案介于2i-1x
和2ix
之间
现在,您可以实际执行二进制搜索,从按2i-2x
向后开始。从那里开始,您可以向前或向后移动,但您肯定会移动2i-3x
,下一次迭代将移动2i-4x
,依此类推
总之,在第一阶段(搜索最大值),您走到了2ix
,并进行了i
测试。在第二个阶段,即二进制优化阶段,您总共执行(2i-1-1)x
并执行i-1
测试。你会在d
的某个点结束,该点介于2i-1
和2i
之间,所以最坏的情况下,你会走到最后一点的3d
(最好的情况下,你会走到3d/2
)。您将要进行的测试数量将为2*ceil(log2(d/x))-1
,这在2*log2(d/x)
的一次测试中
那么,在什么情况下应该使用二进制搜索算法呢?基本上,它取决于行程时间和测试时间的比率,以及所需的答案精度。简单的顺序算法在d/x
大小移动x
和d/x
测试后找到位置d
;上面的二进制搜索算法在最多移动3d
后查找位置d
,但只执行大约2个log(d/x)
测试。粗略地说,如果一次测试花费的成本是旅行成本的两倍以上,并且预期距离远远大于精度,那么您应该选择二进制搜索
在您的示例中,您似乎希望得到精度为200英尺的结果;行程时间为1分钟,测试时间为3分钟,超过行程时间的两倍。因此,您应该更喜欢二进制搜索,除非您希望在精度的小倍数中找到答案(如实际情况)。请注意,尽管二进制算法使用四个测试和1000英尺的行程(相比之下,顺序算法使用三个测试和600英尺),但将精度提高到50英尺只会给二进制算法增加四个测试和150英尺的行程,而顺序算法将需要20个测试
注1:实际上,如果测试的成本很高,那么使用上述算法对链表进行二进制搜索可能是有意义的。假设测试的成本与列表中的索引不成正比,对于线性搜索和二进制搜索,搜索的复杂性将是
O(N)
,但二进制搜索将执行O(logn)
测试和O(N)
步骤,而顺序搜索将执行O(N)
测试和O(N)
步骤。对于足够大的N,这并不重要,但对于实际大小的N,这可能非常重要。实际上,这里可以应用二进制搜索,但需要做一些更改。我们必须计算的不是中心,而是参观的最佳位置
int length = maxUnchecked - minChecked;
whereToGo = minChecked + (int)(length * factorIncrease) + stepIncrease;
因为我们需要找到沟通失败的第一个位置,有时我们必须返回,然后才能使用其他策略
int length = maxUnchecked - minChecked;
int whereToGo = 0;
if ( increase )
whereToGo = minChecked + (int)(length * factorIncrease) + stepIncrease;
else
whereToGo = minChecked + (int)(length * factorDecrease) + stepDecrease;
所以,我们的任务-计算出这样的最优因子增量,因子增量,步长增量,步长递减,f(failPos)之和的值将是最小的。怎么用?如果n(总长度/200.0f)很小,则全强力将帮助您。否则你可以尝试使用遗传算法或smth simple
步长精度=1,步长限制=[0,n)。
系数eps-1/(4*n),系数限值-[0,1]
现在,用简单的代码(c#)来演示:
class Program
{
static double factorIncrease;
static int stepIncrease;
static double factorDecrease;
static int stepDecrease;
static bool debug = false;
static int f(int lastPosition, int minChecked, int maxUnchecked, int last, int failPos, bool increase = true, int depth = 0)
{
if ( depth == 100 )
throw new Exception();
if ( maxUnchecked - minChecked <= 0 ) {
if ( debug )
Console.WriteLine("left: {0} right: {1}", minChecked, maxUnchecked);
return 0;
}
int length = maxUnchecked - minChecked;
int whereToGo = 0;
if ( increase )
whereToGo = minChecked + (int)(length * factorIncrease) + stepIncrease;
else
whereToGo = minChecked + (int)(length * factorDecrease) + stepDecrease;
if ( whereToGo <= minChecked )
whereToGo = minChecked + 1;
if ( whereToGo >= maxUnchecked )
whereToGo = maxUnchecked;
int cur = Math.Abs(whereToGo - lastPosition) + 3;
if ( debug ) {
Console.WriteLine("left: {2} right: {3} whereToGo:{0} cur: {1}", whereToGo, cur, minChecked, maxUnchecked);
}
if ( failPos == whereToGo || whereToGo == maxUnchecked )
return cur + f(whereToGo, minChecked, whereToGo - 1, last, failPos, true & increase, depth + 1);
else if ( failPos < whereToGo )
return cur + f(whereToGo, minChecked, whereToGo, last, failPos, true & increase, depth + 1);
else
return cur + f(whereToGo, whereToGo, maxUnchecked, last, failPos, false, depth + 1);
}
static void Main(string[] args)
{
int n = 20;
int minSum = int.MaxValue;
var minFactorIncrease = 0.0;
var minStepIncrease = 0;
var minFactorDecrease = 0.0;
var minStepDecrease = 0;
var eps = 1 / (4.00 * (double)n);
for ( factorDecrease = 0.0; factorDecrease < 1; factorDecrease += eps )
for ( stepDecrease = 0; stepDecrease < n; stepDecrease++ )
for ( factorIncrease = 0.0; factorIncrease < 1; factorIncrease += eps )
for ( stepIncrease = 0; stepIncrease < n; stepIncrease++ ) {
int cur = 0;
for ( int i = 0; i < n; i++ ) {
try {
cur += f(0, -1, n - 1, n - 1, i);
}
catch {
Console.WriteLine("fail {0} {1} {2} {3} {4}", factorIncrease, stepIncrease, factorDecrease, stepDecrease, i);
return;
}
}
if ( cur < minSum ) {
minSum = cur;
minFactorIncrease = factorIncrease;
minStepIncrease = stepIncrease;
minFactorDecrease = factorDecrease;
minStepDecrease = stepDecrease;
}
}
Console.WriteLine("best - mathmin={4}, f++:{0} s++:{1} f--:{2} s--:{3}", minFactorIncrease, minStepIncrease, minFactorDecrease, minStepDecrease, minSum);
factorIncrease = minFactorIncrease;
factorDecrease = minFactorDecrease;
stepIncrease = minStepIncrease;
stepDecrease = minStepDecrease;
//debug =true;
for ( int i = 0; i < n; i++ )
Console.WriteLine("{0} {1}", 3 + i * 4, f(0, -1, n - 1, n - 1, i));
debug = true;
Console.WriteLine(f(0, -1, n - 1, n - 1, n - 1));
}
}
这取决于你选择了什么
n = 9 mathmin = 144, f++: 0,1(1) s++: 1 f--: 0,2(2) s--: 1
n = 20 mathmin = 562, f++: 0,1125 s++: 2 f--: 0,25 s--: 1