创建二叉搜索树,实现插入、查找和删除等函数
1. 需要掌握的知识
二叉搜索树的基本特性
2. 代码框架(重点)
2.1 采用的数据结构
结构体数组
typedef int ElementType; //通过typedef增加灵活性
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
ElementType Data;
BinTree Left;
BinTree Right;
};
2.2 各分支函数
- Insert()函数,用于建树,向树中插入一个树节点:分树空和树非空两种情况,递归调用即可,属于基本功
21.10.8 疑问:插入时,不用考虑二叉搜索树被破坏的情况吗?比如说,持续插入越来越小的数,这种插入方式难道不会导致树向一边倾斜吗? 自己晕头了,文中要求的是BST Binary Search Tree 二插搜索树的插入,并不是AVL 平衡二叉树。AVL才要求:左右两个子树的高度差的绝对值不超过1,并且左右两个子树也是平衡二叉树
BinTree Insert( BinTree BST, ElementType X )
{
if(!BST)
{
BST=(BinTree)malloc(sizeof(struct TNode));
BST->Data=X;
BST->Left=BST->Right=NULL;
}
else
{
if(X>BST->Data)
BST->Right=Insert(BST->Right,X);
else if(X<BST->Data)
BST->Left=Insert(BST->Left,X);
}
return BST;
}
- 查找最大值 和 最小值 : BST 最左侧的结点为最小值,最右侧的结点为最大值。注意,别遗漏树为空的情况
Position FindMin( BinTree BST )
{
if(!BST) return NULL; //树为空时
while(BST->Left)
BST=BST->Left;
return BST;
}
Position FindMax( BinTree BST )
{
if(!BST) return NULL;
while(BST->Right)
BST=BST->Right;
return BST;
}
- Find( ) 查找函数:根据BST左小右大的特性实现即可,使用递归时,别遗漏返回条件
Position Find( BinTree BST, ElementType X )
{
if(!BST) return NULL;
if(X==BST->Data)
return BST;
else if(X>BST->Data)
return Find(BST->Right,X);
else
return Find(BST->Left,X);
}
- Delete( ) 核心函数,挺锻炼人的逻辑思维能力。我开始一直受困于如何找到删除节点的父亲结点,最后发现不依赖父结点也能正常’删除’。
4.1 首先需要明确,删除存在三种可能:(1)删除结点是叶结点 (2)删除结点有一个子树 (3)删除结点有两个子树
4.2 对于(1)删除结点是叶结点,删除结点的父结点指向NULL即可;对于(2),父结点指向删除结点的子树即可;对于(3),稍微复杂些,根据BST特性,挑选左子树的最大值结点 或 右子树的最小值结点 替换删除结点,然后删除左子树或右子树上的替换结点
4.3 不用找到删除结点的父结点,从删除结点自身入手
4.4 别遗漏树空的情况
2021.10.8:全靠过去的自己为自己续命,总结的确实挺好的(手动咧嘴笑)
BinTree Delete( BinTree BST, ElementType X ) //core
{
if(!BST)
{
printf("Not Found\n");
return NULL;
}
BinTree tmp;
//通过if语句锁定查找的三种情况:大 小 相等
if(X>BST->Data) BST->Right=Delete(BST->Right,X);
else if(X<BST->Data) BST->Left=Delete(BST->Left,X);
else //找到了,准备删除,分三种情况考虑
{
if(BST->Left && BST->Right) //删除结点存在两个子树
{
tmp=FindMin(BST->Right) ;
BST->Data=tmp->Data; //替换掉结点值,而不用修改指针指向
BST->Right=Delete(BST->Right,tmp->Data); //将替换的结点删除即可
}
else
{
tmp=BST;
if(!BST->Left) BST=BST->Right; //删除结点右子树为空或非空:此时也不用考虑删除结点的父结点,改变删除结点自身即可
else if(!BST->Right) BST=BST->Left;//删除结点左子树为空或非空
free(tmp);
}
}
return BST;
}