#include #include /* ------------------------------------------------------------------------------------------------------------------ */ /* */ #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; }