在数组中查找y的x个连续值的最有效方法是什么?

时间:2012-10-18 21:56:55

标签: c++ c performance algorithm profiling

通过callgrind运行我的应用程序显示,这条线路使其他所有内容相形见绌大约10,000倍。我可能会围绕它重新设计,但它让我感到疑惑;有没有更好的方法呢?

这就是我现在正在做的事情:

int i = 1;
while
(
    (
        (*(buffer++) == 0xffffffff && ++i) || 
        (i = 1)
    )
    &&
    i < desiredLength + 1
    &&
    buffer < bufferEnd
);

它正在寻找32位无符号整数数组中第一块desiredLength 0xffffffff值的偏移量。

它比我可能想出的涉及内循环的任何实现快得多。但它仍然太慢了。

6 个答案:

答案 0 :(得分:4)

我也会考虑search_n的建议,因为我很确定它能做到这一点。它实际上非常简单,基本上可以通过expect_length因子来加速。除非目标值在数组中非常密集。

以下是这样的想法:如果从位置K开始有I个连续值的实例,那么位置I + K - 1必须包含该值。所以你先检查一下;如果没有,则可能包含K个连续值的最早位置为I + K,因此您可以在那里重新启动算法。

另一方面,如果您在I + K - 1处找到值,则向后扫描,直到您达到I(在这种情况下您成功),或者您到达某个位置{{1其中不包含目标值。在后一种情况下,您知道有J - 1J的目标值,因此您现在可以检查I + K - 1。如果可行,您只需向后扫描到J + K - 1。如果它不起作用,则在I + K重新启动算法。

大多数情况下,您只会查看向量中的每个J + K位置。对于较大的K'th,这是一个很大的胜利。

答案 1 :(得分:3)

您标记了c ++,因此我假设您有可用的STL算法:

std::search_n(buffer, bufferEnd, desiredLength, 0xffffffff);

答案 2 :(得分:2)

尝试使用C标准库中的memcmp。现代编译器应具有非常优化的memxxx函数实现,从而使现代CPU的速度最快。

答案 3 :(得分:2)

只是一个想法,但你一次迭代int数组一个吗?考虑一下,如果*(buffer) != 0xffffffffbuffer[desiredLength-1] != 0xffffffff,那么您可以确定两者之间没有任何关系,这样您就可以buffer移动desiredLength而不仅仅是desiredLength如果*(buffer)远大于1,则可以显着提高您的速度。当然,它会使你的功能变得复杂,因为:

  1. 如果buffer[desiredLength-1]0xffffffff都等于*(buffer),那么你不能认为它们之间是连续的,所以你仍然需要检查它。
  2. 如果0xffffffff不等于buffer[desiredLength-1]0xffffffff等于0xffffffff,那么您必须跟踪buffer[desiredLength-1]序列的开头。
  3. 检查{{1}}
  4. 时,您必须确保不要超出缓冲区

    有点复杂,但可能加快速度。希望这是有道理的。

答案 4 :(得分:1)

如果我想实现这一点,我会使用memchrmemcmp来实现:

bool found = false;
std::vector<unsigned char> tmp(desiredLength*sizeof(uint32_t), 0xFF);
while( true ) {
    void* p = memchr(bufferStart, 0xFF,
        (bufferEnd-bufferStart-desiredLength) * sizeof(uint32_t));
    if( !p ) break;
    if( !memcmp(p, &tmp[0], desiredLength * sizeof(uint32_t)) ) {
        found = true;
        break;
    }
}

此外,您可以使用可能比您自己的代码更优化的std::search_n

答案 5 :(得分:0)

std::search_n不可用时:

int i = 1;
while
(
    (
        i == 1
        &&
        buffer < bufferEnd
        &&
        (
            (
                *buffer == desired
                &&
                *(buffer + desiredLength - 1) == desired
                &&
                (i = 3)
            )
            ||
            (buffer += desiredLength && (i = 1))
        )
    )
    ||
    (
        i == 2
        &&
        (
            (
                buffer > arr
                &&
                (*(--buffer) == desired)
            )
            ||
            (i = 3)
        )
    )
    ||
    (
        i >= 3
        &&
        buffer < bufferEnd
        &&
        (
            (
                *(buffer++) == desired
                &&
                (i++ || true)
            )
            ||
            (i = 1)
        )
        &&
        (
            i < 3
            ||
            i - 3 < desiredLength + 1
        )
    )
);
buffer -= i - 4;

if (buffer > bufferEnd - (i-3))
    buffer = bufferEnd;

返回相同的结果,仅略慢于std:search_n

buffer = std::search_n(buffer, bufferEnd-1, desiredLength, desired);
if (buffer == bufferEnd-1)
    buffer = bufferEnd;