定义
二叉查找树是一种特殊的二叉树,它不仅是一颗二叉树,还满足如下性质
对于任何非叶子节点,他的左节点都小于它本身,而右节点都大于其本身.
它的左右子树也分别而二叉搜索树
一般情况下,在这么一棵树中进行查找,它的时间复杂度是
但是在最坏情况下,一棵树会退化成单链表,那么此时的查找时间复杂度就是
实现
头文件
#pragma once
#include<stdio.h>
typedef char SearchTreeType;
typedef struct SearchTreeNode
{
SearchTreeType key;
struct SearchTreeNode* lchild;
struct SearchTreeNode* rchild;
}SearchTreeNode;
void SearchTreeInit(SearchTreeNode** root,SearchTreeType key);
void SearchTreeInsert(SearchTreeNode** root, SearchTreeType key);
SearchTreeNode* SearchTreeFind(SearchTreeNode** root, SearchTreeType to_find);
SearchTreeNode* _SearchTreeRemove(SearchTreeNode* root, SearchTreeType to_delete);
插入的实现
插入肯定会插入在叶子节点,
我们比较将要插入的节点和当前节点的大小关系,
如果大于当前节点,就需要在它的右子树寻找合适的节点插入
如果小于当前节点,就要在它的左子树寻找何时的节点插入
void SearchTreeInsert(SearchTreeNode** root, SearchTreeType key)
{
if(root == NULL)
return;
if(*root == NULL)
{
SearchTreeInit(root,key);
}
//递归插入
_SearchTreeInsert_R(*root,key);
}
SearchTreeNode* _SearchTreeInsert_R(SearchTreeNode* root, SearchTreeType key)
{
if(root == NULL)
{
root = (SearchTreeNode*)malloc(sizeof(SearchTreeNode));
root->key = key;
root->rchild = NULL;
root->rchild = NULL;
}
if(key > root->key)
{
root->rchild = _SearchTreeInsert_R(root->rchild,key);
}
else if(key < root->key)
{
root->lchild = _SearchTreeInsert_R(root->lchild,key);
}
else if( key == root->key )
{
return root;
}
return root;
}
查找的实现
依然是一个比较的过程,查找节点比当前节点大,就在当前节点的右子树中继续查找
查找节点比当前节点小,就在其左子树进行查找
如果遇到了NULL,就表示查找失败.
代码很简单就不一一列举了.
删除的实现
删除就比较复杂了,因为在删除后还要保证这棵树是一个二叉查找树.
这里要分情况讨论
删除的是叶子节点
例如我们要删除的是3 ,那么我们就应该找到3的父节点5,将5的左子树置空即可
删除的节点的左子树为空
例如我们要删除的是3 ,那么我们就应该找到3的父节点5,将5的左子树指向 3的右子树,然后释放该节点
删除的节点右子树为空
同上一种情况,将找到3的父节点5,将5的左子树指向 3的左子树,然后释放该节点
扫描二维码关注公众号,回复:
1630814 查看本文章
删除节点左右子树都非空
这里我们有两种可能的方案
1. 在3的左子树中找到最大的节点(2.5) 将2.5和3调换位置,然后将置换后的3删除
2. 在3的右子树中找到最小节点(3.5),将2.5和3调换位置,然后将置换后的3删除
我们只要按这4种情况不重不漏的分析下去,代码就很好写了
SearchTreeNode* _SearchTreeRemove(SearchTreeNode* root, SearchTreeType to_delete)
{
if(root == NULL)
return NULL;
if(root->key > to_delete)
{
root->lchild = _SearchTreeRemove(root->lchild,to_delete);
}
if(root->key < to_delete)
{
root->rchild = _SearchTreeRemove(root->rchild,to_delete);
}
if(root->key == to_delete)
{
// root 是叶子节点
if(root->lchild == NULL && root->rchild == NULL)
{
free(root);
root = NULL;
return NULL;
}
// root 非叶子节点 而且左子树为空,和右子树中最小元素交换,后删除找到的节点
else if(root->lchild == NULL && root->rchild != NULL)
{
SearchTreeNode* to_return = root->rchild;
free(root);
root = NULL;
return to_return;
}
// root 非叶子节点,右子树为空,和左子树中最大元素交换,后删除找到的节
else if(root->rchild == NULL && root->lchild != NULL)
{
SearchTreeNode* to_return = root->lchild;
free(root);
root = NULL;
return to_return;
}
// root 非叶子节点, 左子树中最大值和右子树中最大值 二选一交换 后删除找到的节
else if(root->lchild != NULL && root->rchild != NULL)
{
//采用赋值法
//在左子树取最大值
SearchTreeNode* max = root->lchild;
SearchTreeNode* max_parent = root->lchild;
while(max->rchild)
{
max_parent = max;
max = max->rchild;
}
root->key = max->key;
//左子树是叶子节点(特殊情况)
if(max_parent == max)
{
free(max);
max = NULL;
root->lchild = NULL;
}
else
{
//不用判断将左子树的最大值至为空
free(max_parent->rchild);
max_parent->rchild = NULL;
}
return root;
}
}
return root;
}