搜索结构之K模型与KV模型
搜索结构
在日常的应用中,我们经常需要在海量数据中进行搜索某一数据。根据目前掌握的方法我们可以选择树形结构类似搜索树,平衡树,红黑树等搜索结构。以及哈希这种映射结构。两类结构各有优劣在这里不进行比较,详情请看以前博客。
K与YV模型
搜索结构中同时也分为不同的应用场景,比如单体映射,关键码即为需要搜索到的值,还有双映射,在关键码位置还储存一个数据。第一种叫做K模型。故名思意只有KEY作为关键码,后一种叫做KV模型,除了一个KEY用做映射以外还有一个VALUE数据,举例说明,当我们需要检查一个单词是否拼写正确时,我们需要先将所有单词存储起来然后进行搜索,这种就叫做K模型。当我们需要做一个翻译字典时,首先我们需要将英文作为K作为关键码存储起来,一同存储的还有他的翻译VALUE,这样当我们找到KEY时,同时也可以找到翻译。
接口设计
这里用搜索树与哈希表实现K与KV模型的字典举例。
搜索树实现
- 定义搜索树结构体:
typedef struct BSTreeNode
{
struct BSTreeNode* _left;
struct BSTreeNode* _right;
KeyType _key;
ValueType _value;
}BSTreeNode;
- 创立一个新节点:这里我们需要给出新节点的K与V
BSTreeNode* BuyBSTreeNode(KeyType key, ValueType value)
{
BSTreeNode* tree = (BSTreeNode*)malloc(sizeof(BSTreeNode));
tree->_key = key;
tree->_value = value;
tree->_left = NULL;
tree->_right = NULL;
return tree;
}
- 插入新节点:这里我们利用递归实现,首先我们进行查找,如果节点KEY已经存在那么插入失败,如果不存在我们与根节点的KEY进行比较从而决定递归进左子树还是右子树。当遇到空时插入即可。
int BSTreeInsertR(BSTreeNode** tree, KeyType key, ValueType value)
{
if ((*tree) == NULL)
{
*tree = BuyBSTreeNode(key,value);
return 1;
}
else if ((*tree)->_key == key)
{
return 0;//插入失败
}
else
{
if ((*tree)->_key < key)
{
return BSTreeInsertR(&(*tree)->_right, key,value);
}
else
{
return BSTreeInsertR(&(*tree)->_left, key,value);
}
}
}
- 寻找节点:这个接口可以直接帮我们找到KEY对应的VALUE,依旧是用递归实现,与根节点进行对比从而决定递归左子树还是右子树,当KEY等于根节点时返回节点,找不到时返回空指针即可。
BSTreeNode* BSTreeFindR(BSTreeNode* tree, KeyType key)
{
if (tree == NULL)
{
return NULL;
}
if (tree->_key == key)
{
return tree;//找到了
}
else
{
if (tree->_key < key)
{
return BSTreeFindR(tree->_right, key);
}
else
{
return BSTreeFindR(tree->_left, key);
}
}
}
- 删除节点:利用递归实现,这里要定义一个prev指针指向删除节点的上一个节点,同时又分为删除节点左子树是否为空,右子树是否为空与是否都不为空三种情况,具体方法参考搜索树博客删除部分。
int BSTreeRemoveR(BSTreeNode** tree, KeyType key)
{
if ((*tree)->_key < key)
{
return BSTreeRemoveR(&(*tree)->_right, key);
}
else if ((*tree)->_key > key)
{
return BSTreeRemoveR(&(*tree)->_left,key);
}
else
{
if ((*tree)->_left == NULL)
{
BSTreeNode* cur = *tree;
*tree = (*tree)->_right;
free(cur);
return 1;
}
else if ((*tree)->_right == NULL)
{
BSTreeNode* cur = *tree;
*tree = (*tree)->_left;
free(cur);
return 1;
}
else
{
BSTreeNode* parents = *tree;
BSTreeNode* ptr = parents->_right;
while (ptr->_left)
{
parents = ptr;
ptr = ptr->_left;
}
if (parents == *tree)
{
(*tree)->_key = ptr->_key;
parents->_right = ptr->_right;
free(ptr);
return 1;
}
else
{
(*tree)->_key = ptr->_key;
parents->_left = ptr->_right;
free(ptr);
return 1;
}
}
}
}
哈希实现
字符串哈希算法
故名思意,字符串哈希算法就是将字符串通过某种方式转换成可以映射的整数值,而且要尽量避免哈希冲突。所以这个算法的核心设计点就在于如何让字符串转换成整数的情况下避免哈希冲突,本文给出一种解决方式如下:
size_t BKDRHsah(const char* str)
{
unsigned int seed = 131;
unsigned int hash = 0;
while (*str)
{
hash = hash * seed + (*str++);
}
return hash & 0x7FFFFFFF;
}
更多的可以参考笔者推荐博客“字符串哈希算法详解”。