字符串查询算法
glibc中的strstr的two-way算法,two-way算法主要依据Critical Factorization理论。
要理解Critical Factorization理论,先要理解字符串的period:
设w是定义在字符集A上的非空字符串。设|w|是w的长度。存在正整数p,对所有满足模p同余的
非负整数i,j (i,j < |x|),等式:
w[i] = w[j]
都成立。则p称为字符串w的period。w最小的period记作p(w)。
若存在正整数wp使等式:
w[i] = w[wp+i]
对所有使等式两边有意义的i都成立,那么wp称为字符串w的weak period。
若正整数lp称为非空字符串w在位置l的local period,则有定义在A上的字符串u, v, x,使
w=uv; |u|=l+1;|x|=lp;并使字符串r,s满足下列条件之一:
1. u = rx && v = xs
2. x = ru && v = xs (r不是空字符串)
3. u = rx && x = vs (s不是空字符串)
4. x = ru && x = vs (r,s不是空字符串)
字符串w在位置l的最小local period记作p(w, l)。若此时p(w, l)=p(w),则字符串对(u, v)
称为w的Critical Factorization, l称为critical position。
two-way算法的第一步就是找到Critical Factorization。使用maximal suffix方法,依据如下理论:
字符串w的子字符串记作w[i..e)=w[i]w[i+1]...w[e-1]。w的最大后缀定义为:
存在整数i(i >= 0 && i < |w|),使得对字符串w有意义的所有整数j满足下式:
u[j..|w|) <= u[i..|w|) (4)
字符串的逆向最大后缀的定义与上述定义相似,只是将(4)式改成:
u[j..|w|) >= u[i..|w|) (5)
可以证明字符串w(|w| >= 2)至少有一个critical factorization,且l < p。此外设v是w的
maximal suffix,且w = uv。设m是w的tilde maximal suffix,且w = nm。如果v <= m那么
(n,m)是w的是critical factorization。如果v > m那么(u, v)是w的critical factorization。
Boyer and Moore的BM算法
对齐后从匹配串后面开始匹配,不匹配时的移位算法:
1. 坏字符规则:源串中当前比较的字符不相等且不出现在匹配串中,则把匹配串移位到坏字符的背后
2. 好字符规则: 后移位数 = 好后缀的位置 - 搜索词中的上一次出现位置, 然后继续从后开始匹配
举例来说,如果字符串"ABCDAB"的后一个"AB"是"好后缀"。那么它的位置是5(从0开始计算,取最后的"B"的值),在"搜索词中的上一次出现位置"是1(第一个"B"的位置),所以后移 5 - 1 = 4位,前一个"AB"移到后一个"AB"的位置。
再举一个例子,如果字符串"ABCDEF"的"EF"是好后缀,则"EF"的位置是5 ,上一次出现的位置是 -1(即未出现),所以后移 5 - (-1) = 6位,即整个字符串移到"F"的后一位。
可以看到,"坏字符规则"只能移3位,"好后缀规则"可以移6位。所以,Boyer-Moore算法的基本思想是,每次后移这两个规则之中的较大值。
更巧妙的是,这两个规则的移动位数,只与搜索词有关,与原字符串无关。因此,可以预先计算生成《坏字符规则表》和《好后缀规则表》。使用时,只要查表比较一下就可以了。
KMP算法(Knuth–Morris–Pratt 三人提出的,这几个中性能相对差)
原理:
cababababadcaddecbd查询匹配ababad
ababad 不匹配的时候,
aba 我们可以直接整块右边移动2位继续当前位置继续往下比较,避免了6次冗余操作
下面附上glibc2.6的相关代码
char *
STRSTR (const char *haystack_start, const char *needle_start)
{
const char *haystack = haystack_start;
const char *needle = needle_start;
size_t needle_len;
size_t haystack_len;
bool ok = true;
while (*haystack && *needle)
ok &= *haystack++ == *needle++;
if (*needle)
return NULL;
if (ok)
return (char *) haystack_start;
needle_len = needle - needle_start;
haystack = strchr (haystack_start + 1, *needle_start);
if (!haystack || __builtin_expect (needle_len == 1, 0))
return (char *) haystack;
needle -= needle_len;
haystack_len = (haystack > haystack_start + needle_len ? 1
: needle_len + haystack_start - haystack);
if (needle_len < LONG_NEEDLE_THRESHOLD)
return two_way_short_needle ((const unsigned char *) haystack,
haystack_len,
(const unsigned char *) needle, needle_len);
return two_way_long_needle ((const unsigned char *) haystack, haystack_len,
(const unsigned char *) needle, needle_len);
}
static RETURN_TYPE
two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
const unsigned char *needle, size_t needle_len)
{
size_t i;
size_t j;
size_t period;
size_t suffix;
suffix = critical_factorization (needle, needle_len, &period);
if (CMP_FUNC (needle, needle + period, suffix) == 0)
{
size_t memory = 0;
j = 0;
while (AVAILABLE (haystack, haystack_len, j, needle_len))
{
i = MAX (suffix, memory);
while (i < needle_len && (CANON_ELEMENT (needle[i])
== CANON_ELEMENT (haystack[i + j])))
++i;
if (needle_len <= i)
{
i = suffix - 1;
while (memory < i + 1 && (CANON_ELEMENT (needle[i])
== CANON_ELEMENT (haystack[i + j])))
--i;
if (i + 1 < memory + 1)
return (RETURN_TYPE) (haystack + j);
j += period;
memory = needle_len - period;
}
else
{
j += i - suffix + 1;
memory = 0;
}
}
}
else
{
period = MAX (suffix, needle_len - suffix) + 1;
j = 0;
while (AVAILABLE (haystack, haystack_len, j, needle_len))
{
i = suffix;
while (i < needle_len && (CANON_ELEMENT (needle[i])
== CANON_ELEMENT (haystack[i + j])))
++i;
if (needle_len <= i)
{
i = suffix - 1;
while (i != SIZE_MAX && (CANON_ELEMENT (needle[i])
== CANON_ELEMENT (haystack[i + j])))
--i;
if (i == SIZE_MAX)
return (RETURN_TYPE) (haystack + j);
j += period;
}
else
j += i - suffix + 1;
}
}
return NULL;
}
static size_t
critical_factorization (const unsigned char *needle, size_t needle_len,
size_t *period)
{
size_t max_suffix, max_suffix_rev;
size_t j;
size_t k;
size_t p;
unsigned char a, b;
max_suffix = SIZE_MAX;
j = 0;
k = p = 1;
while (j + k < needle_len)
{
a = CANON_ELEMENT (needle[j + k]);
b = CANON_ELEMENT (needle[max_suffix + k]);
if (a < b)
{
j += k;
k = 1;
p = j - max_suffix;
}
else if (a == b)
{
if (k != p)
++k;
else
{
j += p;
k = 1;
}
}
else
{
max_suffix = j++;
k = p = 1;
}
}
*period = p;
max_suffix_rev = SIZE_MAX;
j = 0;
k = p = 1;
while (j + k < needle_len)
{
a = CANON_ELEMENT (needle[j + k]);
b = CANON_ELEMENT (needle[max_suffix_rev + k]);
if (b < a)
{
j += k;
k = 1;
p = j - max_suffix_rev;
}
else if (a == b)
{
if (k != p)
++k;
else
{
j += p;
k = 1;
}
}
else
{
max_suffix_rev = j++;
k = p = 1;
}
}
if (max_suffix_rev + 1 < max_suffix + 1)
return max_suffix + 1;
*period = p;
return max_suffix_rev + 1;
}
static RETURN_TYPE
two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
const unsigned char *needle, size_t needle_len)
{
size_t i;
size_t j;
size_t period;
size_t suffix;
size_t shift_table[1U << CHAR_BIT];
suffix = critical_factorization (needle, needle_len, &period);
for (i = 0; i < 1U << CHAR_BIT; i++)
shift_table[i] = needle_len;
for (i = 0; i < needle_len; i++)
shift_table[CANON_ELEMENT (needle[i])] = needle_len - i - 1;
if (CMP_FUNC (needle, needle + period, suffix) == 0)
{
size_t memory = 0;
size_t shift;
j = 0;
while (AVAILABLE (haystack, haystack_len, j, needle_len))
{
shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])];
if (0 < shift)
{
if (memory && shift < period)
{
shift = needle_len - period;
}
memory = 0;
j += shift;
continue;
}
i = MAX (suffix, memory);
while (i < needle_len - 1 && (CANON_ELEMENT (needle[i])
== CANON_ELEMENT (haystack[i + j])))
++i;
if (needle_len - 1 <= i)
{
i = suffix - 1;
while (memory < i + 1 && (CANON_ELEMENT (needle[i])
== CANON_ELEMENT (haystack[i + j])))
--i;
if (i + 1 < memory + 1)
return (RETURN_TYPE) (haystack + j);
j += period;
memory = needle_len - period;
}
else
{
j += i - suffix + 1;
memory = 0;
}
}
}
else
{
size_t shift;
period = MAX (suffix, needle_len - suffix) + 1;
j = 0;
while (AVAILABLE (haystack, haystack_len, j, needle_len))
{
shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])];
if (0 < shift)
{
j += shift;
continue;
}
i = suffix;
while (i < needle_len - 1 && (CANON_ELEMENT (needle[i])
== CANON_ELEMENT (haystack[i + j])))
++i;
if (needle_len - 1 <= i)
{
i = suffix - 1;
while (i != SIZE_MAX && (CANON_ELEMENT (needle[i])
== CANON_ELEMENT (haystack[i + j])))
--i;
if (i == SIZE_MAX)
return (RETURN_TYPE) (haystack + j);
j += period;
}
else
j += i - suffix + 1;
}
}
return NULL;
}
google下来的一些性能测试,随机字串性能测试比较
Boyer-Moore 1734 ms Boyer-Moore-Horspool (Joel’s original implementation) 1101 ms Boyer-Moore-Horspool (our implementation) 1080 ms Turbo Boyer-Moore 2683 ms strstr 2116 ms memmem 3047 ms相关知识
字符串查询算法
SQL根据分隔的字符串,查询并组合查询结果的解决方案(转)
算法的艺术
当向搜索字符串添加1个或2个字符时,为什么这个MySQL查询花费的时间会不成比例地长?
字符串
字符串(C# 编程指南)
机器学习算法
js植物算法
模糊查询和转义字符.doc
图像识别算法有哪些
网址: 字符串查询算法 https://www.huajiangbk.com/newsview105050.html
上一篇: nyoj685查找字符串(字典树 |
下一篇: 查找4位编码,不要加点: 观赏用 |
推荐分享

- 1君子兰什么品种最名贵 十大名 4012
- 2世界上最名贵的10种兰花图片 3364
- 3花圈挽联怎么写? 3286
- 4迷信说家里不能放假花 家里摆 1878
- 5香山红叶什么时候红 1493
- 6花的意思,花的解释,花的拼音 1210
- 7教师节送什么花最合适 1167
- 8勿忘我花图片 1103
- 9橄榄枝的象征意义 1093
- 10洛阳的市花 1039