Files
cKit/Foundation/c_StrIndexKmp.c
T

77 lines
2.2 KiB
C
Raw Normal View History

2026-08-29 01:50:50 +08:00
#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;
}