实现二叉查找树基本操作
在这篇博客我们已经记录了二叉查找树插入查找删除的思路,使用递归很容易实现,因为树的定义都是递归实现的,所以相对于递归,使用迭代完成上述操作就比较复杂了.
插入的实现
需要手动记录该节点的父节点,因为要将父节点的子树指向新节点
插入的节点是该父节点的左子树还是右子树,通过比较大小就可以确定
void SearchTreeInsert_ByLooP(SearchTreeNode* root, SearchTreeType key)
{
SearchTreeNode* pre_node = root;
SearchTreeNode* node = root;
for(node = root; node != NULL; )
{
if(node->key > key)
{
pre_node = node;
node = node->rchild;
}
else if(node->key < key)
{
pre_node = node;
node = node->lchild;
}
else if(node->key == key)
{
break;
}
}
//为空 插入新元素
if(node == NULL)
{
node = (SearchTreeNode*)malloc(sizeof(SearchTreeNode));
node->key = key;
node->lchild = NULL;
node->rchild = NULL;
//父节点的左边或者右边插入节点
if(pre_node->key < node->key)
{
pre_node->rchild = node;
}
else
{
pre_node->lchild = node;
}
}
}
查找
查找就没什么了,和递归一样,比较大小,结束循环时node = NULL 就表示查找未命中
删除
递归版本的删除就很复杂了,对于迭代,就更难了.
不过思路还是记录两个节点,pre_node (父节点) node(当前节点),
需要根据大小比较 node是pre_node 的左子树还是右子树
然后分四类情况讨论,和递归一样
这里是删除四种情况的图示
void _SearchTreeRemove_ByLoop(SearchTreeNode** proot,SearchTreeType key)
{
if( proot == NULL )
return;
if( *proot == NULL )
return;
SearchTreeNode* root = *proot;
SearchTreeNode* pre_root = NULL;
//查找需要删除的节点
while(root)
{
if(root->key > key)
{
pre_root = root;
root = root->lchild;
}
else if(root->key < key)
{
pre_root = root;
root = root->rchild;
}
else if(root->key == key)
{
break;
}
}
//没找到 需要删除的节点
if(root == NULL)
{
return;
}
// 如果删除的节点是根节点
if(root == *proot)
{
free(*proot);
*proot = NULL;
return;
}
//删除节点 左右子树都为空 的情况
if(root->lchild == NULL && root->rchild == NULL)
{
// 判断 当前节点 是 其父节点的左节点还是右节点
if(pre_root->key > root->key)
{
pre_root->lchild = NULL;
}
else
{
pre_root->rchild = NULL;
}
free(root);
root = NULL;
}
//当前节点右空 左不空的情况
else if(root->lchild != NULL && root->rchild == NULL)
{
// 判断 当前节点 是 其父节点的左节点还是右节点
if(pre_root->key > root->key)
{
pre_root->lchild = root->lchild;
}
else
{
pre_root->rchild = root->lchild;
}
free(root);
root = NULL;
}
//上一个的镜像
else if(root->rchild != NULL && root->lchild == NULL)
{
if(pre_root->key > root->key)
{
pre_root->lchild = root->rchild;
}
else
{
pre_root->rchild = root->rchild;
}
free(root);
root = NULL;
}
else if(root->rchild != NULL && root->lchild != NULL)
{
//在左子树中找最大的吧, 使用赋值法删除节点
SearchTreeNode* max = root->lchild;
SearchTreeNode* pre_max = NULL;
while(max->rchild)
{
pre_max = max;
max = max->rchild;
}
root->key = max->key;
//左子树是根节点
if(pre_max == NULL)
{
free(root->lchild);
root->lchild = NULL;
}
else
{
//左子树中最大的 ,不用比值
free(pre_max->rchild);
pre_max->rchild = NULL;
}
}
}