strcspn源码分析

来源:互联网 发布:linux napt配置 编辑:程序博客网 时间:2024/05/16 11:04

  strcspn() 是用来顺序在字符串 s1 中搜寻与字符串 s2 中字符的第一个相同字符,返回这个字符在 s1 中第一次出现的位置(下标)。

size_t strcspn(const char *pstr, const char *strCharset)
  另外有一个类似的函数 strpbrk() 相同功能,但是返回的是字符串指针。

  简单地说,若 strcspn() 返回的数值为 n,则代表字符串 s1 开头连续有 n 个字符都不含字符串 s2 内的字符。

  要完成这个函数的功能,最简单的想法就是两个 for 循环:对于 s1 的每个字符,看看是不是在 s2 里,而这又需要一个循环。不用进行尝试,就知道这样做的效率有多低了,虽然空间复杂度是 O(1),但是时间复杂度是 O(mn)。先来看看 glibc 的实现。

size_tstrcspn (s, reject)     const char *s;     const char *reject;{  size_t count = 0;  while (*s != '\0')    if (strchr (reject, *s++) == NULL)      ++count;    else      return count;  return count;}
  对于 s1 的每个字符,都用 strchr 函数检查是否在 s2 的集合中。查看了 strchr 的实现,运用了类似 strlen 的策略,可以将复杂度从 O(m) 降到 O(m/32)。因此 glibc 的实现为 O(mn/32),但是仍然不够理想。

  这个时候我们想到布隆过滤器,它解决的不就是这个问题吗?给定一个非常大的集合,新来一个元素,布隆过滤器的算法即能在 O(1)  的时间内,判断此元素是否在这个集合里。基于这个想法,是不是有可能设计出 O(n) 的实现呢?

  我们继续来看看Microsoft Visual Studio 里 CRT 函数的实现。

/***int strcspn(string, control) - search for init substring w/o control charsPurpose:       returns the index of the first character in string that belongs       to the set of characters specified by control.  This is equivalent       to the length of the length of the initial substring of string       composed entirely of characters not in control.  Null chars not       considered.Entry:      char *string - string to search      char *control - set of characters not allowed in init substringExit:      returns the index of the first char in string      that is in the set of characters specified by control.Uses:Exceptions:***/inline int tStrCSpn(const tChar *pStr, const tChar *pStrSet){    // map有32个字节的大小,也就是256个bit,可把map看成一个2维数组[32][8]    unsigned char map[32] = {0};    // 第一部预处理:每个ASCII码(设为c)有8bit,把它分成2部分,低3位构成下标j(通过c&7(2进制为111)),    // 高5位构成下标i(通过c>>3得到)。这样在map[i][j]中置1表示字符存在    while(*pStrSet)    {        map[*pStrSet >> 3] |= (1 << (*pStrSet & 7));        pStrSet++;    }    map[0] |= 1;    int count = 0;    while(!(map[*pStr >> 3] & (1 << (*pStr & 7))))    {        count++;        pStr++;    }    return count;}

  这个算法效率非常高。第一趟先预处理,用一一对应的方法,构建一个 bitmap ,来标识哪些字符出现过。每次来一个新的字符,通过判断对应的 bitmap 位是否存在方法,就能非常简单判断字符是否在这个集合中了,复杂度 O(1),因此就算判断 n 次,复杂度也只有 O(n)。这也是“布隆过滤器”的一个非常基础的特殊情况。

原创粉丝点击