查找int数组是否包含数字的最快方法

时间:2011-08-22 18:54:36

标签: java android arrays algorithm

这是一个奇怪的问题。我在Java中有一个整数数组,其中每个int代表一种颜色。它们将是0xFFFFFFFF或0x0。如果此数组包含任何等于0xFFFFFFFF的值,那么最快的方法是什么?

这是我目前的代码:

int length = w * h;
for (int i = 0; i < length; i++) {
    if (pixels[i] == 0xFFFFFFFF) {
        return true;
    }
}

我不知道是否有更快的方法来做到这一点。我想你的兽医可能会有一两招。

编辑:看到它只是来自Bitmap.getPixels()的一个愚蠢的像素数组,它无法被排序或转换为另一个存储结构。感谢大家的投入,看起来循环是这种情况下的最佳方式。

9 个答案:

答案 0 :(得分:11)

不,除非整数数组已经排序,否则没有更快的方法,我怀疑它是一组颜色。

扫描未排序的数组需要线性时间“O(n)”。这就是你所做的,一旦找到匹配就退出方法,这也很好。

答案 1 :(得分:11)

没有切换到其他一些数据结构,没有,没有更好的方法来查找数组是否包含该值。您必须查看所有数组元素以查看它是否存在,因为如果您不检查某个特定位置,您可能会错过该像素颜色的一个副本。

也就是说,有其他方法可以解决这个问题。以下是关于如何加快这一点的一些想法:

  • 如果每个值都保证为白色或黑色,则可以在数组旁边存储两个额外的布尔值,表示是否有白色或黑色像素。这样,一旦你运行扫描一次,你就可以回读一下布尔。您还可以存储白色和黑色像素的数量以及数组,然后每当您写入像素时,通过递减原始颜色的像素数并增加新颜色的像素数来更新计数。这样就可以通过查看正确的计数器是否为非零来检查O(1)中是否存在给定颜色的像素。

  • 或者,如果您碰巧知道某些图像(可能是白色和黑色像素应该在哪里),您可以考虑以不同的顺序进行迭代。例如,如果你正在寻找的像素倾向于聚集在图像的中心,重写循环以检查那里首先可能是一个好主意,因为如果有任何类型的像素你会更快地找到它们。这仍然具有相同的最坏情况行为,但对于“逼真”的图像可能会更快。

  • 如果你有多个线程可用并且数组非常庞大(数百万个元素),你可以考虑让多个线程分别搜索数组的一部分来获取值。只有在您有理由怀疑大部分图像不是白色的情况下,这才是可行的。

  • 由于在大多数逼真的图像中,您可能认为图像是混合颜色而您只是寻找一种颜色的东西,因此您可能需要考虑将图像存储为sparse array ,您存储恰好是一种颜色(例如,白色)的像素列表,然后假设其他所有颜色都是黑色。如果您希望大多数图像是带有少量异常值的纯色,这可能是一个非常好的表示。此外,它可以让您不断查询是否存在任何黑色或白色像素 - 只需检查设置像素列表是否为空或者是否包含整个图像。

  • 如果顺序无关紧要,您还可以将元素存储在某个容器中,如哈希表,这可以让您(O)查询元素是否存在。您也可以对数组进行排序,然后只检查端点。

  • 作为微优化,你可以考虑总是在真实图像上附加两个值 - 一个白色像素和一个黑色像素 - 这样你就可以一直迭代直到找到值。这消除了循环中的一个比较(检查是否是入境)和非常大的数组的is recommended by some authors

  • 如果你认为大多数图像是白色和黑色的良好混合,并且可以在一小部分时间内得到错误的答案,你可以考虑探测一些随机位置并检查它们中是否有任何一个正确的颜色。如果是这样,那么显然存在正确颜色的像素并且您已完成。否则,运行完整线性扫描。对于颜色很好混合的图像,这可以节省大量的时间,因为你可以探测一些少量的位置(比如它们的O(log n))并最终避免在许多地方进行大量线性扫描案例。这比以前快了几倍。

  • 如果每个值都是白色或黑色,您还可以考虑将图像存储在bitvector中。这会将数组的大小压缩机器字大小的因子(可能在32-128x压缩之间)然后您可以遍历压缩数组并查看是否有任何值不等于0以查看是否有任何像素是白色的。这也节省了大量的空间,我实际上建议这样做,因为它也使很多其他操作变得容易。

希望这有帮助!

答案 2 :(得分:2)

在字节码级别无关紧要,但在本机代码级别

if (pixels[i] != 0)

可能会快一点,因为您确定只会显示这两个值。

答案 3 :(得分:1)

如果你的阵列真的很大,那么划分和征服可能是值得的。也就是说,将数据段分配给多个线程(可能是t个线程,其中t是可用处理器核心的数量)。使用足够大的数据集,并行性可以分摊线程启动成本。

答案 4 :(得分:1)

以下是有助于大型数组的简单优化:将请求的值放在数组的末尾,从而消除数组边界检查。 (templatetypedef已经提到过这种优化。)这个解决方案可以节省25%的循环运行时间,适用于大型数组:

tmp = a[n - 1]
a[n - 1] = 0xFFFFFFFF

pos = 0
while a[pos] != 0xFFFFFFFF
    pos = pos + 1

a[n - 1] = tmp

if a[pos] = 0xFFFFFFFF then
    return pos
return -1

this地址上有运行时分析的C#实现。

答案 5 :(得分:0)

改善性能的唯一范围是比较。我觉得按位运算符会比条件运算符快一点。 你可以这样做

int length = w * h;
for (int i = 0; i < length; i++) {
    if (pixels[i] & 0xFFFFFFFF) {
        return true;
    }
}

答案 6 :(得分:0)

无法检查何时将颜色插入阵列?如果是这样,您可以存储包含0xFFFFFFFF颜色的数组元素的索引。既然你想要“ANY”条目具有这样的价值,那么这应该可以解决问题:D

如果没有,你的答案具有O(n)的复杂性,这是最好的,因为数组不是(并且不能如你所说)订购。

答案 7 :(得分:-1)

使用内置foreach比索引更快,因为id消除了绑定检查

for(int pix:pixels){
    if(pix!=0)
        return true;
}

答案 8 :(得分:-1)

Arrays.asList(...).contains(...)