算法的成本

时间:2016-11-13 11:58:21

标签: c++ algorithm performance

问题出在下一个:

我们想知道向量的大小,我们不能使用size()但是我们有一个函数 inBounds(vector& arr,int index)如果索引是a,则返回true向量的有效位置。

所以,我的方法是迭代位置。从1开始并复制(2,4,8,16,32 ...)直到inBounds返回false,然后退回,并在子范围内重复搜索。

我们举个例子,把N = 21:

  • 1 = True
  • 2 = True
  • 4 = True
  • 8 = True
  • 16 = True
  • 32 = False

退回到16,并在16-32范围内搜索:

  • (16 + 1)= True
  • (16 + 2)= True
  • (16 + 4)= True
  • (16 + 8)= False

回到20(16 + 4)并重新开始:

  • (20 + 1)= True
  • (20 + 2)= False

从21岁开始:

  • (21 + 1)= False

好的,所以大小是21。

这是我在代码中的实现:

#include <iostream>
#include <vector>
using namespace std;

int inBounds(const vector<int>& arr,int i)
{
    return i < arr.size();
}

int size(const vector<int>& arr)
{
    int init = 0;

    while (inBounds(arr,init))
    {
        int start = 2;
        while (inBounds(arr,init+start))
        {
            start *= 2;
        }
        start /= 2;
        init += start;
    }
    return init;
}


int main()
{
    vector<int> arr;

    for (int i = 0;i < 1000;i++)
    {
        arr.resize(i);
        int n = size(arr);
        if (n != arr.size())
            cout << "FAIL " << arr.size() << ' ' << n << endl;
    }
    return 0;
}

这很好用。但我不知道这个算法的确切成本。第一次搜索确实是log(N),但现在我需要添加子范围搜索。所以我对实际成本有疑问

4 个答案:

答案 0 :(得分:3)

实际上,你最糟糕的情况是 O(log(n) 2 (这是预期的,因为你有一个O(log)周期嵌套在里面另一个日志周期)

要理解原因,请尝试缩小31(一般情况下2 N -1)

我们举个例子,把N = 31:

1 = True
2 = True
4 = True
8 = True
16 = True
32 = False

O(log(N))到这里,好吧,没有人对它进行竞争

-

现在计算额外的步骤

退回到16,并在16-32范围内搜索:

(16+1) = True
(16+2) = True
(16+4) = True
(16+8) = True
(16+16) = False 

(4 + 1)步 - 这是log(32/2)+1 = log(32)

回到24

(24+1) = True
(24+2) = True
(24+4) = True
(24+8) = False

(3 + 1)步 - 这是log(16/2)+ 1 = log(16)

回到28:

(28+1) = True
(28+2) = True
(28+4) = False

(2 + 1)步 - 这是log(8/2)+ 1 = log(8)

回到30

(30+1) = True
(30+2) = False

(1 + 1)步骤,即log(4/2)+ 1 = log(4)

结果:(4 + 3 + 2 + 1 =正数为10步+负数为4)。或者,以另一种形式log(32)+log(16)+log(8)+log(4)+log(2) - 1 =log(32)(1+1/2+1/3+1/4+1/5)-1。忽略最后的-1,你的公式就像

log(N)*(1+1/2+1/3+1/4+...+1/N)

嗯,对于大型N-es,harmonic series是不同的,渐近行为是logarithmic

所以你给自己一个很好的O(log(N)*log(N))复杂性。

QED(??)

答案 1 :(得分:1)

似乎你的第一个子范围搜索也是logN(因为它使用与初始部分基本相同的算法),而你的最终子范围搜索是线性的(迭代每个值),但它是非常有界的并且是N的一小部分。我会说你的算法大致是c * logN,其中c是一个小值,代表你正在做的子搜索的数量,所以通常是O(logN)。

答案 2 :(得分:1)

一旦找到了上限,你真的应该进行二分搜索。应用于您的示例:

  • 初始循环的结果:16→真,32→假,因此大小为(16,32)

二进制搜索总是测试找到的最大的真实和最小的虚假之间的中间位置:

  • 24→false =&gt; (16,24]
  • 20 - true =&gt; (20,24]
  • 22→false =&gt; (20,22)
  • 21→false =&gt; (20,21]

所以大小是21。

请注意,这只需要4个额外的测试,而不是算法的7个。

答案 3 :(得分:1)

假设向量的大小是N = 31.因为这将是你的算法的最坏情况,这里它是如何工作的:

first pass : 1,2,4,8,16,32            [ total = 6 ]
second pass: 17,18,20,24,32           [ total = 5 ]
third pass : 25,26,28,32              [ total = 4 ]
forth pass : 29,30,32                 [ total = 3 ]
fifth pass : 31                       [ total = 1 ]

如果我们谈谈N.那就是:

T(N) = logN*(1+1/2+1/4+1/8+....)

的顺序为:(logN)^2

您应该考虑@celtschk给出的方法O(logN)