了解两种Matrix旋转算法的性能

时间:2016-03-07 16:17:30

标签: c# algorithm

我对基本面的深入理解已经对这些类型的问题解决挑战造成了影响。

HackerRank矩阵旋转问题是一个非常有趣的解决方案。我建议那些试图丰富编码技能的人使用hackerrank(https://www.hackerrank.com/challenges/matrix-rotation-algo

问题摘要是给出一个整数的R x C矩阵,其中R和C的最小值必须是偶数。您必须逆时针旋转矩阵x次。旋转适用于矩阵的元素,而不是矩阵尺寸,如果不清楚的话。

所以我用两种算法解决了这个问题。它们非常相似,因为您可以想象矩阵像洋葱层,您可以在每个层中循环,并旋转该层中的元素。旋转的数量只是x%(该层中元素的数量),因此如果给出x = 1,000,000,则重复完全旋转没有意义。

第一个,最快的是: https://codetidy.com/8002/

第二个,不循环旋转次数,而是做一些重要的逻辑和数学来确定将元素移动到哪里。 https://codetidy.com/8001/

所以当我写第二个时,我认为它会更快疯狂,因为你不会迭代每层中的最大旋转次数。然而,它最终变得更慢。

我不太明白为什么。我在控制台中记录了迭代次数,第一次迭代次数增加了50倍,但速度更快。

1 个答案:

答案 0 :(得分:1)

迭代次数不是一切。以下是一些可能影响性能的一般事项。

要记住数组和矩阵的一个重要事项是缓存命中。如果您的操作产生大量缓存命中,则它们看起来会快几个数量级。要获得缓存命中,通常需要按内存顺序排列。对于顺序前进的数组。对于矩阵,它意味着首先递增最低指数。要获得未命中,您需要以大于高速缓存行大小的增量跳转(取决于CPU)。有趣的实验:基准for (i...) for (j...) ++m[i][j]for (i...) for (j..) ++m[j][i]以查看差异。

在你的情况下,我猜想更快的方法至少对水平部分有非常线性的访问。

然后是分支预测。现代CPU管理指令以更好地利用现有硬件。分支(IF)会破坏管道,因为您不知道要采用哪条路径(该指令仍在执行)。作为优化,编译器/ CPU选择一个并开始处理,如果条件结果是另一种方式,它将抛弃一切并重新开始处理。检查通常会产生相同结果的内容(如i<n)会比那些难以预测的内容更快。

这些是一些低级别的原因,为什么更简单的方法可能看起来更快。添加一些更高级别的原因(比如编译器没有按照你期望的方式优化代码),你会得到这样的结果。

重要说明:复杂性反映了渐近行为。是的,对于足够大的矩阵,第二种方法会更快,并且用于此问题的大小很可能不够大。