77 lines
2.2 KiB
C
77 lines
2.2 KiB
C
#include <c_StrIndexKmp.h>
|
|
#include <c_Memory.h>
|
|
|
|
#define MAX_STACK_LPS 128
|
|
|
|
static void compute_LPS_table(const char* pattern, c_size_t m, long long* lps) {
|
|
c_size_t len = 0; // Length of the previous longest prefix suffix
|
|
lps[0] = 0; // lps[0] is always 0
|
|
c_size_t i = 1;
|
|
|
|
while (i < m) {
|
|
if (pattern[i] == pattern[len]) {
|
|
len++;
|
|
lps[i] = (long long)len;
|
|
i++;
|
|
} else {
|
|
if (len != 0) {
|
|
len = (c_size_t)lps[len - 1]; // Backtrack without shifting 'i'
|
|
} else {
|
|
lps[i] = 0;
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
long long c_StrIndexKmp(const char* text, const char* pattern) {
|
|
if (!text || !pattern) return -1;
|
|
|
|
const c_size_t n = strlen(text);
|
|
const c_size_t m = strlen(pattern);
|
|
|
|
if (m == 0) return 0; // An empty pattern matches at the very beginning
|
|
if (m > n) return -1; // Pattern is longer than the text container
|
|
|
|
// Optimization: Use a stack buffer if the pattern length fits, avoiding heap allocation cycles
|
|
long long stack_lps[MAX_STACK_LPS];
|
|
long long* lps = (m <= MAX_STACK_LPS) ? stack_lps : (long long*)C_ALLOC(m * sizeof(long long));
|
|
if (!lps) return -1; // Allocation failure fallback
|
|
|
|
// Step 1: Precompute the lookup table
|
|
compute_LPS_table(pattern, m, lps);
|
|
|
|
// Step 2: Linear string matching phase
|
|
c_size_t i = 0; // Index for text
|
|
c_size_t j = 0; // Index for pattern
|
|
long long matched_index = -1;
|
|
|
|
while (i < n) {
|
|
if (pattern[j] == text[i]) {
|
|
i++;
|
|
j++;
|
|
}
|
|
|
|
if (j == m) {
|
|
matched_index = (long long)(i - j); // Found match at index (i - j)
|
|
break; // Terminate early for the first occurrence
|
|
}
|
|
// Mismatch after j matches
|
|
else if (i < n && pattern[j] != text[i]) {
|
|
if (j != 0) {
|
|
j = (size_t)lps[j - 1]; // Slide the pattern using the precomputed LPS table
|
|
} else {
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clean up heap memory if it was allocated
|
|
if (lps != stack_lps) {
|
|
C_FREE(lps);
|
|
}
|
|
|
|
return matched_index;
|
|
}
|
|
|