Skip to content

Commit a4c92f3

Browse files
committed
substring_search: implement KMP for string
1 parent 16e391d commit a4c92f3

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ pub mod maximum_flow;
3535
pub mod radix_sorts;
3636

3737
pub mod tries;
38+
pub mod substring_search;

src/substring_search/mod.rs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use std::iter;
2+
3+
pub struct KMP<'a> {
4+
r: usize,
5+
dfa: Vec<Vec<usize>>,
6+
pat: &'a str
7+
}
8+
9+
impl<'a> KMP<'a> {
10+
// create the DFA from a string pattern
11+
pub fn new<'b>(pat: &'b str) -> KMP<'b> {
12+
let r = 256;
13+
let m = pat.len();
14+
let dfa = iter::repeat(iter::repeat(0).take(m).collect::<Vec<usize>>())
15+
.take(r).collect();
16+
17+
let mut ret = KMP {
18+
r: r,
19+
dfa: dfa,
20+
pat: pat
21+
};
22+
ret.build_dfa();
23+
ret
24+
}
25+
26+
fn build_dfa(&mut self) {
27+
let m = self.pat.len();
28+
let r = self.r;
29+
self.dfa[self.pat.char_at(0) as usize][0] = 1;
30+
let mut x = 0;
31+
for j in 1 .. m {
32+
for c in 0 .. r {
33+
self.dfa[c][j] = self.dfa[c][x]; // copy mismatch cases
34+
}
35+
self.dfa[self.pat.char_at(j) as usize][j] = j+1; // set match case
36+
x = self.dfa[self.pat.char_at(j) as usize][x];
37+
}
38+
}
39+
40+
pub fn search(&self, txt: &str) -> Option<usize> {
41+
let m = self.pat.len();
42+
let n = txt.len();
43+
let mut i = 0;
44+
let mut j = 0;
45+
while i < n && j < m {
46+
j = self.dfa[txt.char_at(i) as usize][j];
47+
i += 1;
48+
}
49+
if j == m {
50+
Some(i-m)
51+
} else {
52+
None
53+
}
54+
}
55+
}
56+
57+
58+
#[test]
59+
fn test_kmp() {
60+
let pat = "abracadabra";
61+
let text = "abacadabrabracabracadabrabrabracad";
62+
let kmp = KMP::new(pat);
63+
assert!(kmp.search(text).map_or(false, |pos| text[pos..].starts_with(pat)));
64+
}

0 commit comments

Comments
 (0)