二分搜索树的寻找、插入与删除
节点定义
struct TNode { /* 树结点定义 */
ElementType Data; /* 结点数据 */
TNode* Left; /* 指向左子树 */
TNode* Right; /* 指向右子树 */
};
寻找
- 将key值与当前节点比较,若key较小则前往左子树寻找;否则前往右子树寻找(重复此步骤)
- 当key值与当前节点相等时,返回当前节点地址
find
// 返回目标节点地址,实际上传入的也是一个节点的地址
TNode* find(ElementType key, TNode* root) {
if (!root)
return NULL;
while (root) {
if (key == root->Data)
return root;
else if (key < root->Data)
root = root->Left;
else
root = root->Right;
}
return NULL;
}
findMax
TNode* findMax(TNode* root) {
if (!root)
return NULL;
while (root){
root = root->Right;
}
return root;
}
findMin
TNode* findMin(TNode* root) {
if (!root)
return NULL;
while (root) {
root = root->Left;
}
return root;
}
插入
- 将key值与当前节点比较,若key较小则前往左子树寻找插入位置;否则前往右子树寻找插入位置(重复此步骤)
- 直到当前节点为空,插入即可
应当注意的是,这里如果采用递归实现插入函数,我们最好将函数的宏观语义定义为对以root为根的树插入新节点,并返回root的地址。
// 递归形式
// 返回新的根节点地址(递归形式的插入需要这样处理)
TNode* insert(ElementType key, TNode* root) {
if (!root) {
root = (TNode*)malloc(sizeof(struct TNode));
root->Data = key;
root->Left = NULL;
root->Right = NULL;
return root;
}
if (key > root->Data)
root->Right = insert(key, root->Right);
else if (key < root->Data)
root->Left = insert(key, root->Left);
return root;
}
删除
对于删除,本文对待删除节点的情况作出如下讨论:
- 待删除节点不存在
- 待删除节点是叶子节点
- 待删除节点有一个子节点
- 待删除节点有左右子树
当待删除节点是叶子节点时,应当将其父亲节点指向其的指针改为NULL;当待删除节点只有一个子节点时,应当将其父亲节点指向其的指针改为其子节点;
此外,当出现待删除节点有左右子树,应当进行如下操作:
- 寻找待删除节点右子树的最小节点min
- 将待删除节点更新为min
- 删除右子树中的最小节点min即可
应当注意的是,这里如果采用递归实现删除函数,我们最好将函数的宏观语义定义为对以root为根的树删除节点,并返回root的地址。
// 递归形式
// 返回新的根节点地址
TNode* Delete(ElementType key, TNode* root) {
if (!root)
return NULL;
if (key > root->Data) {
root->Right = Delete(key, root->Right);
return root;
}
else if (key < root->Data) {
root->Left = Delete(key, root->Left);
return root;
}else{
// 待删除节点只有一个非空子节点或无子节点时
if (root->Left == NULL)
return root->Right;
if (root->Right == NULL)
return root->Left;
// 待删除节点有两个非空子节点时
root->Data = findMin(root->Right)->Data;
root->Right = Delete(root->Data, root->Right);
return root;
}
}