vba - 在VBA中这两种使用循环的方式的时间复杂度有什么区别?

标签 vba excel time-complexity big-o

我有一个理论问题,如果您在这里给我建议,我将不胜感激。

假设我们有这两段代码。 第一个:

For Each cell In rng1
    collectionOfValues.Add (cell.Value)
Next

For Each cell In rng2
   collectionOfAddresses.Add (cell.Address)
Next

For i = 1 To collectionOfAddresses.Count
   Range(collectionOfAddresses.Item(i)) = collectionOfValues.Item(i)
Next i

在这里,我们将一个范围中的地址添加到某个集合,并将另一个范围中的值添加到第二个集合中,然后用这些值填充这些地址上的单元格。

这是第二个代码,其效果相同:

For i = 1 To rng1.Rows.Count
  For j = 1 To rng1.Columns.Count
       rng2.Cells(i, j) = rng1.Cells(i, j)
  Next j
Next i

那么,问题是 - 这两种情况的执行时间是多少?我的意思是,很明显第二种情况是 O(n^2) (为了更容易我们假设范围是平方的)。

第一个怎么样? For Each 是否被视为嵌套循环?

如果是这样,是否意味着第一个代码的时间是 O(n^2) + O(n^2) + O(n^2) = 3*O(n^2) 这使得与第二次编码时间相同吗?

一般来说,除了第一个代码在创建集合时需要额外的内存之外,这两个代码是否有所不同?

提前非常感谢。

最佳答案

实际上,你的第一个例子是O(n^4)!

这可能听起来令人惊讶,但这是因为索引到 VBA 集合具有线性复杂性,而不是恒定的复杂性。 VBA Collection 本质上具有列表的性能特征 - 通过索引获取元素 N 所需的时间与 N 成正比。通过索引迭代整个元素所需的时间与 N 成正比到 N^2。 (我对你进行了切换,以区分 N(数据结构中的元素数量)和 n(方形单元格一侧的单元数)。所以这里 N = n^2。)

这就是 VBA 使用 For...Each 表示法来迭代集合的原因之一。当您使用 For...Each 时,VBA 在幕后使用迭代器,因此遍历整个 Collection 的时间复杂度为 O(N) 而不是 O(N^2)。

因此,切换回 n,前两个循环在包含 n^2 个单元格的范围内使用 For...Each,因此它们每个都是 O(n^2)。第三个循环是在包含 n^2 个元素的 Collection 上使用 For...Next,因此时间复杂度为 O(n^4)。

我实际上不确定你的最后一个循环,因为我不知道 Range 的 Cells 属性到底是如何工作的 - 那里可能存在一些额外的隐藏复杂性。但我认为 Cells 将具有数组的性能特征,因此通过索引进行随机访问的时间复杂度为 O(1),这将使最后一个循环的时间复杂度为 O(n^2)。

这是 Joel Spolsky 所说的“画家 Shlemiel 算法”的一个很好的例子:

There must be a Shlemiel the Painter's Algorithm in there somewhere. Whenever something seems like it should have linear performance but it seems to have n-squared performance, look for hidden Shlemiels. They are often hidden by your libraries.

(参见 stackoverflow 成立之前的这篇文章: http://www.joelonsoftware.com/articles/fog0000000319.html )

有关 VBA 性能的更多信息,请访问 Doug Jenkins 的网站:

http://newtonexcelbach.wordpress.com/2010/03/07/the-speed-of-loops/

http://newtonexcelbach.wordpress.com/2010/01/15/good-practice-best-practice-or-just-practice/

(如果这是一个“真正的”程序而不仅仅是一个学习练习,我也会赞同cyberkiwi所说的不要循环遍历范围只是为了复制单元格内容。)

关于vba - 在VBA中这两种使用循环的方式的时间复杂度有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4827963/

相关文章:

algorithm - 什么是最严格的渐近增长率

excel - 使用 VBA 中的 Replace 方法将数字存储为字符串

java - 这个函数逐层打印二叉树的时间和空间复杂度

excel - 如何使用excel宏在单元格中写入工作簿名称

excel - 两个减号在一起的含义 ("double unary")

python - 将 Python 字典写入 CSV,其中键 = 列,值 = 行

c++ - 在我的 Qt 应用程序中打开 Excel 并与之通信

java - 如何衡量该算法的时间复杂度(Big-O)?

vba - 当另一个工作表的公式结果发生变化时如何突出显示单元格?

excel - VBA - 将星期几的名称从任何语言更改为英文