详解二叉搜索树,增删改查都包圆(内附代码实现)

概念

二叉搜索树是一种特殊的二叉树,其中左孩子一定比父节点小,右孩子一定比父节点大递归思想在其中有巨大的作用。下面是我画的二叉树。
在这里插入图片描述

我们用C语言来讲
首先我们的Node是这样的:

typedef struct BST
{
    
    
    int data;
    struct BST* lchild;
    struct BST* rchild;
}BSTree;

创建二叉查找树/增加节点

递归的思想

  1. 递归函数的功能:把每一个节点都添加进二叉查找树中
  2. 递归结束的条件:找到节点应该在的位置,然后进行插入
  3. 递归函数的等价关系:假设要插入的值为 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;
}

查找

递归的思想

  1. 递归函数的功能查找某个值是否在树里面
  2. 递归结束条件找到了(要查找的值和节点的值相同)或没找到(要比较的都比较了一遍,还是找不到)
  3. 递归函数的等价关系:假设要查找的值为 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;
}

删除

递归的思想

  1. 递归函数的功能:删除某个节点
  2. 递归结束条件找到了(要查找的值和节点的值相同,成功删除)或没找到(要比较的都比较了一遍,还是找不到)
  3. 递归函数的等价关系:假设要删除的值为 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;
}

猜你喜欢

转载自blog.csdn.net/skywuuu/article/details/115032812