比strcspn()的天真实现更好

时间:2011-09-21 11:01:47

标签: c algorithm

我必须弄清楚我的主题字符串是否有任何不良字符(我绝对讨厌某些字符)。所以,如果我有一个名为str (char *str)的字符串,并且如果找到字符串bad (char *bad)中的任何字符,则拒绝字符串str。现在我可以使用strcspn(str,bad)来检查这个。但有人可以建议strcspn的实施可能是什么? 一个天真的实现是针对str的每个字符检查bad的每个字符,如果找到匹配则拒绝str

for(i=0;str[i]!='\0';i++)
  for(j=0;bad[j]!='\0';j++)
    if(bad[j]==str[i])
       return -1;   //reject string
return 1;    //accept string

或类似

for(i=0;str[i]!='\0';i++)
  if(strchr(bad,str[i]))   //will return non-NULL if str[i] is found in bad
    return -1;   //reject string
return 1;    //accept string

2 个答案:

答案 0 :(得分:8)

如果str非常长(或者您要针对同一组坏字符检查多个字符串),则可以通过创建大小为256的查找表来获得一些性能,其中元素 i <如果ASCII代码 i 的字符为坏,则/ em>为1,否则为零:

int contains_bad(const char* str, const char* bad) {
    unsigned short int table[256];
    char* ch;

    /* Prepare the lookup table */
    memset(table, 0, 256);
    for (ch = bad; *ch != 0; ch++)
        table[*ch] = 1;

    /* Test the string */
    for (ch = str; *ch != 0; ch++)
        if (table[*ch])
            return -1;

    return 1;
}

上面的代码是O(m + n)最坏的情况,其中 m bad 的长度而 n 的长度是 STR ;你的解决方案是O(mn)最坏的情况。


更新:这是该函数的替代版本,它将查找表保存在静态存储中,并且每255次调用只清除一次。

int contains_bad(const char* str, const char* bad) {
    static unsigned short int table[256];
    static unsigned short int marker = 255;
    char* ch;

    /* Prepare the lookup table */
    if (marker == 255) {
        memset(table, 0, 256);
        marker = 1;
    } else {
        marker++;
    }
    for (ch = bad; *ch != 0; ch++)
        table[*ch] = marker;

    /* Test the string */
    for (ch = str; *ch != 0; ch++)
         if (table[*ch] == marker)
             return -1;

    return 1;
}

答案 1 :(得分:1)

如果您关心最坏情况的性能和/或线程安全性,这里有一个将表保持在堆栈中的变体。

#include <limits.h>
#include <stddef.h>

int contains_bad(const char *str, const char *bad) {
  size_t hint[UCHAR_MAX];
  size_t len_bad;
  for (len_bad = 0; bad[len_bad]; len_bad++) {
    hint[(unsigned char)bad[len_bad] - 1] = len_bad;
  }
  for (; *str; str++) {
    size_t i = hint[(unsigned char)*str - 1];
    if (i < len_bad && *str == bad[i]) return 1;
  }
  return 0;
}

(对于语言律师:从技术上讲,未初始化的数组hint可能有潜伏的陷阱表示。如果你知道这意味着什么,并且实际上关心C程序在长期死平台上的行为,一个解决方案,如果{ {1}}是一个集合,因此不超过bad个字符,是要将UCHAR_MAX更改为size_t hint[UCHAR_MAX],因为保证unsigned char不会有陷阱表示。)