c++ - 计数操作 - 嵌套循环中有多少个运算符?
问题描述
我目前正在做一个关于 Big O 的个人项目,以及我们如何使用线性方程等对不同的算法进行分类。因为对于这个学校项目,我想重点强调我们在课堂上学到的东西来提高我的分数(二次方程等),找到我如何使用数学来找到大 O 可能会很好。
根据我所学到的,我首先计算代码中运算符的数量。然后,根据它的时间复杂度,我必须创建一个满足我们算法的方程;例如,如果我有一个 O(n) 的算法,我的方程将类似于 y = mx+b。
这真的很容易,但是对于具有嵌套循环的二次函数或算法,它就更难了......假设我有以下代码......
void printAllPairs()
{
//int n = 5; just using n to represent our array size, but for now we'll initlalize it to a value
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
std::cout << i << "," << j << "\n";
}
}
}
我知道这个算法是 O(n^2),我也知道将 O(n^2) 记为 O(n^2+an+b) 或将 O(n) 记为 O(mn+b) 是不好的做法,但是我如何用二次方程(例如 x^2 + ax + b 或类似的东西)来表示这个算法?我知道我有两个常量(第 3 行和第 5 行中的两个赋值运算符),但是在“int j = 0”中找到的运算符是否也被视为常量?由于这是一个嵌套循环,所以每次运行第二个循环时都必须再次运行 j = 0,对吗?
使用 O(n) 方程,这非常简单,因为我可以轻松识别哪些运算符是常数和系数,也就是哪些运算符受或不受 n 影响。
关于如何将 printAllPairs() 算法表示为二次方程的任何帮助?对不起,如果这对你们来说似乎很容易,但是一位高中生在这里需要帮助。
编辑:
解决方案
首先,我想澄清一些可能是误解的事情(尽管我可能对你的问题读了很多)。O(n^2)
不是 . 的速记或简化O(n^2 + an + b)
。相反,它们指的是完全相同的东西。O(n^2 + alog(n))
也是同样的事情,无数其他的表达方式也是如此。使算法二次的不是复杂度是二次多项式,而是复杂度最终不会比an^2
某些特定的增长更快a
。这就是 big-O 的价值:我们不必担心对复杂性的所有可能贡献,而是可以专注于一般形状。
Big-O 有太多细节
好的,关于我认为你的问题的核心,即如何明确常量。我通常不建议在实践中这样做,但从技术上讲,这是真正的交易。
让我们将问题分解为多个部分并构建完整的问题。首先,算法中最简单的部分:
std::cout << i << "," << j << "\n";
这不依赖于n
,它的时间复杂度以某个常数为界。我们称它为常量a
。所以我们这条语句的总时间复杂度是:
t0 = a
酷,漂亮,简单。
现在让我们介绍最里面的循环:
for (int j = 0; j < n; j++)
{
std::cout << i << "," << j << "\n";
}
就时间复杂度而言,这个循环涉及:
n
重复std::cout
我们刚刚分析的常量语句。n
重复一些不断的记账工作(如增量、比较、跳转)。我们称之为簿记复杂性b1
。- 一些额外的恒定工作(例如初始化
j
)。我们称之为复杂性b2
。
总而言之,我们的时间复杂度现在看起来像这样:
t1 = n * (t0 + b1) + b2
= n * (a + b1) + b2
这遵循 中的线性多项式的一般形式n
。
现在我们再次做同样的思考过程。
n
我们刚刚分析的(线性)循环的重复。n
重复一些我们称之为的持续簿记工作c1
。- 一些额外的持续工作,我们称之为
c2
.
所以这个循环的时间复杂度是:
t2 = n * (t1 + c1) + c2
= n * ((n * (a + b1) + b2) + c1) + c2
= n^2 * (a + b1) + n * (b2 + c1) + c2
所以我们看到算法是O(n^2 * (a + b1) + n * (b2 + c1) + c2)
,这当然等价于O(n^2)
。
实践中的大 O
在这里,我们就 Big-O 的实际计算提出一些建议,这将为您省去很多麻烦。我将带您回到“big-O 的值”,即常量和非显性项根本不重要,所以甚至不必费心去跟踪它们。仅此一项就可以为您省去很多麻烦。
再一次,让我们打破这个问题。您会看到分析看起来就像上一节一样,但噪音大大降低。
我们再次从单个语句开始:
std::cout << i << "," << j << "\n";
由于这不依赖于n
,我们称其为常数。即,时间复杂度为O(1)
。
现在我们介绍最里面的循环:
for (int j = 0; j < n; j++)
{
std::cout << i << "," << j << "\n";
}
我们有:
n
重复O(1)
我们刚才分析的陈述。n
重复一些O(1)
簿记工作。- 一些额外的
O(1)
工作。
所以这个循环有时间复杂度O(n * 1 + n * 1 + 1)
,相当于O(n)
.
现在最外层循环:
n
O(n)
我们刚刚分析的循环的重复。n
重复一些O(1)
簿记工作。- 一些额外的
O(1)
工作。
所以这个循环有时间复杂度O(n * n + n * 1 + 1)
,相当于O(n^2)
.
推荐阅读
- python - 通过索引列#s 在 Pandas 数据框中添加计算列
- swift - 在 Swift 4 中访问 PartialKeyPath 的可选值
- image - JPEG压缩原始图像的分辨率
- c++ - 为什么 C++ 引用会耗尽结构中的内存?
- c++ - 如何将 char 类型变量附加到字符串?
- rxjs - 带间隔的 concatMap 未按预期工作
- c++ - TS Concepts 类型名约束
- android - Google Play 订阅始终“待付款”
- javascript - 使用带有换行符的php字符串作为javascript变量
- angular - ngClass 正在删除加载时的选择选项