Algorithm 二进制搜索不具有遍历开销。是什么?

Algorithm 二进制搜索不具有遍历开销。是什么?,algorithm,big-o,traversal,binary-search,Algorithm,Big O,Traversal,Binary Search,当我试图将二进制搜索应用于现实世界时,它让我失望了。情况如下 我需要测试通过无线电通信的设备的范围。 通信需要快速进行,但传输速度较慢 可以忍受,在一定程度上(比如说,大约3分钟)。我需要测试一下 传输是否每200英尺成功一次,直到失败,最多1600英尺 脚。每200英尺进行一次测试,需要3分钟才能完成 执行 我天真地假设二进制搜索将是找到故障点的最有效的方法,但是考虑到200英尺/分钟的行驶速度和3分钟的测试时间。如果在500英尺处发生传输故障,二进制搜索不是查找故障点的最有效方法,如下所示

当我试图将二进制搜索应用于现实世界时,它让我失望了。情况如下

我需要测试通过无线电通信的设备的范围。 通信需要快速进行,但传输速度较慢 可以忍受,在一定程度上(比如说,大约3分钟)。我需要测试一下 传输是否每200英尺成功一次,直到失败,最多1600英尺 脚。每200英尺进行一次测试,需要3分钟才能完成 执行

<>我天真地假设二进制搜索将是找到故障点的最有效的方法,但是考虑到200英尺/分钟的行驶速度和3分钟的测试时间。如果在500英尺处发生传输故障,二进制搜索不是查找故障点的最有效方法,如下所示

简单地走过去测试每一个点就可以更快地找到解决方案,只需12分钟,而二进制搜索和测试则需要16分钟


我的问题:当旅行时间很重要时,如何计算最有效的解决方案路径?这被称为什么(例如二进制旅行搜索等)?

二进制搜索确实是基于
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