遍历成本对二进制搜索效率不高。什么是?

时间:2012-12-03 02:22:12

标签: algorithm big-o traversal binary-search

当我尝试将它应用到现实世界时,二进制搜索让我感到失望。方案如下。

  

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

我天真地认为二元搜索是找到故障点的最有效方法,但考虑行程速度为200英尺/分钟,测试时间为3分钟。如果在500英尺处发生传输失败,二进制搜索不是找到故障点的最有效方法,如下所示。

enter image description here

只需走路并测试每一个点就可以更快地找到解决方案,只需12分钟,而二分搜索&测试需要16分钟。

我的问题:在旅行时间问题上,您如何计算解决方案的最有效途径?这叫什么(例如,二元旅行搜索等)?

3 个答案:

答案 0 :(得分:3)

二进制搜索确实取决于O(1)访问时间;例如,在链接列表中进行二进制搜索很少[但请参阅注释1],这基本上就是您正在做的事情,因为您似乎假设只有离散间隔值得测试。如果您正在寻求更准确的答案,您会发现二进制搜索允许任意精度,每次精度需要额外测试一次。

假设您甚至不知道最大值是什么。然后你不能先在中间测试,因为你不知道中间位置。相反,你可能会进行指数搜索限制(这是一种内部的二进制搜索);您首先在x,然后2x,然后4x进行测试,直至达到大于最大值的点(信号未达到那么远)。 (x是您感兴趣的最小答案;换句话说,如果x处的第一次测试显示信号未达到,则您将停止。)在此阶段结束时,您对于某个整数2ix,我会在i,您将知道答案在2i-1x2ix之间。

现在你可以实际进行二分查找,首先是2i-2x。从那里开始,你可以向前或向后,但你一定会旅行2i-3x,下一次你将旅行2i-4x,等等。

总而言之,在第一阶段(搜索最大值),您走到2ix,并进行了i次测试。在第二阶段,二进制细化,您总共进行(2i-1-1)xi-1次测试。你最终会在d2i-1之间的2i结束,所以最坏的情况下你会走3d的最后一点(最好的,你会走路3d/2)。您将完成的测试次数为2*ceil(log2(d/x)) - 1,这是2*log2(d/x)的一次测试。

在什么情况下你应该做二进制搜索算法呢?基本上,它取决于行程时间和测试时间的比率,以及所需的答案精度。简单的顺序算法在d移动大小d/xx测试后找到位置d/x;上面的二进制搜索算法在最多d旅行后找到位置3d,但只进行2 log(d/x)次测试。粗略地说,如果测试花费的成本是旅行d/x的两倍以上,并且预期距离远远大于精度,那么您应该更喜欢二分搜索。

在您的示例中,您似乎希望结果的精度为200英尺;旅行时间为1分钟,测试时间为3分钟,是旅行时间的两倍以上。所以你应该更喜欢二分搜索,除非你期望在少量的精度倍数中找到答案(就像这样)。请注意,虽然二进制算法使用四个测试和1000英尺的行程(与三个测试相比,顺序算法600英尺),将精度提高到50英尺只会增加四个测试和150英尺的二进制算法,顺序算法需要20次测试。


注1:实际上,如果测试成本很高,那么使用上述算法二进制搜索链表可能是有意义的。假设测试的成本与列表中的索引不成比例,对于线性搜索和二进制搜索,搜索的复杂度将为O(N),但二进制搜索将进行O(log N)测试和O(N)步骤,而顺序搜索将执行O(N)测试和O(N)步骤。对于足够大的N,这没关系,但对于真实世界大小的N,它可能很重要。

答案 1 :(得分:0)

实际上,二分搜索可以在这里应用,但有几处变化。我们必须计算不是居中,而是要访问的最佳位置。

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;

所以,我们的任务 - 找出这样的最佳因子增加,factorDecrease,stepIncrease,stepDecrease,f(failPos)之和的值将是最小的。怎么样?如果n(总长度/ 200.0f)很小,全部强力会帮助你。否则你可以尝试使用遗传算法或简单的smth。

步骤精度= 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));

    }
}

所以,有些值(f ++ - factorIncrease,s ++ - stepIncrease,f-- - factorDecrease):

 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

答案 2 :(得分:0)

根据您实际想要优化的内容,可能有一种方法可以找出最佳搜索模式。我认为你不想优化最坏的情况时间,因为许多搜索策略的最慢情况是在休息时间结束时,二进制搜索实际上非常好 - 你走到最后而不改变方向,你不会停顿很多。

您可能会考虑使用不同的二叉树,也许可以计算出平行所需的平均时间。二进制搜索是一种树,因此随着时间走路并进行测试 - 一个非常不平衡的树,其中每个节点至少有一个叶子连接到它。

当沿着这样一棵树追随时,你总是从你走过的一条线的另一端开始,在进行测量之前走一段距离,然后根据结果和树,停止或重复这个过程用一条较短的线,你在哪一端。

这为您提供了可以使用动态编程进行攻击的内容。假设您已经解决了长达N段的问题,因此您知道这些长度的最佳解决方案的成本。现在,您可以为N + 1段制定最佳解决方案。考虑以N + 1种可能的方式将N + 1段分成两部分。对于每种这样的方式,计算转移到其决策点并进行测量的成本,然后在决策点两侧的两个部分段中增加最佳解决方案的成本,可能加权以考虑结束这些部分的概率。通过考虑这些N + 1种可能的方法,您可以找出分割N + 1段的最佳方法及其成本,并继续,直到您为实际拥有的部分数量找出最佳解决方案。