二叉树搜索树
删除(Delete)二叉搜索树上的任意一个节点
原理
我们将删除结点的情况 分为三种
1.NO child
- 被删除节点是叶子结点 因为叶子结点没有孩子 可以直接删除
- 我们只需要将结点释放内存在讲这个空地址 return 回去就好了
- One child
- 结点只有一个孩子,无论是这个孩子是左孩子 还是右孩子
- 因为只有一个孩子 我们只需要将 root(被删除的结点) = root->child
- 指针root 移动到他自身唯一的孩子去 跳过这个被删除的结点 最后返回root->child 给root的父亲
- 同时要先用一个临时变量temp 把root记录下来 最后free(temp) 释放内存空间
- Two child
- 面对有两个孩子的结点, 我们应该将它转为成情况1 或者情况2
- 我们找到 这个结点右子树的最小值 或者是左子树的最大值
- 为什么要找到右子树的最小值? 因为右子树的最小值一定比这个根节点的左子树
大 同时一定比根节点的右子树小, 而且 无论是最小值还是最大值一定都只有一个孩子 - 这样一来我们将情况3 转换成情况2
- 如果使用右子树的最小值
- 首些 得到右子树最小值的节点 min ,再把根节点root->data = min->data
- 替换掉root的值
- 最后再把最小值的结点删除 因为是从右子树找到最小值 所以我们要以右子树为根去删除
- root->right = Delete(root->right, min->data);
- root的右子树中某个结点被删除了
- 最后逐层返回
测试代码
#include<stdio.h>
#include<stdlib.h>
typedef struct BstNode{
int data;
struct BstNode* left;
struct BstNode* right;
}BstNode;
BstNode* Insert(BstNode* root,int data);
BstNode* GetNewNode(int data);
int Search(BstNode* root, int data);
BstNode* FindMin(BstNode* root);
BstNode* Delete(BstNode* root, int data) ;
void PreOrder( BstNode* root);
int main()
{
BstNode *Proot; //The pointer is point to root node of Tree
Proot = NULL; //setting Tree as empty
Proot = Insert(Proot,15);
Proot = Insert(Proot,10);
Proot = Insert(Proot,20);
Proot = Insert(Proot,25);
Proot = Insert(Proot,8);
Proot = Insert(Proot,12);
int number;
printf("Enter number be searched\n");
PreOrder( Proot);
Proot = Delete(Proot, 10);
printf("\n");
PreOrder( Proot);
return 0;
}
BstNode* GetNewNode(int data)
{
BstNode* newNode = (BstNode*)malloc(sizeof(BstNode)); //申请一个Bstnode结构的变量 将指针指向这个变量
(*newNode).data = data; // 将数据给到结点
newNode->left = NULL; //子树指针为空
newNode->right = NULL;
return newNode; //返回指针
}
BstNode* Insert(BstNode* root,int data)
{
if( root == NULL){ //查看根节点是否为空 如果空就这这个指针指向一个新的结点
root = GetNewNode(data);
}else if( data <= root->data){ //如果数据比结点小 将结点插入到左子树
root->left = Insert(root->left, data);
}else {
root->right = Insert(root->right ,data); //否者数据比结点大 将结点插入到右子树
}
return root;
}
int Search(BstNode* root, int data)
{
if(root == NULL) return 0; //0代表树空
else if(root->data == data) return 1;
else if( data <= root->data) return Search(root->left, data);
else return Search(root->right, data);
}
BstNode* FindMin(BstNode* root)
{
BstNode* current = root;
while( current->left !=NULL)
{
current = current->left;
}
return current;
}
BstNode* Delete(BstNode* root, int data) //根节点和要删除的数据
{
if( root == NULL) return NULL;
else if( data < root->data) root->left = Delete( root->left,data); //data 比 根节点要小 那么就去根的左子树去匹配
else if( data > root->data) root->right = Delete(root->right, data); //data 比根节点要大 去根的右子树寻找匹配项
else // 找到了匹配的结点了 要区分被删除的结点的子树个数 分三种
{
// Case no child
if( root->left == NULL && root->right == NULL)
{
free(root);
root = NULL ;
}
// Case 2 One child
else if( root->left == NULL)
{
BstNode* temp = root; //临时指针指向root
root = root->right; //因为 只有一个右孩子 所有我们将结点前进 再把这个结点返回
free(temp); // 把要删除的结点内存释放
// 这样子root指向的结点就被root->right 代替了
}else if ( root->right ==NULL)
{
BstNode* temp = root; //临时指针指向root
root = root->left; //因为 只有一个左孩子 所有我们将结点前进 再把这个结点返回
free(temp); // 把要删除的结点内存释放
// 这样子root指向的结点就被root->right 代替了
} // case 3 Two child
else{
BstNode* min = FindMin(root->right); // 从右子树寻找最小值 或者从左子树寻找最大值
root->data = min->data; // 将被删除的结点data 替换成min的data
root->right = Delete( root->right, min->data);
}
}
return root;
}
void PreOrder( BstNode* root)
{
if( root == NULL ) return ;
else
{
printf("%5d",root->data);
PreOrder(root->left);
PreOrder(root->right);
}
}