Files
cKit/String/c_TrieSet.c
T
2026-08-31 22:49:42 +08:00

365 lines
12 KiB
C

#include <c_TrieSet.h>
#include <c_StringBuffer.h>
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
#define c_StringBuffer_PushBack c_StringBuffer_AppendChar
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
/**
* @brief 内部私有:安全开辟并清空一个全新的 Trie SET 节点
*/
C_STATIC_FORCE_INLINE
c_TrieSetNode* c_TrieSet_CreateNode(c_Allocator_t* alloc) {
c_TrieSetNode* node = (c_TrieSetNode*)c_Allocator_Alloc(alloc, sizeof(c_TrieSetNode));
if (!node) return NULL;
node->is_key = false;
memset(node->next, 0, sizeof(node->next)); // 256路子链接初始化清零
return node;
}
/**
* @brief 就地初始化多路单词查找树集合
*/
c_err_t c_TrieSet_Init(c_TrieSet_t* self, c_Allocator_t* allocator) {
if (!self) {
return C_ERR_PARAM;
}
if (allocator) {
self->allocator = *allocator;
} else {
self->allocator = c_DefaultAllocator;
}
self->root = NULL;
self->size = 0;
return C_ERR_OK;
}
/**
* @brief 内部递归注入状态机
*/
static c_err_t c_TrieSet_InternalAdd(c_TrieSet_t* self, c_TrieSetNode** node_ptr, const char* key, c_size_t d, bool* is_new_inserted) {
// 递归基 A:若下探路径上的节点为空,延迟惰性加载开辟新控制头
if (*node_ptr == NULL) {
*node_ptr = c_TrieSet_CreateNode(&self->allocator);
if (*node_ptr == NULL) return C_ERR_NOMEM;
}
c_TrieSetNode* curr = *node_ptr;
// 递归基 B:成功定位推进匹配到了字符串键的物理末尾截止字符 '\0'
if (key[d] == '\0') {
if (curr->is_key) {
// 🌟【强去重拦截】:元素已在集合中完好存在,果断扔回 C_ERR_EXIST 阻止向下流转
*is_new_inserted = false;
return C_ERR_EXIST;
}
curr->is_key = true;
*is_new_inserted = true;
return C_ERR_OK;
}
// 多路高速变轨寻址:利用字符原生无符号代码作为下标一键穿透
unsigned char c = (unsigned char)key[d];
return c_TrieSet_InternalAdd(self, &(curr->next[c]), key, d + 1, is_new_inserted);
}
/**
* @brief 向集合中注入添加一个变长元素键(自动去重,时间复杂度绝对锁定为 O(W))
*/
c_err_t c_TrieSet_Add(c_TrieSet_t* self, const char* key) {
if (!self || !key) return C_ERR_PARAM;
bool is_new = false;
c_err_t err = c_TrieSet_InternalAdd(self, &(self->root), key, 0, &is_new);
if (err == C_ERR_OK && is_new) {
self->size++; // 仅在去重确认后递增全局计数
}
return err;
}
/**
* @brief 内部下探滑窗辅助:根据指定字符串前缀寻找树内对应的局部根节点
*/
static c_TrieSetNode* c_TrieSet_SubtreeSearch(c_TrieSetNode* x, const char* key, c_size_t d) {
if (x == NULL) return NULL;
if (key[d] == '\0') return x;
unsigned char c = (unsigned char)key[d];
return c_TrieSet_SubtreeSearch(x->next[c], key, d + 1);
}
/**
* @brief 包含性检索判定(时间复杂度为完美的常数均摊 O(W))
*/
bool c_TrieSet_Contains(const c_TrieSet_t* self, const char* key) {
if (!self || !key || self->size == 0) return false;
c_TrieSetNode* x = c_TrieSet_SubtreeSearch(self->root, key, 0);
return (x != NULL && x->is_key);
}
/**
* @brief 内部私有:安全走查当前节点下方 256 路是否还有残存子代分支
*/
C_STATIC_FORCE_INLINE
bool c_TrieSet_HasChildren(const c_TrieSetNode* node) {
for (int r = 0; r < C_TRIE_R; r++) {
if (node->next[r] != NULL) return true;
}
return false;
}
/**
* @brief 内部级联递归惰性剪枝删除状态机
*/
static c_TrieSetNode* c_TrieSet_InternalRemove(c_TrieSet_t* self, c_TrieSetNode* x, const char* key, c_size_t d, c_err_t* out_err) {
if (x == NULL) {
*out_err = C_ERR_NOTFOUND;
return NULL;
}
if (key[d] == '\0') {
if (x->is_key) {
x->is_key = false; // 抹除完整键标识
self->size--;
*out_err = C_ERR_OK;
} else {
*out_err = C_ERR_NOTFOUND;
}
} else {
unsigned char c = (unsigned char)key[d];
x->next[c] = c_TrieSet_InternalRemove(self, x->next[c], key, d + 1, out_err);
}
// 🌟🌟🌟【自底向上绝对安全惰性剪枝防线】🌟🌟🌟
// 退栈回溯时,若发现当前节点的元素完结标记已被剥离,且下方已无任何子代网络常驻
if (!x->is_key) {
if (!c_TrieSet_HasChildren(x)) {
// 果断对该多路节点实施就地物理垃圾回收,返回 NULL 断开父链接挂载
c_Allocator_Free(&self->allocator, x);
return NULL;
}
}
return x;
}
/**
* @brief 从有序集合中精准剔除一个指定的变长字符串元素(触发自适应级联剪枝)
*/
c_err_t c_TrieSet_Remove(c_TrieSet_t* self, const char* key) {
if (!self || !key) return C_ERR_PARAM;
if (self->size == 0) return C_ERR_EMPTY;
c_err_t err = C_ERR_NOTFOUND;
self->root = c_TrieSet_InternalRemove(self, self->root, key, 0, &err);
return err;
}
/**
* @brief 后序深度递归遍历释放辅助
*/
static void c_TrieSet_InternalDestroy(c_Allocator_t* alloc, c_TrieSetNode* x) {
if (x == NULL) return;
for (int r = 0; r < C_TRIE_R; r++) {
c_TrieSet_InternalDestroy(alloc, x->next[r]);
}
c_Allocator_Free(alloc, x);
}
/**
* @brief 集合彻底反初始化注销销毁
*/
void c_TrieSet_Destroy(c_TrieSet_t* self) {
if (self && self->root) {
c_TrieSet_InternalDestroy(&self->allocator, self->root);
self->root = NULL;
self->size = 0;
}
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
/**
* @brief 内部静态辅助:下探滑窗寻找特定前缀所在的局部子树根节点
*/
static c_TrieSetNode* c_TrieSet_FindSubtreeRoot(c_TrieSetNode* x, const char* prefix, c_size_t d) {
if (x == NULL) return NULL;
if (prefix[d] == '\0') return x;
unsigned char c = (unsigned char)prefix[d];
return c_TrieSet_FindSubtreeRoot(x->next[c], prefix, d + 1);
}
/**
* @brief 内部DFS辅助:供 KeysWithPrefix 前缀联想使用(由 c_StringBuffer_t 驱动)
*/
static c_err_t c_TrieSet_CollectPrefixDFS(c_TrieSetNode* x, c_StringBuffer_t* path_buf, c_StringList_t* results) {
if (x == NULL) return C_ERR_OK;
// 1. 若当前路径构成集合内一个有效的完整唯一元素
if (x->is_key) {
c_err_t err = c_StringList_Add(results, c_StringBuffer_CStr(path_buf));
if (err != C_ERR_OK) return err;
}
// 2. 单调向全 256 路子代分支网络执行就地滑动探测
for (int r = 0; r < C_TRIE_R; r++) {
if (x->next[r] != NULL) {
// 就地前推:将当前分支字符压入自适应缓冲区,零堆碎片开销
c_err_t err = c_StringBuffer_PushBack(path_buf, (char)r);
if (err != C_ERR_OK) return err;
err = c_TrieSet_CollectPrefixDFS(x->next[r], path_buf, results);
if (err != C_ERR_OK) return err;
// 就地回溯:探查完当前分支后,执行 PopBack 弹栈抹除
c_StringBuffer_PopBack(path_buf);
}
}
return C_ERR_OK;
}
/**
* @brief 🌟 集合高阶接口 1:前缀模糊联想匹配检索
*/
c_err_t c_TrieSet_KeysWithPrefix(c_TrieSet_t* self, const char* prefix, c_StringList_t* results) {
if (!self || !prefix || !results) return C_ERR_PARAM;
if (self->size == 0 || self->root == NULL) return C_ERR_OK;
c_TrieSetNode* subtree_root = c_TrieSet_FindSubtreeRoot(self->root, prefix, 0);
if (subtree_root == NULL) return C_ERR_OK; // 前缀路径未走通,平滑返回空行
// 初始化独立的弹性路径缓冲区,前置装填好已匹配的公共前缀
c_StringBuffer_t path_buffer;
c_size_t prefix_len = strlen(prefix);
c_err_t err = c_StringBuffer_Init(&path_buffer, prefix_len + 16, &self->allocator);
if (err != C_ERR_OK) return err;
c_StringBuffer_Append(&path_buffer, prefix, prefix_len);
// 启动多路并行 DFS 状态机
err = c_TrieSet_CollectPrefixDFS(subtree_root, &path_buffer, results);
c_StringBuffer_Destroy(&path_buffer); // 原子回收局部缓冲区
return err;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/**
* @brief 内部递归辅助:供 KeysThatMatch 通配符正则走查使用(由 c_StringBuffer_t 驱动)
*/
static c_err_t c_TrieSet_MatchPatternRecursive(c_TrieSetNode* x, const char* pattern, c_size_t d, c_StringBuffer_t* path_buf, c_StringList_t* results) {
if (x == NULL) return C_ERR_OK;
char current_pat = pattern[d];
// 递归基:模式串已步进到末尾截止位置
if (current_pat == '\0') {
if (x->is_key) {
c_err_t err = c_StringList_Add(results, c_StringBuffer_CStr(path_buf));
if (err != C_ERR_OK) return err;
}
return C_ERR_OK;
}
// 🌟🌟🌟【通配符万能字符信道辐射状态机】🌟🌟🌟
if (current_pat == '.') {
for (int r = 0; r < C_TRIE_R; r++) {
if (x->next[r] != NULL) {
c_StringBuffer_PushBack(path_buf, (char)r); // 就地前推
c_err_t err = c_TrieSet_MatchPatternRecursive(x->next[r], pattern, d + 1, path_buf, results);
if (err != C_ERR_OK) {
c_StringBuffer_PopBack(path_buf);
return err;
}
c_StringBuffer_PopBack(path_buf); // 就地回溯恢复
}
}
} else {
// 精确字符 O(1) 二级单路快速寻址
unsigned char c = (unsigned char)current_pat;
if (x->next[c] != NULL) {
c_StringBuffer_PushBack(path_buf, (char)c);
c_err_t err = c_TrieSet_MatchPatternRecursive(x->next[c], pattern, d + 1, path_buf, results);
if (err != C_ERR_OK) {
c_StringBuffer_PopBack(path_buf);
return err;
}
c_StringBuffer_PopBack(path_buf);
}
}
return C_ERR_OK;
}
/**
* @brief 🌟 集合高阶接口 2:通配符正则全词模糊匹配接口
*/
c_err_t c_TrieSet_KeysThatMatch(c_TrieSet_t* self, const char* pattern, c_StringList_t* results) {
if (!self || !pattern || !results) return C_ERR_PARAM;
if (self->size == 0 || self->root == NULL) return C_ERR_OK;
c_StringBuffer_t path_buffer;
c_err_t err = c_StringBuffer_Init(&path_buffer, strlen(pattern) + 8, &self->allocator);
if (err != C_ERR_OK) return err;
err = c_TrieSet_MatchPatternRecursive(self->root, pattern, 0, &path_buffer, results);
c_StringBuffer_Destroy(&path_buffer);
return err;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/**
* @brief 内部寻阻辅助:供 LongestPrefixOf 深度爬坡状态机使用
*/
static void c_TrieSet_FindLongestPrefixLength(c_TrieSetNode* x, const char* query, c_size_t d, c_size_t* out_longest_len) {
if (x == NULL) return;
if (x->is_key) {
*out_longest_len = d; // 沿途更新最大有效掩码位宽
}
if (query[d] == '\0') return;
unsigned char c = (unsigned char)query[d];
c_TrieSet_FindLongestPrefixLength(x->next[c], query, d + 1, out_longest_len);
}
/**
* @brief 🌟 集合高阶接口 3:最长前缀分级掩码路由寻址
*/
c_err_t c_TrieSet_LongestPrefixOf(c_TrieSet_t* self, const char* query, c_StringList_t* results) {
if (!self || !query || !results) return C_ERR_PARAM;
if (self->size == 0 || self->root == NULL) return C_ERR_OK;
c_size_t longest_match_length = 0;
c_TrieSet_FindLongestPrefixLength(self->root, query, 0, &longest_match_length);
if (longest_match_length == 0 && !self->root->is_key) {
return C_ERR_NOTFOUND;
}
// 利用 StringBuffer 直接截断装填该寻址段
c_StringBuffer_t path_buffer;
c_err_t err = c_StringBuffer_Init(&path_buffer, longest_match_length + 4, &self->allocator);
if (err != C_ERR_OK) return err;
c_StringBuffer_Append(&path_buffer, query, longest_match_length);
err = c_StringList_Add(results, c_StringBuffer_CStr(&path_buffer));
c_StringBuffer_Destroy(&path_buffer);
return err;
}