建议分析算法
Proposed analysis of algorithm
我最近一直在练习分析算法。我觉得我对分析非递归算法有很好的理解,但我不确定,并且刚刚开始全面理解递归算法。虽然,我还没有正式检查我的方法,我所做的是否确实是正确的
问是否有人可以检查我已经实现和分析的一些算法,看看我的理解是否正确,或者我是否完全偏离了。
此处:
1)
sum = 0;
for (i = 0; i < n; i++){
for (j = 0; j < i*i; j++){
if (j % i == 0) {
for (k = 0; k < j; k++){
sum++;
}
}
}
}
我对这个的分析是 O(n^5),原因是:
Sum(i = 0 to n)[Sum(j = 0 to i^2)[Sum(k = 0 to j) of 1]]
评估为:
(1/2)(n^5/5 + n^4/2 + n^3/3 - n/30) + (1/2)(n^3/3 + n^2/2 + n/6) + (1/2)(n^3/3 + n^2/2 + n/6) + n + 1。
因此它是 O(n^5)
作为循环总和的评估是否正确?
三重求和。我假设 if 语句将始终通过最坏情况的复杂性。这是对最坏情况的正确假设吗?
2)
int tonyblair (int n, int a) {
if (a < 12) {
for (int i = 0; i < n; i++){
System.out.println("*");
}
tonyblair(n-1, a);
} else {
for (int k = 0; k < 3000; k++){
for (int j = 0; j < nk; j++){
System.out.println("#");
}
}
}
}
我对该算法的分析是 O(infinity),因为如果假设为真,if 语句中的无限递归,这将是最坏的情况。虽然,为了纯粹的分析,我分析了如果这不是真的并且 if 语句不会 运行。由于以下原因,我得到了 O(nk) 的复杂性:
Sum(k = 0 to 3000)[Sum(j = 0 to nk) of 1]
然后评估为 nk(3001) + 3001。因此是 O(nk),其中 k 未被丢弃,因为它控制循环的迭代次数。
1号
我不知道你是怎么推导出你的公式的。通常添加项发生在算法中有多个步骤时,例如预先计算数据然后从数据中查找值。相反,嵌套的 for 循环意味着乘法。此外,对于这段代码来说,最坏的情况也是最好的情况,因为给定 n 的值,最后的总和将是相同的。
为了找到复杂度,我们想要找到内循环被评估的次数。如果从 1 到 n,求和通常很容易解决,所以我稍后会去掉它们中的 0。如果 i 为 0,则中间循环不会 运行,如果 j 为 0,则内部循环不会 运行。我们可以将代码等价地重写为:
sum = 0;
for (i = 1; i < n; i++)
{
for (j = 1; j < i*i; j++)
{
if (j % i == 0)
{
for (k = 0; k < j; k++)
{
sum++;
}
}
}
}
我可以通过强制外循环从 2 开始来让我的生活更艰难,但我不会这样做。外循环现在从 1 到 n-1 运行s。中间根据i的当前值循环运行s,所以需要做求和:
中间的for循环总是走到(i^2 - 1),j只能被i整除总共(i - 1)次(i, i*2, i*3, . .., i*(i-2), i*(i-1)).有了这个,我们得到:
然后中间循环执行j次。不过,我们求和中的 j 与代码中的 j 不同。求和中的 j 表示每次执行中间循环。每次执行中间循环时,代码中的j都会是(i * (number of executions so far)) = i * (the j in the summation)
。因此,我们有:
我们可以将 i 移动到两个求和之间,因为它是内部求和的常数。那么,1到n求和的公式就是众所周知的:n*(n+1)/2
。因为我们要 n - 1,所以我们必须减去 n。这给出:
平方和和立方和的求和也是众所周知的。请记住,在这两种情况下我们只求和到 n-1,我们必须记住分别减去 n^3 和 n^2,我们得到:
这显然是n^4。如果我们一直解决它,我们得到:
2号
对于最后一个,由于 if 语句,如果 a < 12 实际上是 O(infinity)。好吧,从技术上讲,一切都是 O(infinity),因为 Big-O 只提供 运行 时间的上限。如果 a < 12,它也是 omega(infinity) 和 theta(infinity)。如果只有else运行s,那么我们就有了i*n的1到2999的求和:
请务必注意,从 1 到 2999 的总和是一个常数(即 4498500)。无论一个常数有多大,它仍然是一个常数,与 n 无关。我们最终会将其排除在 运行 时间计算之外。有时,当一个理论上快的算法有一个大常数时,它实际上比其他理论上慢的算法慢。我能想到的一个例子是Chazelle's linear time triangulation algorithm。从来没有人实施过它。无论如何,我们有 4498500 * n。这是 theta(n):
我最近一直在练习分析算法。我觉得我对分析非递归算法有很好的理解,但我不确定,并且刚刚开始全面理解递归算法。虽然,我还没有正式检查我的方法,我所做的是否确实是正确的
问是否有人可以检查我已经实现和分析的一些算法,看看我的理解是否正确,或者我是否完全偏离了。
此处:
1)
sum = 0;
for (i = 0; i < n; i++){
for (j = 0; j < i*i; j++){
if (j % i == 0) {
for (k = 0; k < j; k++){
sum++;
}
}
}
}
我对这个的分析是 O(n^5),原因是: Sum(i = 0 to n)[Sum(j = 0 to i^2)[Sum(k = 0 to j) of 1]] 评估为: (1/2)(n^5/5 + n^4/2 + n^3/3 - n/30) + (1/2)(n^3/3 + n^2/2 + n/6) + (1/2)(n^3/3 + n^2/2 + n/6) + n + 1。 因此它是 O(n^5)
作为循环总和的评估是否正确?
三重求和。我假设 if 语句将始终通过最坏情况的复杂性。这是对最坏情况的正确假设吗?
2)
int tonyblair (int n, int a) {
if (a < 12) {
for (int i = 0; i < n; i++){
System.out.println("*");
}
tonyblair(n-1, a);
} else {
for (int k = 0; k < 3000; k++){
for (int j = 0; j < nk; j++){
System.out.println("#");
}
}
}
}
我对该算法的分析是 O(infinity),因为如果假设为真,if 语句中的无限递归,这将是最坏的情况。虽然,为了纯粹的分析,我分析了如果这不是真的并且 if 语句不会 运行。由于以下原因,我得到了 O(nk) 的复杂性:
Sum(k = 0 to 3000)[Sum(j = 0 to nk) of 1] 然后评估为 nk(3001) + 3001。因此是 O(nk),其中 k 未被丢弃,因为它控制循环的迭代次数。
1号
我不知道你是怎么推导出你的公式的。通常添加项发生在算法中有多个步骤时,例如预先计算数据然后从数据中查找值。相反,嵌套的 for 循环意味着乘法。此外,对于这段代码来说,最坏的情况也是最好的情况,因为给定 n 的值,最后的总和将是相同的。
为了找到复杂度,我们想要找到内循环被评估的次数。如果从 1 到 n,求和通常很容易解决,所以我稍后会去掉它们中的 0。如果 i 为 0,则中间循环不会 运行,如果 j 为 0,则内部循环不会 运行。我们可以将代码等价地重写为:
sum = 0;
for (i = 1; i < n; i++)
{
for (j = 1; j < i*i; j++)
{
if (j % i == 0)
{
for (k = 0; k < j; k++)
{
sum++;
}
}
}
}
我可以通过强制外循环从 2 开始来让我的生活更艰难,但我不会这样做。外循环现在从 1 到 n-1 运行s。中间根据i的当前值循环运行s,所以需要做求和:
中间的for循环总是走到(i^2 - 1),j只能被i整除总共(i - 1)次(i, i*2, i*3, . .., i*(i-2), i*(i-1)).有了这个,我们得到:
然后中间循环执行j次。不过,我们求和中的 j 与代码中的 j 不同。求和中的 j 表示每次执行中间循环。每次执行中间循环时,代码中的j都会是(i * (number of executions so far)) = i * (the j in the summation)
。因此,我们有:
我们可以将 i 移动到两个求和之间,因为它是内部求和的常数。那么,1到n求和的公式就是众所周知的:n*(n+1)/2
。因为我们要 n - 1,所以我们必须减去 n。这给出:
平方和和立方和的求和也是众所周知的。请记住,在这两种情况下我们只求和到 n-1,我们必须记住分别减去 n^3 和 n^2,我们得到:
这显然是n^4。如果我们一直解决它,我们得到:
2号
对于最后一个,由于 if 语句,如果 a < 12 实际上是 O(infinity)。好吧,从技术上讲,一切都是 O(infinity),因为 Big-O 只提供 运行 时间的上限。如果 a < 12,它也是 omega(infinity) 和 theta(infinity)。如果只有else运行s,那么我们就有了i*n的1到2999的求和:
请务必注意,从 1 到 2999 的总和是一个常数(即 4498500)。无论一个常数有多大,它仍然是一个常数,与 n 无关。我们最终会将其排除在 运行 时间计算之外。有时,当一个理论上快的算法有一个大常数时,它实际上比其他理论上慢的算法慢。我能想到的一个例子是Chazelle's linear time triangulation algorithm。从来没有人实施过它。无论如何,我们有 4498500 * n。这是 theta(n):