Skip to content

Commit 27c98df

Browse files
kevinburchfieldsiriakimp2002
authored
Add Rabin Karp string search algorithm (TheAlgorithms#187)
* Rabin Karp Algorithm * test attribution * Update README.md Co-authored-by: Andrii Siriak <siryaka@gmail.com> Co-authored-by: imp <imp07@qq.com>
1 parent 5004776 commit 27c98df

File tree

4 files changed

+123
-1
lines changed

4 files changed

+123
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ These are for demonstration purposes only.
5555
## [Strings](./src/string)
5656

5757
- [x] [Knuth Morris Pratt](./src/string/knuth_morris_pratt.rs)
58-
- [ ] Rabin Carp
58+
- [x] [Rabin Carp](./src/string/rabin_karp.rs)
5959

6060
## [General](./src/general)
6161

src/string/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,9 @@ __Properties__
99
* Case space complexity O(w)
1010

1111
[kmp-wiki]: https://en.wikipedia.org/wiki/Knuth–Morris–Pratt_algorithm
12+
13+
### [Rabin Karp](./rabin_karp.rs)
14+
From [Wikipedia][rabin-karp-wiki]: a string-searching algorithm created by Richard M. Karp and Michael O. Rabin that uses hashing
15+
to find an exact match of a pattern string in a text.
16+
17+
[rabin-karp-wiki]: https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm

src/string/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
mod knuth_morris_pratt;
2+
mod rabin_karp;
23

34
pub use self::knuth_morris_pratt::knuth_morris_pratt;
5+
pub use self::rabin_karp::rabin_karp;

src/string/rabin_karp.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
pub fn rabin_karp(target: String, pattern: String) -> Vec<usize> {
2+
// Quick exit
3+
if target.is_empty() || pattern.is_empty() || pattern.len() > target.len() {
4+
return vec![];
5+
}
6+
7+
let string: String = (&pattern[0..pattern.len()]).to_string();
8+
let hash_pattern = hash(string.clone());
9+
let mut ret = vec![];
10+
for i in 0..(target.len() - pattern.len() + 1) {
11+
let s = (&target[i..(i + pattern.len())]).to_string();
12+
let string_hash = hash(s.clone());
13+
14+
if string_hash == hash_pattern && s == string {
15+
ret.push(i);
16+
}
17+
}
18+
ret
19+
}
20+
21+
fn hash(mut s: String) -> u16 {
22+
let prime: u16 = 101;
23+
let last_char = s
24+
.drain(s.len() - 1..)
25+
.next()
26+
.expect("Failed to get the last char of the string");
27+
let mut res: u16 = 0;
28+
for (i, &c) in s.as_bytes().iter().enumerate() {
29+
if i == 0 {
30+
res = (c as u16 * 256) % prime;
31+
} else {
32+
res = (((res + c as u16) % 101) * 256) % 101;
33+
}
34+
}
35+
(res + last_char as u16) % prime
36+
}
37+
38+
#[cfg(test)]
39+
mod tests {
40+
use super::*;
41+
42+
#[test]
43+
fn hi_hash() {
44+
let hash_result = hash("hi".to_string());
45+
assert_eq!(hash_result, 65);
46+
}
47+
48+
#[test]
49+
fn abr_hash() {
50+
let hash_result = hash("abr".to_string());
51+
assert_eq!(hash_result, 4);
52+
}
53+
54+
#[test]
55+
fn bra_hash() {
56+
let hash_result = hash("bra".to_string());
57+
assert_eq!(hash_result, 30);
58+
}
59+
60+
// Attribution to @pgimalac for his tests from Knuth-Morris-Pratt
61+
#[test]
62+
fn each_letter_matches() {
63+
let index = rabin_karp("aaa".to_string(), "a".to_string());
64+
assert_eq!(index, vec![0, 1, 2]);
65+
}
66+
67+
#[test]
68+
fn a_few_separate_matches() {
69+
let index = rabin_karp("abababa".to_string(), "ab".to_string());
70+
assert_eq!(index, vec![0, 2, 4]);
71+
}
72+
73+
#[test]
74+
fn one_match() {
75+
let index = rabin_karp("ABC ABCDAB ABCDABCDABDE".to_string(), "ABCDABD".to_string());
76+
assert_eq!(index, vec![15]);
77+
}
78+
79+
#[test]
80+
fn lots_of_matches() {
81+
let index = rabin_karp("aaabaabaaaaa".to_string(), "aa".to_string());
82+
assert_eq!(index, vec![0, 1, 4, 7, 8, 9, 10]);
83+
}
84+
85+
#[test]
86+
fn lots_of_intricate_matches() {
87+
let index = rabin_karp("ababababa".to_string(), "aba".to_string());
88+
assert_eq!(index, vec![0, 2, 4, 6]);
89+
}
90+
91+
#[test]
92+
fn not_found0() {
93+
let index = rabin_karp("abcde".to_string(), "f".to_string());
94+
assert_eq!(index, vec![]);
95+
}
96+
97+
#[test]
98+
fn not_found1() {
99+
let index = rabin_karp("abcde".to_string(), "ac".to_string());
100+
assert_eq!(index, vec![]);
101+
}
102+
103+
#[test]
104+
fn not_found2() {
105+
let index = rabin_karp("ababab".to_string(), "bababa".to_string());
106+
assert_eq!(index, vec![]);
107+
}
108+
109+
#[test]
110+
fn empty_string() {
111+
let index = rabin_karp("".to_string(), "abcdef".to_string());
112+
assert_eq!(index, vec![]);
113+
}
114+
}

0 commit comments

Comments
 (0)