zoukankan      html  css  js  c++  java
  • 二叉搜索树的插入、删除、查找

    二叉查找树有以下性质:

    (1)若左子树不空,则左子树上所有节点的值均小于它的根节点的值
    (2)若右子树不空,则右子树上所有节点的值均大于它的根节点的值
    (3)左、右子树也分别为二叉排序树
    (4)没有键值相等的节点
     

    插入(递归)

      插入的数据之后要满足二叉树的性质1和2,所以要先找到插入位置,且插入的位置一定是在叶子节点的下面

      所以插入分两个步骤:

      1、确定插入位置是在那个叶子节点下面

      2、新建一个节点,让叶子节点指向新建的节点

      

    node* insert(node* root,int x)
    {
        //插入的位置一定是在叶子节点,这里是先递归找到叶子节点,
        if(root==NULL)
        {
            //然后新建一个节点,让叶子节点指向这个节点
            node *temp=(struct node*)malloc(sizeof(struct node));
            temp->data=x;
            temp->left=NULL;
            temp->right=NULL;
            return temp;
        }
        if(x<root->data)
        {
            root->left=insert(root->left,x);
        }
        else
            root->right=insert(root->right,x);
        return root;//插入的时候是递归,所以最后会返回根节点
    }

    查找(递归)

      从根节点不断往下找就行

      

    bool search(node * root,int x)
    {
        //递归到子节点任然没找到,说明不存在这个节点
        if(root==NULL)
            return false;
        else if(x<root->data)
            return search(root->left,x);
        else if(x>root->data)
            return search(root->right,x);
        else
            return true;
    }

    删除(递归)

      删除的时候比较复杂,因为删除的节点不一定是在叶子节点上,有可能在其它位置,删除一个节点后还要维持二叉树的完整和树的性质

      

      如何维持二叉查找树的完整和性质呢?

      1、先说如何维持树的完整性:

      找到被删除节点的位置之后,我们不直接把这个节点删除,而是从被删除节点的子树中找到一个后继节点,用后继节点的值去替换被删除的节点,

      然后删除后继节点(这里有一个递归,会递归到子节点,最后变成删除叶子节点,删除叶子节点就不会影响树的完整)

      2、如何维持二叉查找树的性质,也就是如何找后继节点(这个性质是:左节点比根节点小,右节点比根节点大)

      1、如果被删除的这个节点既有子树,又有右子树

        从右子树中找一个最小值,这个最小值就是后继节点

        举个例子解释一下:

        

         如果我要删除值为3的节点,从节点3的右子树中找一个最小值是4,4比右子树中的所有值都大,同时比左子树中所有值都小,所以可以让4去替代3成为根节点

      代码

    //在右子树中查找后继节点(右子树中的最小值)
    node* FindMin(node *root)
    {
        if(root==NULL)
            return NULL;
        else if(root->left==NULL)
            return root;
        else
            return FindMin(root->left);
    }

      2、如果被删除的这个节点既有只有左子树

        从左节点中找一个最大值成为后继节点,原理同上

      代码

      

    //在左子树中查找后继节点(左子树中的最大值)
    node* FindMax(node *root)
    {
        if(root==NULL)
            return NULL;
        else if(root->right==NULL)
            return root;
        else
            return FindMax(root->right);
    }

      3、如果被删除的这个节点既有只有右子树

      从右子树中找一个最小值成为后继节点

    删除的代码

    //删除值为x的节点
    node* delet(node* root,int x)
    {
        //递归出口是叶子节点
        if(root==NULL)
        {
            return root;
        }
        else
        {
            if(x<root->data)
                root->left=delet(root->left,x);
            else if(x>root->data)
                root->right=delet(root->right,x);
            else
            {
                //左右节点都存在
               if(root->left&&root->right)
               {
                    node* temp=FindMin(root->right);
                    //把当前节点的值修改成后继节点的值
                    root->data=temp->data;
                    //在右子树中找后继节点的位置,并删除
                    root->right=delet(root->right,root->data);
               }
               else
               {
                    //只存在一个子节点
                    if(root->left==NULL)
                        root=root->right;
                    if(root->right==NULL)
                        root=root->left;
               }
            } 
        }
        return root;//返回根节点
    }

    遍历(递归)

      树的遍历有三种方式:前序、后序、中序

      

    void inOrder(node* root)//以中序序列输出
    {
        if(root->left != NULL ) //输出左节点
            inOrder(root->left);
        cout << root->data << " ";//输出根节点
        if(root->right != NULL ) 
            inOrder(root->right);//输出右节点
    }
    void preOrder(node* root)//以先序序列输出
    {
        cout << root->data << " ";//
        if(root->left!=NULL)
            preOrder(root->left);//
        if(root->right!=NULL)
            preOrder(root->right);//
    }
    void houOrder(node* root)//后序序列输出
    {
        if(root->left!=NULL)//
            houOrder(root->left);
        if(root->right!=NULL)//
            houOrder(root->right);
        cout << root->data << " ";//
    }

    完整代码

    #include<iostream>
    #include<stdlib.h>
    #include<string.h>
    using namespace std;
    struct node
    {
        int data;
        struct node* left;
        struct node* right;
    };
    //查找值为x的节点是否在二叉树
    bool search(node * root,int x)
    {
        //递归到子节点任然没找到,说明不存在这个节点
        if(root==NULL)
            return false;
        else if(x<root->data)
            return search(root->left,x);
        else if(x>root->data)
            return search(root->right,x);
        else
            return true;
    }
    //向树中插入一个节点
    node* insert(node* root,int x)
    {
        //插入的位置一定是在叶子节点,这里是先递归找到叶子节点,
        if(root==NULL)
        {
            //然后新建一个节点,让叶子节点指向这个节点
            node *temp=(struct node*)malloc(sizeof(struct node));
            temp->data=x;
            temp->left=NULL;
            temp->right=NULL;
            return temp;
        }
        if(x<root->data)
        {
            root->left=insert(root->left,x);
        }
        else
            root->right=insert(root->right,x);
        return root;//插入的时候是递归,所以最后会返回根节点
    }
    //在左子树中查找后继节点(左子树中的最大值)
    node* FindMax(node *root)
    {
        if(root==NULL)
            return NULL;
        else if(root->right==NULL)
            return root;
        else
            return FindMax(root->right);
    }
    
    //在右子树中查找后继节点(右子树中的最小值)
    node* FindMin(node *root)
    {
        if(root==NULL)
            return NULL;
        else if(root->left==NULL)
            return root;
        else
            return FindMin(root->left);
    }
    
    //删除值为x的节点
    node* delet(node* root,int x)
    {
        //递归出口是叶子节点
        if(root==NULL)
        {
            return root;
        }
        else
        {
            if(x<root->data)
                root->left=delet(root->left,x);
            else if(x>root->data)
                root->right=delet(root->right,x);
            else
            {
                //左右节点都存在
               if(root->left&&root->right)
               {
                    node* temp=FindMin(root->right);
                    //把当前节点的值修改成后继节点的值
                    root->data=temp->data;
                    //在右子树中找后继节点的位置,并删除
                    root->right=delet(root->right,root->data);
               }
               else
               {
                    //只存在一个子节点
                    if(root->left==NULL)
                        root=root->right;
                    if(root->right==NULL)
                        root=root->left;
               }
            } 
        }
        return root;//返回根节点
    }
    void PrintBSTree(node *root)//前序遍历输出
    {
        if(root==NULL)
            return ;
        else
        {
            cout<<root->data<<' ';
            PrintBSTree(root->left);
            PrintBSTree(root->right);
        }
    }
    void inOrder(node* root)//以中序序列输出
    {
        if(root->left != NULL ) //输出左节点
            inOrder(root->left);
        cout << root->data << " ";//输出根节点
        if(root->right != NULL ) 
            inOrder(root->right);//输出右节点
    }
    void preOrder(node* root)//以先序序列输出
    {
        cout << root->data << " ";//
        if(root->left!=NULL)
            preOrder(root->left);//
        if(root->right!=NULL)
            preOrder(root->right);//
    }
    void houOrder(node* root)//后序序列输出
    {
        if(root->left!=NULL)//
            houOrder(root->left);
        if(root->right!=NULL)//
            houOrder(root->right);
        cout << root->data << " ";//
    }
    
    int main()
    {
        int x,n;
        node* root=new node;
        root=NULL;
        cin>>n;
        for(int i=0;i<n;i++)
        {
            cin>>x;
            root=insert(root,x);
        }
        
        preOrder(root);
        cout<<endl;
        delet(root,4);
        preOrder(root);
        cout<<endl;
        
        return 0;
    }
  • 相关阅读:
    杂七杂八的文档资料。
    图片(img标签)的onerror事件
    html的a标签的 href 和 onclick。
    【mysql】一次有意思的数据库查询分析。
    书籍:Building Secure PHP Apps
    js关闭当前页面/关闭当前窗口
    【汉字乱码】IE下GET形式传递汉字。
    弹出层展示插件。
    原型图设计工具。
    LeetCode(24): 两两交换链表中的节点
  • 原文地址:https://www.cnblogs.com/-citywall123/p/12587078.html
Copyright © 2011-2022 走看看