二叉搜索树的定义
二叉搜索树,也称有序二叉树,排序二叉树,是指一棵空树或者具有下列性质的二叉树:
若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
任意节点的左、右子树也分别为二叉查找树。
没有键值相等的节点。
二叉树搜索树的基本操作
二叉树搜索树插入(递归与迭代)
二叉树搜索树查找(递归与迭代)
二叉树搜索树删除(递归与迭代)
二叉树搜索树销毁
搜索二叉树的定义及初始化
typedef struct SearchTreeNode
{
SearchTreeNode* rchild;
SearchTreeNode* lchile;
SearchTreeType data;
}SearchTreeNode;
//因为会修改根节点的指向,所以使用二级指针
void SearchTreeInit(SearchTreeNode** root)
{
if(root==NULL)
{
return ;
}
*root=NULL;
return ;
}
二叉树搜索树创建新节点与
SearchTreeNode* SearchTreeCreateNode(SearchTreeType value)
{
SearchTreeNode* newnode=(SearchTreeNode*)malloc(sizeof(SearchTreeNode));
newnode->data=value;
newnode->lchild=NULL;
newnode->rchild=NULL;
return newnode;
}
搜索二叉树销毁节点
void DelNodeSearchTree(SearchTreeNode* value)
{
free(value);
return ;
}
二叉搜索数插入新节点
//递归版本
void SearchTreeInsert(SearchTreeNode** root, SearchTreeType value)
{
if(root==NULL)
{
return ;
}
if(*root==NULL)
{
//空树,直接插入
SearchTreeNode* newnode=SearchTreeCreateNode(value);
*root=newnode;
return ;
}
//对于非空,采用递归插入
SearchTreeNode* cur=*root;
if(value<cur->data)
{
//递归插入左子树
SearchTreeInsert(&cur->lchild,value);
}
if(value>cur->data)
{
//递归插入右子树
SearchTreeInsert(&cur->rchild,value);
}
else
{
//关于等于的处理有很多,以下可以采用一种约定
//我们约定这个二查搜索树不能重复
//一旦重复,直接返回,插入失败
return;
}
return ;
}
//非递归版本
void SearchTreeInsert(SearchTreeNode** root,SearchTreeType value)
{
if(root==NULL)
{
return ;
}
//空树
if(*root==NULL)
{
*root=SearchTreeCreateNode(value);
return ;
}
//对于非空树,要找到先找到插入的位置
SearchTreeNode* cur=*root;
//把插入元素的父节点记录下来
SearchTreeNode* pre=NULL;
//此循环只是为了找到插入位置
while(1)
{
if(cur==NULL)
{
//找到插入位置,跳出循环
break;
}
if(value<cur->data)
{
pre=cur;
cur=cur->lchild;
}
else if(value>cur->data)
{
pre=cur;
cur=cur->rchild;
}
else
{
//发现有一个重复元素,则插入失败
return ;
}
}
SearchTreeNode* new_node=SearchTreeCreateNode(value);
//pre一定不为空,如果pre为空
//意味着前面的while循环一进来就命中了:cur==NULL
//然而cur为空,在最开始就排除了
if(new_node->data<pre->data)
{
pre->lchild=new_node;
}
else if(new_node->data>pre->data)
{
pre->rchild=new_node;
}
return;
}
二叉搜索数的查找
SearchTreeNode* SearchTreeFind(SearchTreeNode* root, SearchTreeType to_find)
{
if(root==NULL)
{
return ;
}
if(to_find<root->data)
{
//递归查找左子树
return SearchTreeFind(root->lchild,to_find);
}
else if(to_find>root->data)
{
return SearchTreeFind(root->rchild,to_find);
}
return root;
}
//非递归
SearchTreeNode* SearchTreeFind(SearchTreeNode* root,SearchTreeType value)
{
if(root==NULL)
{
return NULL ;
}
SearchTreeNode* cur=root;
while(cur!=NULL)
{
if(value<cur->data)
{
cur=cur->lchild;
}
else if(value>cur->data)
{
cur=cur->rchild;
}
else
{
break;
}
}
return cur;
}
二叉搜索数的删除
(分三种情况进行处理):
1.p为叶子节点,直接删除该节点,再修改其父节点的指针(注意分是根节点和不是根节点),如图a。
2.p为单支节点(即只有左子树或右子树)。让p的子树与p的父亲节点相连,删除p即可;(注意分是根节点和不是根节点);如图b。
3.p的左子树和右子树均不空。找到p的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y的右子树的父亲节点,并用y的值代替p的值;或者方法二是找到p的前驱x,x一定没有右子树,所以可以删除x,并让x的父亲节点成为y的左子树的父亲节点。如图c。
//递归版本
void SearchTreeRemove(SearchTreeNode** root, SearchTreeType value)
{
if(root==NULL)
{
//非法输入
return ;
}
if(*root==NULL)
{
//空树
return ;
}
//1.找到to_remove所在的位置
SearchTreeNode* cur=*root;
if(value<cur->data)
{
//递归删除左子树
SearchTreeRemove(&cur->lchild,value);
return ;
}
else if(value>cur->data)
{
//递归删除右子树
SearchTreeRemove(&cur->rchild,value);
return ;
}
//找到要删除元素,分情况讨论
else
{
SearchTreeNode* to_remove_node=cur;
//要删除的元素没有子树
if(cur->lchild==NULL&&cur->rchild==NULL)
{
*root=NULL;
DelNodeSearchTree(to_remove_node);
return ;
}
//要删除的元素只有左子树
else if(cur->lchild!=NULL&&cur->rchild==NULL)
{
//把当前节点的左孩子托付给该点的父节点
*root=to_remove_node->lchild;
DelNodeSearchTree(to_remove_node);
return ;
}
else if(cur->lchild==NULL&&cur->rchild!=NULL)
{
//把当前节点的右孩子托付给该点的父节点
*root=to_remove_node->rchild;
DelNodeSearchTree(to_remove_node);
return ;
}
//要删除的元素既有左子树,又有右子树
{
//找到右子树中的最小节点
SearchTreeNode* min=to_remove_node->rchild;
while(min->lchild!=NULL)
{
min=min->lchild;
//循环结束,找到了最小节点
}
//将最小值覆盖要删除当前节点值
to_remove_node->data=min->data;
//尝试递归删除min->data
SearchTreeRemove(&to_remove_node->rchild,min->data);
return ;
}
}
return ;
}
//非递归版本
void SearchTreeRemove(SearchTreeNode** root,SearchTreeType value)
{
if(root==NULL)
{
return ;
}
if(*root==NULL)
{
return ;
}
//先找到要删除的节点是谁
SearchTreeNode* to_remove_node=*root;
//找到删除节点的父节点
SearchTreeNode* pre=NULL;
while(1)
{
if(to_remove_node==NULL)
{
//没找到要删除的元素,直接返回
return ;
}
//在左子树中查找
if(value<to_remove_node->data)
{
pre=to_remove_node;
to_remove_node=to_remove_node->lchild;
}
//在右子树上查找
else if(value>to_remove_node->data)
{
pre=to_remove_node;
to_remove_node=to_remove_node->rchild;
}
else
{
//找到了
break;
}
}
//找到了,分四种情况讨论
//没有子树
if(to_remove_node->lchild==NULL&&to_remove_node->rchild==NULL)
{
//此处先判定删除节点是否是根节点
if(to_remove_node==*root)
{
//删除节点是根节点
*root=NULL;
}
else
{
//删除节点不是根节点
if(to_remove_node->data<pre->data)
{
pre->lchild=NULL;
}
else
{
pre->rchild=NULL;
}
}
//统一释放内存
DelNodeSearchTree(to_remove_node);
return ;
}
//只有左子树
else if(to_remove_node->lchild!=NULL&&to_remove_node->rchild==NULL)
{
//删除节点是根节点
if(*root=to_remove_node)
{
*root=to_remove_node;
}
//不是根节点
else
{
//要删除节点是父节点的左子树
if(to_remove_node->data<pre->data)
{
//把当前节点的左子树托付给父节点的左子树(该点只有左子树,没有右子树)
pre->lchild=to_remove_node->lchild;
}
//要删除节点是父节点的左子树
if(to_remove_node->data<pre->data)
{
//把当前节点的左子树托付给父节点的右子树
pre->rchild=to_remove_node->lchild;
}
}
DelNodeSearchTree(to_remove_node);
return ;
}
//只有右子树
else if(to_remove_node->lchild==NULL&&to_remove_node->rchild!=NULL)
{
//要删除元素是根节点
if(*root==to_remove_node)
{
*root=NULL;
}
//要删除元素不是根节点(只有右子树)
else
{
//要删除元素是父节点的左子树,则把要删除元素的右子树托付给父节点的左孩子
if(to_remove_node->data<pre->data)
{
pre->lchild=to_remove_node->rchild;
}
//要删除元素是父节点的右子树,则把要删除元素的右子树托付给父节点的右孩子
if(to_remove_node->data>pre->data)
{
pre->rchild=to_remove_node->rchild;
}
}
DelNodeSearchTree(to_remove_node);
return ;
}
//既有左子树又有右子树
else
{
SearchTreeNode* min=to_remove_node->rchild;
SearchTreeNode* min_pre=to_remove_node;
while(min->lchild!=NULL)
{
min_pre=min;
min=min->lchild;
}
//循环结束,min就指向了to_remove_node右子树的最小值
to_remove_node->data=min->data;
if(min->data<min_pre->data)
{
//min 是min_pre的左子树
//min一定没有左子树
min_pre->lchild=min->rchild;
}
else
{
//通常情况下mins是min_pre的左子树
//但是c初始情况下除外
min_pre->rchild=min->rchild;
}
DelNodeSearchTree(min);
return ;
}
return ;
}
搜索二叉树的销毁
void SearchTreeDestory(SearchTreeNode** root)
{
if(root==NULL)
{
return ;
}
if(*root==NULL)
{
return ;
}
SearchTreeNode* cur=*root;
SearchTreeDestory(&cur->lchild);
SearchTreeDestory(&cur->rchild);
DelNodeSearchTree(cur);
//防止变成野指针
*root=NULL;
return ;
}