一个排序算法的时间复杂度

4
下面的两个程序从文件中获取n个整数,并计算第a到第b个整数的和q(问题数量)次。我认为上面的程序时间复杂度比下面的差,但我在计算这两个算法的时间复杂度时遇到了问题。
[input sample]
5 3
5 4 3 2 1
2 3
3 4
2 4

[output sample]
7
5
9

程序 1:

#include <stdio.h>

FILE *in=fopen("input.txt","r");
FILE *out=fopen("output.txt","w");

int n,q,a,b,sum;
int data[1000];

int main()
    int i,j;
    fscanf(in,"%d%d",&n,&q);
    for(i=1;i<=n;i++) fscanf(in,"%d",&data[i]);
    for i=0;i<q;i++)
    {
        fscanf(in,"%d%d",&a,&b);
        sum=0;
        for(j=a;j<=b;j++) sum+=data[j];
        fprintf(out,"%d\n",sum);
    }
    return 0;
}

程序2:

#include <stdio.h>

FILE *in=fopen("input.txt","r");
FILE *out=fopen("output.txt","w");

int n,q,a,b;
int data[1000];
int sum[1000];

int main()
{
    int i,j;
    fscanf(in,"%d%d",&n,&q);
    for(i=1;i<=n;i++) fscanf(in,"%d",&data[i]);
    for(i=1;i<=n;i++) sum[i]=sum[i-1]+data[i];
    for(i=0;i<q;i++)
    {
        fscanf(in,"%d%d",&a,&b);
        fprintf(out,"%d\n",sum[b]-sum[a-1]);
    }
    return 0;
}

下面的程序获取1到m之间的n个整数并对它们进行排序。但是,我无法计算时间复杂度。
[input sample]
5 5
2 1 3 4 5

[output sample]
1 2 3 4 5

程序:

#include <stdio.h>
FILE *in=fopen("input.txt","r")
FILE *out=fopen("output.txt","w")

int n,m;
int data[1000];
int count[1000];

int main()
{
    int i,j;
    fscanf(in,"%d%d",&n,&m);
    for(i=0;i<n;i++)
    {
        fscanf(in,"%d",&data[i]);
        count[data[i]]++
    }
    for(i=1;i<=m;i++)
    {
        for(j=0;j<count[i];j++) fprintf(out,"%d ",i);
    }
    return 0;
}

有讽刺意味(或者说并不讽刺)的是,我无法计算自己算法的时间复杂度,但我很热衷于学习,所以请编程大神们帮帮我!


2
“having trouble” 是没有意义的。你困惑在哪里?你停在哪里了?你尝试过什么?代码并不是很有趣。有趣的是你如何尝试计算复杂度以及复杂度计算的哪个部分让你停下来了。 - S.Lott
S.Lott,如果我的问题写得不礼貌,我很抱歉。在程序1中,我无法定义时间复杂度,因为j循环嵌套在i循环内部,但是j的值可能与输入不同,并且它可能不会运行完整个循环。在程序2中,我无法定义时间复杂度,因为有三个循环,它们没有嵌套。我最好的猜测是O(n+q)。在最后一个程序中,我无法定义时间复杂度,因为有两个循环,取决于n和m的值而不同,我不知道n和m哪个更大。如果我再次没有表述清楚,请告诉我! - Passionate Learner
@热爱学习的同学们:请不要在自己的问题下发表评论。您拥有这个问题。请更新问题,使其完整明显。请修复问题并删除您的评论。 - S.Lott
1个回答

3
你需要做的是关注循环,具体来说是循环重复的次数以及循环内所花费的时间。 你需要将外部循环重复的次数乘以内部循环所需的时间...如果有内部循环,则需要将外部循环的重复次数乘以内部循环的重复次数,例如,以获得时间复杂度。
在你的第一个程序中,你有一个花费O(n)时间的循环,后面跟着一个花费O(q*(b-a))时间的循环...我不太清楚b和a代表什么...但如果你可以限制b-a(比如说,你知道b-a
在第二个程序中,您有两个循环,每个循环需要O(n)时间,然后是一个需要O(q)时间的循环。因此,总运行时间为O(n + q)。请注意,如果一个术语支配另一个术语,则可以放弃较小的术语。即使不知道(b-a)的值,现在已经明显比第一个更好了。
在第三个程序中,总运行时间为O(n+m),因为您有一个需要O(n)时间的循环,然后是一个需要O(m)时间的循环。如果您知道m < n或反之亦然,则可以通过删除支配项来简化表达式。如果它们可以变化,以便您不知道哪一个支配另一个,则将其写成O(m + n)是关于陈述时间复杂性最好的方法。
我应该指出,即使循环执行了多次,但是它执行的次数是固定的(例如,在程序2中,您有两个需要O(n)时间的循环),这不会影响时间复杂度,因为O(2n)与O(n)相同;换句话说,在大O复杂度分析中,常数因素并不重要。此外,如果您有一个内部循环在执行次数方面有所变化,如果您正在执行“最坏情况”复杂度分析,则只需要知道它可能具有的最坏值。
例如,考虑以下循环:
for (int i = 0; i < n; i++ ){ for (int j = i+1; j < n; j++ ){ // something taking O(1) time } }
上面的循环需要O(n^2)时间,即使不是所有的内部循环都需要O(n)时间。

我还想补充一点,你应该更好地格式化你的程序。即使当if/for/while语句在主体中只有一个语句时,花括号并不是严格要求的,但使用花括号和换行符会使代码更易读。例如,如果你这样写:

for (int i=1; i<=n; i++) {
    sum[i]=sum[i-1]+data[i];
}
相比于写成 for (i=1; i<=n; i++) sum[i]=sum[i-1]+data[i];,这样写更好。此外,我应该指出,即使您将此问题标记为C++,您仍在使用类似C的代码...在C++中,您可以在for循环的初始化中声明变量(我建议您这样做)。此外,在C++中,iostreams库std::cinstd::coutstd::fstreamstd::ostringstreamstd::istringstream等)优于C FILE*对象。
您可能还会对以下资源感兴趣:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接