二叉查找树的定义
二叉排序树 (Binary Sort Tree) 又称二叉查找树,它是一种对排序和查找都很有用的特殊二叉树。
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1) 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2) 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3) 它的左、 右子树也分别为二叉排序树。
二叉排序树是递归定义的。 由定义可以得出二叉排序树的一个重要性质:中序遍历一棵二叉
树时可以得到一个结点值递增的有序序列。
二叉查找树的实现
#include <stdio.h>
#include <stdlib.h>
#define true 1
#define false 0
#define ElemType int
#define KeyType int
/**
* 二叉排序树的结点结构定义
*/
typedef struct _BinaryNode
{
/* data */
ElemType data;
struct _BinaryNode *lchild;
struct _BinaryNode *rchild;
}BinaryNode,*BinaryTree;
/**
* @brief 二叉查找树查找算法
*
* @param[in] Node 当前查找的二叉查找树的结点
* @param[in] KeyData 待查找的数据
* @param[in] FatherNode 当前查找的二叉查找树的结点的父结点
* @param[out] FoundNode 如果找到,存放找到的结点;如果没找到,值为空。
* @param[out] FatherOfFoundNode 如果找到,存放找到的结点的父结点;如果没找到,存放最后查找的那个结点。
*
* @return int
* @retval 1 查找成功
* @retval 0 查找失败
*/
int SearchBST(BinaryTree Node,KeyType KeyData,BinaryTree FatherNode,BinaryTree *FoundNode,BinaryTree *FatherOfFoundNode)
{
/**
* 此函数是递归的,如果Node结点为空,说明查无可查,查找失败。
* 给函数的输出参数FatherOfFoundNode指向最后一个查找的结点。
*/
if(!Node)
{
*FatherOfFoundNode = FatherNode;
*FoundNode = NULL;
return false;
}
/**
* 此函数是递归的,如果Node结点的数据与查找的数据相同,说明已查到。
* 给函数的输出参数FoundNode指向查找到的结点,函数的输出参数FatherOfFoundNode指向查找结点的父结点。
*/
if(KeyData == Node->data)
{
*FoundNode = Node;
*FatherOfFoundNode = FatherNode;
return true;
}
/**
* 此函数是递归的,如果Node结点的数据比查找的数据大,说明待查找数据可能在Node结点的左子树中。查找左子树。
*/
else if(KeyData < Node->data)
{
return SearchBST(Node->lchild, KeyData, Node, FoundNode,FatherOfFoundNode);
}
/**
* 此函数是递归的,如果Node结点的数据比查找的数据小,说明待查找数据可能在Node结点的右子树中。查找右子树。
*/
else
{
return SearchBST(Node->rchild, KeyData, Node, FoundNode,FatherOfFoundNode);
}
}
/**
* @brief 二叉查找树查找最小值算法
*
* @param[in] BinaryNode 当前查找的二叉查找树的结点
*
* @return BinaryTree
* @retval !NULL 查找到的结点指针
* @retval NULL 查找失败
*/
BinaryTree FindBSTMin(BinaryTree BinaryNode)
{
if(BinaryNode == NULL)
{
return NULL;
}
else
{
if(BinaryNode->lchild == NULL)
{
return BinaryNode;
}
else
{
return FindBSTMin(BinaryNode->lchild);
}
}
}
/**
* @brief 二叉查找树查找最大值算法
*
* @param[in] BinaryNode 当前查找的二叉查找树的结点
*
* @return BinaryTree
* @retval !NULL 查找到的结点指针
* @retval NULL 查找失败
*/
BinaryTree FindBSTMax(BinaryTree BinaryNode)
{
if(BinaryNode == NULL)
{
return NULL;
}
else
{
if(BinaryNode->rchild == NULL)
{
return BinaryNode;
}
else
{
return FindBSTMax(BinaryNode->rchild);
}
}
}
/**
* @brief 二叉查找树查找算法
*
* @param[in] Tree 指向待查找的二叉查找树的结点
* @param[in] Data 待查找的数据
*
* @return int
* @retval 1 插入成功
* @retval 0 插入失败
*/
int InsertBST(BinaryTree *Tree,ElemType Data)
{
BinaryTree FoundNode = NULL;
BinaryTree FatherOfFoundNode = NULL;
/**
* 插入之前先查找,查找失败就做插入操作
*/
if(!SearchBST(*Tree,Data,NULL,&FoundNode,&FatherOfFoundNode))
{
/**
* 初始化插入结点
*/
BinaryTree InsertNode = (BinaryTree)malloc(sizeof(BinaryNode));
InsertNode->data = Data;
InsertNode->lchild = NULL;
InsertNode->rchild = NULL;
/**
* 最后一次查找的结点为空,说明整个二叉排序树是空树,此时插入的结点是根结点
*/
if(!FatherOfFoundNode)
{
*Tree = InsertNode;
}
else if(Data < FatherOfFoundNode->data)
{
FatherOfFoundNode->lchild = InsertNode;
}
else
{
FatherOfFoundNode->rchild = InsertNode;
}
return true;
}
/**
* 插入之前先查找,查找成功返回失败
*/
else
{
return false;
}
}
/**
* @brief 二叉查找树删除算法
*
* @param[in] DeleteNode 指向待查找的二叉查找树的结点的指针
* @param[in] FatherOfDeleteNode 指向待查找的二叉查找树结点的父结点的指针
*
* @return int
* @retval 1 插入成功
* @retval 0 插入失败
*/
int DeleteNode(BinaryTree *DeleteNode,BinaryTree *FatherOfDeleteNode)
{
BinaryTree FatherOfPrecursorForDeleteNode = NULL;//待删除结点的前驱结点的父亲
BinaryTree PrecursorForDeleteNode = NULL;//待删除结点的前驱结点
/**
* 情况1:待删除结点DeleteNode本身就是叶子结点
*/
if (!(*DeleteNode)->lchild && !(*DeleteNode)->rchild) {
/**
* 情况1.1:待删除结点DeleteNode本身就是叶子结点,且是为他父亲的左孩子,将父结点的左孩子结点指向空
*/
if((*FatherOfDeleteNode)->lchild == *DeleteNode)
{
(*FatherOfDeleteNode)->lchild = NULL;
}
/**
* 情况1.2:待删除结点DeleteNode本身就是叶子结点,且是为他父亲的右孩子,将父结点的右孩子结点指向空
*/
else
{
(*FatherOfDeleteNode)->rchild = NULL;
}
/**
* 释放待删除结点的内存
*/
free(*DeleteNode);
*DeleteNode = NULL;
}
/**
* 情况2:右子树为空,左子树不为空,只需用待删除结点DeleteNode的父结点指向待删除结点DeleteNode的左子树即可;
* 注意区分待删除结点是他父结点的左孩子还是右孩子
*/
else if(!(*DeleteNode)->rchild)
{
if((*FatherOfDeleteNode)->lchild == *DeleteNode)
{
(*FatherOfDeleteNode)->lchild = (*DeleteNode)->lchild;
}
else
{
(*FatherOfDeleteNode)->rchild = (*DeleteNode)->lchild;
}
free(*DeleteNode);
*DeleteNode = NULL;
}
/**
* 情况3:左子树为空,右子树不为空,只需用待删除结点DeleteNode的父结点指向待删除结点DeleteNode的右子树即可;
* 注意区分待删除结点是他父结点的左孩子还是右孩子
*/
else if(!(*DeleteNode)->lchild)
{
if((*FatherOfDeleteNode)->rchild == *DeleteNode)
{
(*FatherOfDeleteNode)->rchild = (*DeleteNode)->rchild;
}
else
{
(*FatherOfDeleteNode)->lchild = (*DeleteNode)->rchild;
}
free(*DeleteNode);
*DeleteNode = NULL;
}
else
{
/**
* 情况4:左右子树均不为空,用待删除结点的前驱结点的data替换待删除结点的data,删除待删除结点的前驱结点
*/
FatherOfPrecursorForDeleteNode = *DeleteNode;//待删除结点的前驱结点的父亲初始化为待删除结点,即默认待删除结点的前驱结点为其左子树
PrecursorForDeleteNode = (*DeleteNode)->lchild;//待删除结点的前驱结点初始化,默认待删除结点的前驱结点为待删除结点的左子树
//遍历,找到结点 DeleteNode 的直接前驱
while (PrecursorForDeleteNode->rchild)
{
FatherOfPrecursorForDeleteNode = PrecursorForDeleteNode;
PrecursorForDeleteNode = PrecursorForDeleteNode->rchild;
}
//循环之后PrecursorForDeleteNode即为待删除结点的前驱结点,FatherOfPrecursorForDeleteNode即为待删除结点的前驱结点的父亲
//直接改变结点 DeleteNode 的值
(*DeleteNode)->data = PrecursorForDeleteNode->data;
//此种情况是待删除结点 DeleteNode 的左子树没有右子树,这时待删除结点的前驱结点为其左子树,待删除结点的前驱结点的父亲为待删除结点本身。
if (FatherOfPrecursorForDeleteNode == *DeleteNode) {
//直接将待删除结点的前驱结点的左子树上移即可
(*DeleteNode)->lchild = PrecursorForDeleteNode->lchild;
}
else {
//此时待删除结点的前驱结点不是他的左孩子,那么找到的待删除结点的前驱结点有如下特征:只存在有左孩子无右孩子或左右孩子均无的这两种情况。
//改待删除结点的前驱结点的父亲FatherOfPrecursorForDeleteNode 指向待删除结点的前驱结点PrecursorForDeleteNode的左孩子结点
//此种情况已经考虑待删除结点的前驱结点没有左孩子。
FatherOfPrecursorForDeleteNode->rchild = PrecursorForDeleteNode->lchild;
}
//删除直接前驱结点
free(PrecursorForDeleteNode);
PrecursorForDeleteNode = NULL;
}
return true;
}
/**
* @brief 二叉查找树删除整颗树算法
*
* @param[in] BinaryNode 待删除的二叉查找树的根结点
*
* @return BinaryTree
* @retval NULL 删除成功
*/
BinaryTree DeleteBST(BinaryTree BinaryNode)
{
if(BinaryNode != NULL)
{
DeleteBST(BinaryNode->lchild);
DeleteBST(BinaryNode->rchild);
free(BinaryNode);
}
return NULL;
}
//测试案例
int main(void)
{
int i;
//int Squence[5] = {3, 4, 2, 5, 9};
int Squence2[] = {8, 4, 10, 2, 6, 12, 5};
BinaryTree Tree = NULL;
for (i = 0; i < sizeof(Squence2)/sizeof(Squence2[0]);++i)
{
int ReturnCode = InsertBST(&Tree, Squence2[i]);
printf("insert %d result %d\r\n", Squence2[i], ReturnCode);
}
BinaryTree FoundNode = NULL;
BinaryTree FatherOfFoundNode = NULL;
if(SearchBST(Tree,8,NULL,&FoundNode,&FatherOfFoundNode))
{
DeleteNode(&FoundNode,&FatherOfFoundNode);
}
}