Skip to content

Commit 83b05cc

Browse files
committed
feat: add kmp version index_of
1 parent bdd75e8 commit 83b05cc

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

planglib/std/slice.pi

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub trait SliceExt<T> {
22
fn index_of(sub_arr:[T]) Option<i64>;
3+
fn index_of_kmp(sub_arr:[T]) Option<i64>;
34
fn len() i64;
45
fn slice(start: i64, end: i64) [T];
56
fn copy(to:[T], len:i64) Result<()|SliceOutOfIdxErr>;
@@ -9,6 +10,25 @@ pub struct SliceOutOfIdxErr {
910

1011
}
1112

13+
14+
fn arr_next<T:Eq<T>>(arr:[T]) [i64] {
15+
let len = arr.len();
16+
let next = [0* len];
17+
next[0] = -1;
18+
let i = 0;
19+
let j = -1;
20+
while i < len - 1 {
21+
if j == -1 || arr[i].eq(&arr[j]) {
22+
i = i + 1;
23+
j = j + 1;
24+
next[i] = j;
25+
} else {
26+
j = next[j];
27+
}
28+
}
29+
return next;
30+
}
31+
1232
use core::eq::Eq;
1333
impl<T:Eq<T>> SliceExt<T> for [T] {
1434
/// # index_of
@@ -17,6 +37,18 @@ impl<T:Eq<T>> SliceExt<T> for [T] {
1737
fn index_of(sub_arr:[T]) Option<i64> {
1838
let len = self.len();
1939
let sub_len = sub_arr.len();
40+
41+
// Calculate the expected cost of both algorithms
42+
let cost_index_of = len * sub_len/2;
43+
let cost_index_of_kmp = len + sub_len;
44+
45+
// Choose the algorithm with the lower expected cost
46+
if cost_index_of_kmp < cost_index_of {
47+
return self.index_of_kmp(sub_arr);
48+
}
49+
50+
51+
2052
if sub_len > len || sub_len == 0{
2153
return None{};
2254
}
@@ -38,6 +70,31 @@ impl<T:Eq<T>> SliceExt<T> for [T] {
3870

3971
}
4072

73+
74+
fn index_of_kmp(sub_arr:[T]) Option<i64> {
75+
let len = self.len();
76+
let sub_len = sub_arr.len();
77+
if sub_len > len || sub_len == 0{
78+
return None{};
79+
}
80+
let next = arr_next(sub_arr);
81+
let i = 0;
82+
let j = 0;
83+
while i < len {
84+
if j == -1 || (*self)[i].eq(&sub_arr[j]) {
85+
i = i + 1;
86+
j = j + 1;
87+
} else {
88+
j = next[j];
89+
}
90+
if j == sub_len {
91+
return i - sub_len;
92+
}
93+
}
94+
return None{};
95+
}
96+
97+
4198
/// # len
4299
///
43100
/// Get the length of the array.

test/test/std_test.pi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ pub fn test_std() void {
88
let re1 = chars.index_of(subchars);
99
panic::assert(re is i64);
1010
panic::assert((re as i64!) == 2);
11+
re = "abfdscdcdcdcde".index_of("cdcde"); // will auto use kmp
12+
panic::assert(re is i64);
13+
panic::assert((re as i64!) == 9);
1114

1215
panic::assert(re1 is i64);
1316
panic::assert((re1 as i64!) == 2);

0 commit comments

Comments
 (0)