215 lines
7.1 KiB
C
215 lines
7.1 KiB
C
#include <c_BST.h>
|
|
|
|
c_err_t c_BST_Init(c_BST_t* self, c_size_t key_size, c_size_t val_size, c_SortCompare_t cmp, void* args, c_Allocator_t* allocator) {
|
|
if (!self || key_size == 0 || val_size == 0 || !cmp) {
|
|
return C_ERR_PARAM;
|
|
}
|
|
|
|
// 自适应分配器降级缺省安全播种
|
|
if (allocator) {
|
|
self->allocator = *allocator;
|
|
} else {
|
|
self->allocator = c_DefaultAllocator;
|
|
}
|
|
|
|
self->root = NULL;
|
|
self->size = 0;
|
|
self->key_size = key_size;
|
|
self->val_size = val_size;
|
|
self->cmp = cmp;
|
|
self->args = args;
|
|
|
|
return C_ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief 根据指定的 Key 检索关联的 Value 值(平均时间复杂度 O(log N))
|
|
*/
|
|
c_err_t c_BST_Get(const c_BST_t* self, const void* key, void* out_val) {
|
|
if (!self || !key || !out_val) return C_ERR_PARAM;
|
|
|
|
c_BSTNode* curr = self->root;
|
|
while (curr != NULL) {
|
|
int cmp_res = self->cmp(key, curr->key, self->args);
|
|
if (cmp_res < 0) {
|
|
curr = curr->left; // 目标比当前小,滑向左子树
|
|
} else if (cmp_res > 0) {
|
|
curr = curr->right; // 目标比当前大,滑向右子树
|
|
} else {
|
|
// 精确命中,将内部深度存储的数据镜像复制给外部
|
|
memcpy(out_val, curr->val, self->val_size);
|
|
return C_ERR_OK;
|
|
}
|
|
}
|
|
|
|
return C_ERR_NOTFOUND;
|
|
}
|
|
|
|
/**
|
|
* @brief 检查树中是否包含指定的 Key 键值
|
|
*/
|
|
bool c_BST_Contains(const c_BST_t* self, const void* key) {
|
|
if (!self || !key) return false;
|
|
c_BSTNode* curr = self->root;
|
|
while (curr != NULL) {
|
|
int cmp_res = self->cmp(key, curr->key, self->args);
|
|
if (cmp_res < 0) curr = curr->left;
|
|
else if (cmp_res > 0) curr = curr->right;
|
|
else return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief 内部递归插入/覆写辅助(基于二级指针代理,完美消除悬空控制流)
|
|
*/
|
|
static c_err_t c_BST_InternalPut(c_BST_t* self, c_BSTNode** node_ptr, const void* key, const void* val, bool* is_new_inserted) {
|
|
c_BSTNode* curr = *node_ptr;
|
|
|
|
// 递归基:如果当前插槽为空,在此物理位置开辟并挂载新节点
|
|
if (curr == NULL) {
|
|
c_BSTNode* new_node = (c_BSTNode*)c_Allocator_Alloc(&self->allocator, sizeof(c_BSTNode));
|
|
void* new_key = c_Allocator_Alloc(&self->allocator, self->key_size);
|
|
void* new_val = c_Allocator_Alloc(&self->allocator, self->val_size);
|
|
|
|
if (!new_node || !new_key || !new_val) {
|
|
if (new_node) c_Allocator_Free(&self->allocator, new_node);
|
|
if (new_key) c_Allocator_Free(&self->allocator, new_key);
|
|
if (new_val) c_Allocator_Free(&self->allocator, new_val);
|
|
return C_ERR_NOMEM;
|
|
}
|
|
|
|
memcpy(new_key, key, self->key_size);
|
|
memcpy(new_val, val, self->val_size);
|
|
new_node->key = new_key;
|
|
new_node->val = new_val;
|
|
new_node->left = NULL;
|
|
new_node->right = NULL;
|
|
|
|
*node_ptr = new_node; // 代理写入,父节点指针自动对齐
|
|
*is_new_inserted = true;
|
|
return C_ERR_OK;
|
|
}
|
|
|
|
int cmp_res = self->cmp(key, curr->key, self->args);
|
|
if (cmp_res < 0) {
|
|
return c_BST_InternalPut(self, &(curr->left), key, val, is_new_inserted);
|
|
} else if (cmp_res > 0) {
|
|
return c_BST_InternalPut(self, &(curr->right), key, val, is_new_inserted);
|
|
} else {
|
|
// 键已存在,执行覆写(Overwrite)语义
|
|
memcpy(curr->val, val, self->val_size);
|
|
*is_new_inserted = false;
|
|
return C_ERR_OK;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 存入键值对。若 Key 已存在则覆写更新;若不存在则开辟新节点维护树拓扑
|
|
*/
|
|
c_err_t c_BST_Put(c_BST_t* self, const void* key, const void* val) {
|
|
if (!self || !key || !val) return C_ERR_PARAM;
|
|
|
|
bool is_new = false;
|
|
c_err_t err = c_BST_InternalPut(self, &(self->root), key, val, &is_new);
|
|
if (err == C_ERR_OK && is_new) {
|
|
self->size++;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* @brief 内部辅助:寻找并剥离指定子树的绝对最小值节点(用于 Hibbard 删除替换)
|
|
*/
|
|
static c_BSTNode* c_BST_DeleteMin(c_BST_t* self, c_BSTNode** node_ptr) {
|
|
c_BSTNode* curr = *node_ptr;
|
|
if (curr->left == NULL) {
|
|
// 找到最小值,将右子树代理向上对接,将当前节点断开剥离并返回
|
|
*node_ptr = curr->right;
|
|
return curr;
|
|
}
|
|
return c_BST_DeleteMin(self, &(curr->left));
|
|
}
|
|
|
|
/**
|
|
* @brief 内部递归删除控制流(基于二级指针代理的 Hibbard 经典删除算法)
|
|
*/
|
|
static c_err_t c_BST_InternalDelete(c_BST_t* self, c_BSTNode** node_ptr, const void* key) {
|
|
c_BSTNode* curr = *node_ptr;
|
|
if (curr == NULL) {
|
|
return C_ERR_NOTFOUND; // 节点不存在
|
|
}
|
|
|
|
int cmp_res = self->cmp(key, curr->key, self->args);
|
|
if (cmp_res < 0) {
|
|
return c_BST_InternalDelete(self, &(curr->left), key);
|
|
} else if (cmp_res > 0) {
|
|
return c_BST_InternalDelete(self, &(curr->right), key);
|
|
} else {
|
|
// 精确命中当前要删除的节点 curr,开启 Hibbard 拆解合并
|
|
c_BSTNode* old_node = curr;
|
|
|
|
if (curr->right == NULL) {
|
|
// 情况 1:无右子树,直接将左子树整体顶替上来
|
|
*node_ptr = curr->left;
|
|
} else if (curr->left == NULL) {
|
|
// 情况 2:无左子树,直接将右子树整体顶替上来
|
|
*node_ptr = curr->right;
|
|
} else {
|
|
// 情况 3:左右子树均完好。寻找右子树的绝对最小值充当继承后继者 (Successor)
|
|
c_BSTNode* successor = c_BST_DeleteMin(self, &(curr->right));
|
|
|
|
// 后继者完美接管原节点的双向拓扑路由
|
|
successor->left = old_node->left;
|
|
successor->right = *node_ptr; // 此时 *node_ptr 已经是处理过 deleteMin 后的右子树根
|
|
|
|
*node_ptr = successor; // 代理顶替
|
|
}
|
|
|
|
// 释放被移出树的旧节点物理内存
|
|
c_Allocator_Free(&self->allocator, old_node->key);
|
|
c_Allocator_Free(&self->allocator, old_node->val);
|
|
c_Allocator_Free(&self->allocator, old_node);
|
|
return C_ERR_OK;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief 根据指定 Key 彻底从树中移出其关联的键值对节点
|
|
*/
|
|
c_err_t c_BST_Delete(c_BST_t* self, const void* key) {
|
|
if (!self || !key) return C_ERR_PARAM;
|
|
if (self->size == 0) return C_ERR_EMPTY;
|
|
|
|
c_err_t err = c_BST_InternalDelete(self, &(self->root), key);
|
|
if (err == C_ERR_OK) {
|
|
self->size--;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* @brief 内部递归反初始化解构辅助
|
|
*/
|
|
static void c_BST_InternalDeinit(c_Allocator_t* alloc, c_BSTNode* node) {
|
|
if (node == NULL) return;
|
|
|
|
// 递归后序遍历:先解构左右子树,再回收当前节点
|
|
c_BST_InternalDeinit(alloc, node->left);
|
|
c_BST_InternalDeinit(alloc, node->right);
|
|
|
|
c_Allocator_Free(alloc, node->key);
|
|
c_Allocator_Free(alloc, node->val);
|
|
c_Allocator_Free(alloc, node);
|
|
}
|
|
|
|
/**
|
|
* @brief 二叉搜索树反初始化彻底释放
|
|
*/
|
|
void c_BST_Destroy(c_BST_t* self) {
|
|
if (self && self->root) {
|
|
c_BST_InternalDeinit(&self->allocator, self->root);
|
|
self->root = NULL;
|
|
self->size = 0;
|
|
}
|
|
} |