#include #include /** * @brief 内部私有:安全开辟并清空一个全新的 Trie 物理节点 */ C_STATIC_FORCE_INLINE c_TrieNode* c_TrieST_CreateNode(c_Allocator_t* alloc) { c_TrieNode* node = (c_TrieNode*)c_Allocator_Alloc(alloc, sizeof(c_TrieNode)); if (!node) return NULL; node->val = NULL; memset(node->next, 0, sizeof(node->next)); // 将 256 路子链接全部初始化填充为干净的 NULL return node; } /** * @brief 就地初始化多路单词查找树符号表 * * @param val_cp 多态值拷贝函数指针。若传入 NULL,则自动对 Value 降级执行原始物理地址浅拷贝托管 * @param val_free 多态值销毁函数指针。若 Value 属于扁平内置类型无须释放,可传入 NULL */ c_err_t c_TrieST_Init(c_TrieST_t* self, void* (*val_cp)(const void*, void*), void (*val_free)(void*, void*), void* val_arg, 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; self->val_cp = val_cp; self->val_free = val_free; self->val_arg = val_arg; return C_ERR_OK; } /** * @brief 内部递归插入状态机 */ static c_err_t c_TrieST_InternalPut(c_TrieST_t* self, c_TrieNode** node_ptr, const char* key, c_size_t d, const void* val, bool* is_new_key) { // 递归基 A:若沿途下探到的物理链接为空,在此处延迟惰性加载开辟新控制头 if (*node_ptr == NULL) { *node_ptr = c_TrieST_CreateNode(&self->allocator); if (*node_ptr == NULL) return C_ERR_NOMEM; } c_TrieNode* curr = *node_ptr; // 递归基 B:已经完美推进匹配到了变长键的物理末尾截止字符 if (key[d] == '\0') { if (curr->val == NULL) { *is_new_key = true; // 确定属于全新插入而非覆写 } else { *is_new_key = false; // 属于相同键更新覆写语义 if (self->val_free) { self->val_free(curr->val, self->val_arg); // 覆写前先摧毁老对象堆空间 } } // 执行值转储 if (self->val_cp) { curr->val = self->val_cp(val, self->val_arg); } else { curr->val = (void*)val; // 浅拷贝放行 } return C_ERR_OK; } // 多路高速变轨寻址:利用当前的无符号字符物理代码直接作为 256 维数组下标切入 unsigned char c = (unsigned char)key[d]; return c_TrieST_InternalPut(self, &(curr->next[c]), key, d + 1, val, is_new_key); } /** * @brief 存入键值对(时间复杂度仅取决于变长键长 O(W),与总键数完全独立解耦) * * @param key 以 '\0' 结尾的标准变长字符串键 * @param val 指向待注入 Value 对象的指针 */ c_err_t c_TrieST_Put(c_TrieST_t* self, const char* key, const void* val) { if (!self || !key || !val) return C_ERR_PARAM; bool is_new = false; c_err_t err = c_TrieST_InternalPut(self, &(self->root), key, 0, val, &is_new); if (err == C_ERR_OK && is_new) { self->size++; // 只有在全新键插入时才增加全局计数 } return err; } /** * @brief 内部下探滑窗辅助:根据指定字符串前缀寻找对应的 Trie 树局部根节点 */ static c_TrieNode* c_TrieST_SubtreeSearch(c_TrieNode* 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_TrieST_SubtreeSearch(x->next[c], key, d + 1); } /** * @brief 依据指定字符串键,精准提取读取其关联多态 Value 的原生物理堆地址 * * @return void* 找到时返回该值的原生指针;未找到或表为空时返回 NULL */ void* c_TrieST_Get(const c_TrieST_t* self, const char* key) { if (!self || !key || self->size == 0) return NULL; c_TrieNode* x = c_TrieST_SubtreeSearch(self->root, key, 0); if (x == NULL) return NULL; return x->val; // 🌟【重要约束】:必须返回 val,若 val 为 NULL 说明虽然路径前缀存在但并非完整键 } /** * @brief 检查符号表内是否有效包含指定的字符串键 */ bool c_TrieST_Contains(const c_TrieST_t* self, const char* key) { return c_TrieST_Get(self, key) != NULL; } /** * @brief 内部私有:安全走查某个 Trie 节点当前是否彻底沦为空仓空节点 */ C_STATIC_FORCE_INLINE bool c_TrieST_HasChildren(const c_TrieNode* node) { for (int r = 0; r < C_TRIE_R; r++) { if (node->next[r] != NULL) return true; // 只要 256 路中有任一指针不为空,说明包含子代分支 } return false; } /** * @brief 内部级联递归惰性剪枝删除状态机 */ static c_TrieNode* c_TrieST_InternalDelete(c_TrieST_t* self, c_TrieNode* 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->val != NULL) { // 精确命中要斩断的目标完整键:调用用户自备析构函数原路瓦解清除 Value 堆空间 if (self->val_free) { self->val_free(x->val, self->val_arg); } x->val = NULL; 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_TrieST_InternalDelete(self, x->next[c], key, d + 1, out_err); } // 🌟🌟🌟【自底向上绝对安全惰性剪枝防线(Lazy Pruning Countermeasure)】🌟🌟🌟 // 退栈回溯时,如果发现当前节点的值已经被抹除置空 (val == NULL) if (x->val == NULL) { // 且进一步走查发现它下方的 256 路子代指针也已全部被断开变空 (无子孙驻留) if (!c_TrieST_HasChildren(x)) { // 说明此节点已彻底丧失路由及存储价值,果断对其执行物理垃圾回收,并向父层级返回 NULL 断开挂载! c_Allocator_Free(&self->allocator, x); return NULL; } } return x; // 沿途返回自身指针,维持上层树拓扑形态不破裂 } /** * @brief 根据指定变长字符串键彻底从树中斩断移除该符号,并自动自适应逆向触发级联剪枝释放 */ c_err_t c_TrieST_Delete(c_TrieST_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_TrieST_InternalDelete(self, self->root, key, 0, &err); return err; } /** * @brief 内部后序深度递归遍历解构辅助 */ static void c_TrieST_InternalDestroy(c_Allocator_t* alloc, c_TrieNode* x, void (*val_free)(void*, void*), void* val_arg) { if (x == NULL) return; // 后序递归:先将 256 路子代网络彻底瓦解,最后再收拢解构自身 for (int r = 0; r < C_TRIE_R; r++) { c_TrieST_InternalDestroy(alloc, x->next[r], val_free, val_arg); } if (x->val && val_free) { val_free(x->val, val_arg); } c_Allocator_Free(alloc, x); } /** * @brief 符号表注销解构:全多路节点级联物理洗刷清除 */ void c_TrieST_Destroy(c_TrieST_t* self) { if (self && self->root) { c_TrieST_InternalDestroy(&self->allocator, self->root, self->val_free, self->val_arg); self->root = NULL; self->size = 0; } } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ /** * @brief 内部私有:下探滑窗寻找特定前缀所在的局部子树根节点 */ static c_TrieNode* c_TrieST_FindSubtreeRoot(c_TrieNode* 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_TrieST_FindSubtreeRoot(x->next[c], prefix, d + 1); } /** * @brief 内部DFS辅助状态机:供 KeysWithPrefix 前缀联想收集路径使用 */ static c_err_t c_TrieST_CollectPrefixDFS(c_TrieNode* x, c_StringBuffer_t* path_buf, c_StringList_t* results) { if (x == NULL) return C_ERR_OK; // 1. 若当前路径恰好构成一个有效独立键,从 StringBuffer 提取零拷贝只读 CStr 镜像,通过 StringList 值拷贝深拷贝压出 if (x->val != NULL) { 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_AppendChar(path_buf, (char)r); if (err != C_ERR_OK) return err; err = c_TrieST_CollectPrefixDFS(x->next[r], path_buf, results); if (err != C_ERR_OK) return err; // 🌟就地回溯:探查完当前分支后,执行 PopBack 弹栈抹除,恢复当前层缓冲区形态,物理杜绝内存污染 c_StringBuffer_RemoveAt(path_buf, path_buf->size-1, 1); } } return C_ERR_OK; } /** * @brief 🌟 高阶总线 API 1:前缀模糊联想匹配检索 */ c_err_t c_TrieST_KeysWithPrefix(c_TrieST_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_TrieNode* subtree_root = c_TrieST_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; // for (c_size_t i = 0; i < prefix_len; i++) { // c_StringBuffer_AppendChar(&path_buffer, prefix[i]); // } c_StringBuffer_Append(&path_buffer, prefix, prefix_len); // 启动多路并行 DFS 状态机 err = c_TrieST_CollectPrefixDFS(subtree_root, &path_buffer, results); c_StringBuffer_Destroy(&path_buffer); // 原子回收局部弹性路径链,常数级空间控制 return err; } /* ------------------------------------------------------------------------------------------------------------------ */ static c_err_t c_TrieST_MatchPatternRecursive(c_TrieNode* 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->val != NULL) { 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_AppendChar(path_buf, (char)r); // 就地前推 c_err_t err = c_TrieST_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_AppendChar(path_buf, (char)c); c_err_t err = c_TrieST_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 🌟 高阶总线 API 2:通配符正则全词模糊匹配接口(StringBuffer 加固版) */ c_err_t c_TrieST_KeysThatMatch(c_TrieST_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_TrieST_MatchPatternRecursive(self->root, pattern, 0, &path_buffer, results); c_StringBuffer_Destroy(&path_buffer); return err; } /* ------------------------------------------------------------------------------------------------------------------ */ /** * @brief 内部寻阻辅助:供 LongestPrefixOf 深度爬坡状态机使用 */ static void c_TrieST_FindLongestPrefixLength(c_TrieNode* x, const char* query, c_size_t d, c_size_t* out_longest_len) { if (x == NULL) return; if (x->val != NULL) { *out_longest_len = d; // 沿途更新最大有效掩码位宽 } if (query[d] == '\0') return; unsigned char c = (unsigned char)query[d]; c_TrieST_FindLongestPrefixLength(x->next[c], query, d + 1, out_longest_len); } /** * @brief 🌟 高阶总线 API 3:最长前缀分级掩码路由寻址(StringBuffer 加固版) */ c_err_t c_TrieST_LongestPrefixOf(c_TrieST_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_TrieST_FindLongestPrefixLength(self->root, query, 0, &longest_match_length); if (longest_match_length == 0 && self->root->val == NULL) { 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; // for (c_size_t i = 0; i < longest_match_length; i++) { // c_StringBuffer_AppendChar(&path_buffer, query[i]); // } 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; }