加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 同时复杂但运行时间变化很大

发布时间:2020-12-16 10:14:32 所属栏目:百科 来源:网络整理
导读:对于这个问题:给定偶数(大于2),返回两个素数,其总和将等于给定数. 以下算法分别具有时间复杂度O(A2.5)和O(Alog(log(A)).仍然对于A(整数)的值大到73939138,第二个算法真的很慢.我试过很多输入,第一个更快.你能解释一下原因吗? int ul=A/2;vector int answer
对于这个问题:给定偶数(大于2),返回两个素数,其总和将等于给定数.

以下算法分别具有时间复杂度O(A2.5)和O(Alog(log(A)).仍然对于A(整数)的值大到73939138,第二个算法真的很慢.我试过很多输入,第一个更快.你能解释一下原因吗?

int ul=A/2;
vector <int> answer;
for (int i=1; i<=ul; i++)
{
    if (check(i)==1 && check(A-i)==1 ) //check(i) checks primality of i in O(i^1.5)
   {
       int myint[2] ={ i,A-i };
       answer.assign( myint,myint+2);
       return answer;
   }
}
vector<bool> primes(A+1,true);
int i,j;
//Sieve of Eratosthenes O(Alog(log(A)))
for(i=2;i*i<A+1;i++)
{
    if(primes[i])
    {
        for(j=2;i*j<A+1;j++)
            primes[i*j]=0;
    }
}
vector<int> arr,answer;
//arr is vector containing all primes from 2 to A; O(A)
for(i=2;i<A+1;i++)
{
    if(primes[i])
        arr.push_back(i);
}
i=0;j=arr.size()-1;
//Algorithm to find 2 numbers summing up to a value
while(i<=j)
{
    if(arr[i]+arr[j]>A)
        j--;
    else if(arr[i]+arr[j]<A)
        i++;
    else
    {
        answer.push_back(arr[i]);
        answer.push_back(arr[j]);
        return answer;
    }
}

编辑:check(n)定义如下:

int check(int n)
{
    int ul=sqrt(n);
    if(n<2)
        return 0;
    for(int i=2; i<=ul; i++)
    {
        if(n%i==0)
            return 0;
    }
    return 1;    
}

解决方法

您考虑的复杂性并不能直接提供有关算法性能的信息,而是提供有关渐近行为的信息,通常用于最坏情况.

最坏情况与平均情况

只需看看A = 73939138的答案:

73939138 = 5 + 73939133

所以基本上,你的第一个算法会做10次调用来检查,而第二个算法会通过巨大的循环来填充数组素数.

第一算法的平均情况复杂度可能远低于O(A ^ 2.5),而第二算法的平均情况复杂度接近或等于O(A log(log(A)).

注意:关于平均情况复杂性的后续内容仅仅是猜测,不要将它们用于合理的结果.

第二种算法:

在这个算法中,无论A是什么,你都必须使用Eratosthenes的筛来填充数组素数,即O(A log(log(A))).由于这是算法中最耗时的部分,因此该算法的平均情况复杂度可能接近其最坏情况复杂度,因此O(A log(log(A))).

第一种算法:

这里更复杂……基本上,它取决于算法的结果.根据Wikipedia’s page on Goldbach’s conjecture,将A作为两个素数之和的平均写入方式是A /(2 * log(A)^ 2).

由于素数不能有两种不同的方式,这意味着平均有2 * A /(2 * log(A)^ 2)= A /(log(A)^ 2)素数有助于其中一种方式.

如果我们假设* 1这些素数均匀分布,则较小的素数应该接近A /(A / log(A)^ 2)= log(A)^ 2.

所以你只需要检查大约log(A)^ 2的数字.

1我完全不知道这是不是真的,我只是在猜测……

渐近行为

检查@PeterBecker’s answer and comments.

当你说O(A log(log(A)))复杂度时,你隐藏了很多东西 – 任何函数f(A)= C *(A log(log(A)))g(A)其中g( A)是O(A log(log(A)))也是O(A log(log(A))).

例如:

f(A) = c1 * A * log(log(A)) + c2 * A + c3 * log(A)

…是O(A log(log(A))).

系数c1,c2,c3决定了算法实现的实际行为,不幸的是,这些通常很难找到(或复杂).

例如,快速查看您的实现显示以下内容:

>第一种算法不使用任何类型的容器,因此几乎没有内存需求(只有一些局部变量).
>第二种算法使用两个相对较大的数组,素数和arr – 如果A = 73939138:

> primes包含73939139“entity” – 这很可能是通过std :: vector< bool>的特化来优化的,但你仍然需要~9MB,它不适合L1缓存,也许是L2,你需要一点点每次访问的每个操作.
> arr应该包含~4000000 int(参见here),因为你使用push_back需要多次分配.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读