繁体   English   中英

O(n)比O(nlogn)需要更多时间

[英]O(n) takes more time than O(nlogn)

我在spoj上尝试这个问题。 首先,我想出了一种简单的o(blogb)算法(将问题代入b)。但是由于问题的作者提到了约束,因为b属于[0,10 ^ 7],所以我不敢相信无论如何,无论如何我都将其编码如下

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<cstdlib>
#include<stack>
#include<queue>
#include<string>
#include<cstring>


#define PR(x) cout<<#x"="<<x<<endl
#define READ2(x,y) scanf("%d %d",&x,&y)
#define REP(i,a) for(long long i=0;i<a;i++)
#define READ(x) scanf("%d",&x)
#define PRARR(x,n) for(long long i=0;i<n;i++)printf(#x"[%d]=\t%d\n",i,x[i])
using namespace std;
#include <stdio.h>
struct node {
          int val;
          int idx;
          };

bool operator<(node a,node b){ return a.val<b.val;}
node contain[10000001];
int main(){
          int mx=1,count=1,t,n;
          scanf("%d",&t);
          while(t--){
                count=1;mx=1;
                scanf("%d",&n);
                for(int i=0;i<n;i++){
                        scanf("%d",&contain[i].val);
                        contain[i].idx=i;
                        }
          sort(contain,contain+n);
          for(int j=1;j<n;j++){
                    if(contain[j].idx>contain[j-1].idx)
                            count++;
                            else count=1;
                            mx=max(count,mx);
                                }
                    printf("%d\n",n-mx);
                    }
                   }             

它在SPOJ服务器上经过了0.01秒(这是很慢的),但是我很快想出了O(b)算法,代码如下

 #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<cstdlib>
    #include<stack>
    #include<queue>
    #include<string>
    #include<cstring>


    #define PR(x) printf(#x"=%d\n",x)
    #define READ2(x,y) scanf("%d %d",&x,&y)
    #define REP(i,a) for(int i=0;i<a;i++)
    #define READ(x) scanf("%d",&x)
    #define PRARR(x,n) for(int i=0;i<n;i++)printf(#x"[%d]=\t%d\n",i,x[i])
    using namespace std;
    int val[1001];
    int arr[1001];
    int main() { 
    int t;
    int n;
    scanf("%d",&t);
    while(t--){
            scanf("%d",&n);
            int mn=2<<29,count=1,mx=1;
            for(int i=0;i<n;i++){
                    scanf("%d",&arr[i]);
                    if(arr[i]<mn) { mn=arr[i];}
                    }
            for(int i=0;i<n;i++){
                    val[arr[i]-mn]=i;
                    }
            for(int i=1;i<n;i++){
            if(val[i]>val[i-1]) count++;
            else {

            count=1;
            }
            if(mx<count) mx=count;
            }
            printf("%d\n",n-mx);
            }
    }

但令人惊讶的是,它花了0.14s :O

现在我的问题是b> 2的o(b)是否比o(blogb)好吗? 那为什么时间差那么大呢? 社区中的一位成员建议,这可能是由于缓存未命中所致。与o(blogb)相比,o(b)代码的本地化程度较低,但我不认为这会导致0.10s的差异,对于<1000运行的代码? (是b实际上小于1000,不知道为什么问题设置者如此夸张)

编辑 :我看到所有答案都趋向于以渐近符号表示的隐藏常量值,这通常会导致算法运行时出现差异。但是,如果您查看代码,您将意识到我正在做的就是用另一个遍历替换排序调用现在我假设sort至少一次访问数组的每个元素,如果我们考虑执行的行数,这是否会使两个程序更加接近?此外,我过去使用spoj的经验告诉我I / O会对程序的运行时间产生巨大影响,但是我在两个代码中都使用了相同的I / O例程。

大O符号表示当输入集接近无限大小时函数需要花费多长时间。 如果您有足够大的数据集,则O(n)将始终胜过O(n log n)。

实际上,由于大O公式中的其他隐藏变量,某些“性能较差”的算法更快。 一些更具可扩展性的算法可能会更慢。 随着输入集的变小,差异变得更加任意。

当我花费数小时来实施可伸缩解决方案时,以及在进行测试时,我都以艰辛的方式学习了所有这些方法,发现这对于大型数据集来说只会更快。

编辑:

关于具体情况,有人提到同一行代码在性能方面可能有很大差异。 这可能是这种情况。 这意味着大O公式中的“隐藏变量”非常相关。 您越了解计算机内部的工作原理,就会掌握更多的优化技术。

如果您只记得一件事,请记住这一点。 请勿仅通过阅读代码来比较两种算法的性能。 如果那么重要,请在实际数据集上安排一个实际的实现。

I / O操作( scanf()printf() )对结果有偏见。

众所周知,这些操作速度很慢,并且在计时时显示出很大的差异。 除非使用这些I / O操作,否则您绝不能使用它们来评估代码的性能。

因此,请删除这些电话,然后重试。

我还将指出0.1s非常小。 0.1s的差异可能是指加载可执行文件和准备执行代码所花费的时间。

Big-O表示法不是可将n任意值插入的公式。 它仅将函数的增长描述为n到无穷大。

这是一个比人们可能怀疑的问题更有趣的问题。 O()概念可能有用,但并不总是像某些人认为的那样有用。 对数订单尤其如此。 代数上,对数确实具有零阶,也就是说,log(n)/ n ^ε收敛于任何正ε。

订单计算中的对数因子实际上并不重要,这比我们想像的要多。

但是,肯德尔·弗雷(Kendall Frey)是对的。 对于足够大的数据集,O(n * log(n))最终将丢失。 只是数据集可能必须非常大才能显示对数差异。

我在SPOj中查看了您的解决方案。 我注意到您的O(nlogn)解决方案占用79M内存,而O(n)仅占用很小的内存,显示为0K。 我也查看了其他解决方案。 我看过的大多数最快的解决方案都使用了大量的内存。 现在,我能想到的最明显的原因是std::sort()函数的实现。 它的实现非常好,可以使您的解决方案速度惊人。 对于O(n)解决方案,我认为由于if() {...} else {...}可能会很慢。 尝试将其更改为三元运算符,并让我们知道它是否有所不同。

希望能帮助到你 !!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM