算法的复杂度分析

complexity analysis of algorithm

本文关键字:复杂度 算法      更新时间:2023-10-16

这里是代码,它填充二维数组与随机生成的数字范围[1 19]没有重复,我的问题是:如何确定它的复杂性?

例如,我看到它的运行时间至少是O(n^2),因为它的内部和外部循环,但是关于goto语句?

下面是我的代码:
#include <iostream>
#include <set>
#include <cstdlib>
using namespace std;
int main()
{
    int min=1;
    int max=19;
    int  a[3][3];
    set<int>b;
    for (int i=0; i<3; i++)
    {
        for (int j=0; j<3; j++)
        {
loop:
            int m=min+rand()%(max-min);
            if (b.find(m)==b.end())
            {
                a[i][j]=m;
                b.insert(m);
            }
            else
                goto loop;
        }
    }
    for (int i=0; i<3; i++)
    {
        for (int j=0; j<3; j++)
            cout<< a[i][j]<<"  ";
        cout<<endl;
    }
    return 0;
}

我会说算法的复杂度是c*O(n^2)其中c是某个常数,这是因为如果它在循环中发现重复的元素它会重复生成随机数并花费一些常数时间,对吗?

随着获得工作数的可能性降低,go -loop的数量增加。对于均匀随机数生成器,其行为与..的数量呈线性关系。数字。它绝对不会给你的复杂度增加一个常数。

如果n是a中元素的个数,那么它的平均比例为0 (n²)。(或者如果n是方阵a的行数;O (n⁴)).

一个更简单的实现是使用Fisher-Yates shuffle

它是0(∞)。0符号给出了一个上界。由于您在循环中使用了rand(),因此无法保证您将取得进展。因此,不存在上界。

[编辑]好吧,除了传统的最坏情况的复杂性,人们还想要其他的复杂性。

假设RNG生成无穷个1的序列而得到的最坏情况复杂度;这意味着即使第一次循环迭代也没有完成。因此,在运行时间上没有有限的上界,O(∞)。

最佳情况下的复杂度是通过假设RNG生成序列号来获得的。即每次迭代的代价为O(log N) (set::find),有O(N)*O(N)次迭代,因此上界为O(N2 log N)。

平均情况复杂度更难。假设max = k*N*N对于某些k> 1, RNG将在O(1)时间内成功地选择一个"未使用"的号码。即使选择了N*N个号码,仍然有(k-1)个未使用的号码,因此选择一个未使用的号码的机会pp >= (k-1)*(N*N)/k*(N*N) <=> p>= (k-1)/k。这意味着我们可以期望在k/(k-1)尝试中选择一个未使用的数字,这与N无关,因此是O(1)。set::find仍然主导每次迭代的成本,为O(log N)。我们仍然有相同的迭代次数,所以我们得到相同的上限O(N2 log N)

goto循环,直到一个随机数等于给定的数字。如果随机数的分布是均匀的,"retry…"直到"平均线性"相对于范围的振幅。但是这种线性会导致set::find (log(n)) (ste::insert只发生一次)的复杂度乘以

两个外部for是基于常量的(所以它们的计时不依赖于数据),因此它们只是乘以时间,但不会增加复杂性。

"复杂度"不是指你的程序占用了多少绝对时间(或空间)。它是关于当你增加程序输入数据的大小时,所增加的时间(或空间)

(顺便说一下,O表示时间,O表示空间可能不同)

时间复杂度。

假设n是矩阵中元素的数量,你必须问自己当你向矩阵中添加单个元素时会发生什么(即当n变成n+1时):

  • 您需要遍历新元素,它是0(1)。这里我们讨论的是一次迭代,所以双循环并不重要。
  • 您有另一个打印迭代,它也是0(1),假设cout<<是0(1)。
  • 你必须find的元素是0 (log(n)) - std::set通常实现为红黑树。
  • 您必须重试find(通过goto)可能几次。根据rnd, min, maxint的宽度,重试次数可能是0(1)(即它不随元素数量的增加而增加),也可能比这更糟。
  • 你必须insert的元素是0 (log(n))。

假设"最佳"rnd,您将看到以下元素增加

(O (1) + O (1)) * (O (log (n)) * O (1) + O (log (n)) = O (1) * O (log (n)) = O (log (n))

…所以对于n个元素,复杂度是:

(O (n) + O (n)) * (O (log (n)) * O (1) + O (log (n)) = O (n) * O (log (n)) = O (n * log (n))

假设"坏"rnd (0 (n)),您将看到…

(O (n) + O (n)) * (O (log (n)) * O (n) + O (log (n)) = O (n) * O (n * log (n)) = O (n ^ 2 * log (n))

空间复杂性

你的矩阵是O(n), std::set是O(n),所以你在这里总体上是O(n)。