概念
二叉搜索树是一种特殊的二叉树,其中左孩子一定比父节点小,右孩子一定比父节点大。递归思想在其中有巨大的作用。下面是我画的二叉树。
我们用C语言来讲
首先我们的Node是这样的:
typedef struct BST
{
int data;
struct BST* lchild;
struct BST* rchild;
}BSTree;
创建二叉查找树/增加节点
递归的思想:
- 递归函数的功能:把每一个节点都添加进二叉查找树中
- 递归结束的条件:找到节点应该在的位置,然后进行插入
- 递归函数的等价关系:假设要插入的值为 x x x,首先判断
root->data == x?
,是就直接返回,不重复插入了,不是就比较两者的值的大小,如果root->data < x
,那么就在右子树中继续插入;如果root->data>x
,那么就在左子树中继续插入。
BSTree* CreateBSTree(BSTree* root, int x)
{
if(!root)
{
root = CreateBSTNode(x); //CreateBestNode是用来创建一个新的Node的
return root;
}
if(x < root->data)
root->lchild = CreateBSTree(root->lchild, x);
root->rchild = CreateBSTree(root->rchild, x);
return root;
}
BSTree* CreateBSTNode(int x)
{
BSTree* newNode = (BSTree*)malloc(sizeof(BSTree));
newNode->data = x;
newNode->lchild = NULL;
newNode->rchild = NULL;
return newNode;
}
查找
递归的思想:
- 递归函数的功能:查找某个值是否在树里面
- 递归结束条件:找到了(要查找的值和节点的值相同)或没找到(要比较的都比较了一遍,还是找不到)
- 递归函数的等价关系:假设要查找的值为 x x x,首先判断
root->data == x?
,是就直接返回,不是就比较两者的值的大小,如果root->data < x
,那么就在右子树中找x;如果root->data>x
,那么就在左子树中找x;找不到就返回NULL
BSTree* find(BSTree* root, int x)
{
if(!root)
return NULL;
if(x < root->data)
return find(root->lchild, x);
if(x > root->data)
return find(root->rchild, x);
return root;
}
删除
递归的思想:
- 递归函数的功能:删除某个节点
- 递归结束条件:找到了(要查找的值和节点的值相同,成功删除)或没找到(要比较的都比较了一遍,还是找不到)
- 递归函数的等价关系:假设要删除的值为 x x x,首先判断
root->data == x?
,是就删除,不是就比较两者的值的大小,如果root->data < x
,那么就在右子树中找x;如果root->data>x
,那么就在左子树中找x
BSTree* DeleteBSTNode(BSTree* root, int x)
{
/*三种情况:
**1. 没有子节点
**2.一个子节点
**3.两个子节点
**特殊考虑删的是根节点
*/
BSTree* temp;
if(!root)
return NULL;
else if(x < root->data)
root->lchild = DeleteBSTNode(root->lchild, x);
else if(x > root->data)
root->rchild = DeleteBSTNode(root->rchild, x);
else // x == root->data的情况
{
if(root->lchild && root->rchild) //有两个子节点
{
temp = findleftmax(root->lchild);//要把的是左子树最大的拿来当当前的root
root->data = temp->data;
root->lchild = DeleteBSTNode(root->lchild, root->data);//把左子树最大的节点删掉
}
else //没有两个子节点
{
temp = root;
if(root->lchild) //只有左孩子,就直接把左子树拿来当节点
{
root = root->lchild;
}
else if(root->rchild) //只有右孩子,就直接把左子树拿来当节点
{
root = root->rchild;
}
else //左右孩子都没有,就直接删掉
{
root = NULL;
}
free(temp); //释放原本的root
temp = NULL;
}
}
return root;
}
BSTree* findleftmax(BSTree* root)
{
if(root->rchild)
return findleftmax(root->rchild);
return root;
}
完整版代码
typedef struct BST
{
int data;
struct BST* lchild;
struct BST* rchild;
}BSTree;
BSTree* CreateBSTree(BSTree* root, int x)
{
if(!root)
{
root = CreateBSTNode(x); //CreateBestNode是用来创建一个新的Node的
return root;
}
if(x < root->data)
root->lchild = CreateBSTree(root->lchild, x);
root->rchild = CreateBSTree(root->rchild, x);
return root;
}
BSTree* CreateBSTNode(int x)
{
BSTree* newNode = (BSTree*)malloc(sizeof(BSTree));
newNode->data = x;
newNode->lchild = NULL;
newNode->rchild = NULL;
return newNode;
}
BSTree* find(BSTree* root, int x)
{
if(!root)
return NULL;
if(x < root->data)
return find(root->lchild, x);
if(x > root->data)
return find(root->rchild, x);
return root;
}
BSTree* DeleteBSTNode(BSTree* root, int x)
{
/*三种情况:
**1. 没有子节点
**2.一个子节点
**3.两个子节点
**特殊考虑删的是根节点
*/
BSTree* temp;
if(!root)
return NULL;
else if(x < root->data)
root->lchild = DeleteBSTNode(root->lchild, x);
else if(x > root->data)
root->rchild = DeleteBSTNode(root->rchild, x);
else // x == root->data的情况
{
if(root->lchild && root->rchild) //有两个子节点
{
temp = findleftmax(root->lchild);//要把的是左子树最大的拿来当当前的root
root->data = temp->data;
root->lchild = DeleteBSTNode(root->lchild, root->data);//把左子树最大的节点删掉
}
else //没有两个子节点
{
temp = root;
if(root->lchild) //只有左孩子,就直接把左子树拿来当节点
{
root = root->lchild;
}
else if(root->rchild) //只有右孩子,就直接把左子树拿来当节点
{
root = root->rchild;
}
else //左右孩子都没有,就直接删掉
{
root = NULL;
}
free(temp); //释放原本的root
temp = NULL;
}
}
return root;
}
BSTree* findleftmax(BSTree* root)
{
if(root->rchild)
return findleftmax(root->rchild);
return root;
}
void preOrder(BSTree* root)
{
if(root)
{
printf("%d ", root->data);
preOrder(root->lchild);
preOrder(root->rchild);
}
}
int main()
{
BSTree* root = NULL; //最开始的时候记得要赋个NULL值,比较安全
int x;
int flag = 1;
// 以下是创建二叉查找树或插入的函数
while(flag)
{
printf("Enter the data of BST node: ");
scanf("%d", &x);
getchar();
root = CreateBSTree(root, x);
printf("Enter 0 to stop: ");
scanf("%d", &flag);
getchar();
}
// 下面是遍历
preOrder(root);
printf("\n");
// 下面是删除
printf("Please enter the value to delete: ");
scanf("%d", &x);
DeleteBSTNode(root, x);
preOrder(root);
return 0;
}