在C中优化搜索算法

时间:2008-08-19 07:28:32

标签: c performance algorithm optimization

这种顺序搜索算法的性能(取自 The Practice of Programming)使用C的任何本机实用程序进行改进,例如如果我将i变量设置为寄存器变量?

int lookup(char *word, char*array[])
{
    int i

    for (i = 0; array[i] != NULL; i++)
        if (strcmp(word, array[i]) == 0)
            return i;

    return -1;
}

10 个答案:

答案 0 :(得分:24)

是的,但只是非常轻微。使用更好的算法可以实现更大的性能提升(例如,保持列表排序并进行二分查找)。

一般来说,优化给定的算法只能让你到目前为止。选择更好的算法(即使它没有完全优化)可以为您提供相当大的(数量级)性能改进。

答案 1 :(得分:2)

我认为,它不会产生太大的影响。编译器已经在那个方向上进行了优化。

此外,变量i没有太大的影响,单词在整个函数中保持不变,其余的太大而不适合任何寄存器。只有缓存有多大以及整个阵列是否适合那里。

字符串比较在计算上相当昂贵。

你可以在搜索之前对数组使用某种散列吗?

答案 2 :(得分:2)

作为哨兵方法,有众所周知的技术。 要使用sentinel方法,您必须知道“array []”的长度。 您可以使用sentinal删除“array [i]!= NULL”进行比较。

int lookup(char *word, char*array[], int array_len)
{
    int i = 0;
    array[array_len] = word;
    for (;; ++i)
        if (strcmp(word, array[i]) == 0) 
            break;
    array[array_len] = NULL;
    return (i != array_len) ? i : -1;
}

答案 3 :(得分:1)

如果您正在阅读TPOP,接下来将会看到他们如何使用不同的数据结构和算法将搜索速度提高许多倍。

但是你可以通过替换像

这样的东西来加快速度
for (i = 0; i < n; ++i)
    foo(a[i]);

char **p = a;
for (i = 0; i < n; ++i)
    foo(*p);
    ++p;

如果数组末尾有一个已知值(例如NULL),你可以消除循环计数器:

for (p = a; *p != NULL; ++p)
    foo(*p)
祝你好运,这是一本好书!

答案 4 :(得分:0)

要优化该代码,最好的办法是重写strcmp例程,因为您只检查相等性而不需要评估整个单词。

除此之外,你不能做太多其他事情。您无法排序,因为您正在寻找更大文本中的文本。二进制搜索也不起作用,因为文本不太可能被排序。

我的2p(C-psuedocode):

wrd_end = wrd_ptr + wrd_len;
arr_end = arr_ptr - wrd_len;
while (arr_ptr < arr_end)
{
    wrd_beg = wrd_ptr; arr_beg = arr_ptr;
    while (wrd_ptr == arr_ptr)
    {
        wrd_ptr++; arr_ptr++;
        if (wrd_ptr == wrd_en)
            return wrd_beg;
    }
    wrd_ptr++;
}

答案 5 :(得分:0)

实际上,将I设置为寄存器变量将不会执行编译器不会执行的任何操作。

如果你愿意花一些时间预先处理参考数组,你应该谷歌“世界上最快的拼字游戏程序”并实现它。 Spoiler:它是针对字符查找优化的DAG。

答案 6 :(得分:0)

Mark Harrison:你的for循环永远不会终止! (++ p是缩进的,但实际上并不在for: - 中)

此外,在指针和索引之间切换通常对性能没有影响,也不会添加注册关键字(如已经提到的那样) - 编译器足够聪明,可以在适当的地方应用这些转换,如果你足够了解它你的cpu arch,它会比手动的psuedo-micro-optimations做得更好。

答案 7 :(得分:0)

匹配字符串的更快方法是将它们存储为Pascal样式。如果每个字符串不需要超过255个字符,请将它们大致存储起来,并将计数放在第一个字节中:

char s[] = "\x05Hello";

然后你可以这样做:

for(i=0; i<len; ++i) {
    s_len = strings[i][0];
    if(
        s_len == match_len
        && strings[i][s_len] == match[s_len-1]
        && 0 == memcmp(strings[i]+1, match, s_len-1)
    ) {
        return 1;
    }
}

为了获得非常快的速度,请为字符串start + 64,+ 128和下一个字符串的开头添加内存预取提示。但那太疯狂了。 : - )

答案 8 :(得分:0)

另一种快速方法是让编译器使用SSE2优化的memcmp。使用固定长度的char数组并对齐,以便字符串以64字节对齐方式开始。然后我相信你可以获得良好的memcmp函数,如果你将const char匹配[64]而不是const char * match传递给函数,或者strncpy匹配到64,128,256,无论字节数组。

考虑到这一点,这些SSE2匹配功能可能是英特尔和AMD的加速器库等软件包的一部分。检查一下。

答案 9 :(得分:-1)

/* there is no more quick  */
int lookup(char *word, char*array[])
{
    int i;
    for(i=0; *(array++) != NULL;i++)
        if (strcmp(word, *array) == 0)
            return i;
    return -1;
}