• 二叉查找树BST


    二叉查找树(BST)

    定义:  

      又称二叉排序树,二叉搜索树;具备以下特性的树称为二叉查找树:

    1.左子树上所有结点的值均小于它的根结点的值

    2.右子树上所有结点的值均大于它的根结点的值;

    3.左、右子树也分别为二叉查找树。

    typedef struct STreeNode* pSTreeNode;
    typedef int TreeKeyType;
    
    struct STreeNode 
    {
        TreeKeyType key;//节点数据
        //节点指针
        pSTreeNode pLeftChild;//指向左子树
        pSTreeNode pRightChild;//指向右子树
        
        STreeNode( TreeKeyType Value )//构造函数
        {
            key = Value;
            pLeftChild = NULL;
            pRightChild = NULL;
        }
        
    };

    查找:

    1、若待查找的元素值和根节点相同,则返回根节点;
    2、若待查找的元素值小于根节点的元素值,则递归从根节点的左子树中查找;
    3、若待查找的元素值大于根节点的元素值,则递归从根节点的右子树中查找。

    //查找成功,返回指向该节点的指针
    //查找失败,返回NULL
    //pNode-二叉查找树;Value-查找值
    pSTreeNode Search( pSTreeNode pNode, TreeKeyType Value )
    {
        //没有找到
        if ( pNode == NULL )
            return NULL;
    
        //待查找的元素值与根节点的值相同
        if ( pNode->key == Value )
            return pNode;
    
        else
        {
            //带查找的元素值小于根节点的元素值
            if ( pNode->key > Value )
                //在左子树中递归查找
                return Search( pNode->pLeftChild, Value );
            //带查找的元素值大于根节点的元素值
            else
                //在右子树中递归查找 
                return Search( pNode->pRightChild, Value );
        }
    }

    插入:

    1、若当前二叉树为空,则插入的元素为根节点;
    2、若插入的元素值小于根节点值,则递归从根节点的左子树中找到可插入位置;
    3、若插入的元素值大于根节点值,则递归从根节点的右子树中找到可插入位置。

    //插入成功返回true;插入失败返回false
    //pNode-二叉查找树;Value-插入值
    bool Insert( pSTreeNode pNode, TreeKeyType Value )
    {
        if ( pNode == NULL)
                pNode = new STreeNode( Value );
    
        //插入元素的值小于根节点的值
        if ( pNode->key > Value )
            //插入到左子树
            Insert( pNode->pLeftChild, Value );
    
        //插入节点的值大于根节点的值
        else if( pNode->key < Value )
            //插入到右子树
            Insert( pNode->pRightChild, Value );  
    
        //插入节点的值等于根节点的值
        else   
            //树中已有关键字相同的节点,不再插入
            return false;
    
        return true;
    }    

    删除:

    1、待删除节点Z为叶子节点,则直接删除该节点。修改父节点的指针;
    2、待删除节点Z为单支节点(只有左子树或者右子树),让Z的子树与Z的父节点相连,删除节点Z;
    3、待删除节点Z左右子树都不为空
    方法一:找到Z的后继节点Y,Y一定没有左子树,用Y替换Z,并让Y的父亲节点成为Y的右子树的父亲节点,接着删除Y。
    方法二:找到Z的前驱节点X,X一定没有右子树,用X替换Z,并让X的父亲节点成为X的左子树的父亲节点,接着删除X。

    以方法二为例:

    void CBinTree::Delete( pSTreeNode pNode,TreeKeyType Value )
    {
        pSTreeNode pParentNode = pNode;
        pSTreeNode pFindNode = pNode;
    
        //循环结束后,pFindNode指向待删除节点
        //pParentNode指向待删除结点的父节点
        while ( pFindNode != NULL )
        {
            if ( pFindNode->key == Value )
                break;
    
            pParentNode = pFindNode;
            if ( pFindNode->key > Value )
                pFindNode = pFindNode->pLeftChild;
            else
                pFindNode = pFindNode->pRightChild;
        }
    
        //没有找到该节点,不需要做删除操作
        if ( pFindNode == NULL )
            return;
    
    
        //  该节点只有一棵子树或者为叶子节点
        if ( pFindNode->pLeftChild == NULL || pFindNode->pRightChild == NULL )
        {
            //  该节点为叶子节点
            pSTreeNode pTemp = NULL;
    
            //该节点只有左子树
            if ( pFindNode->pLeftChild != NULL)
                pTemp = pFindNode->pLeftChild;
    
            //该节点只有右子树
            else if ( pFindNode->pRightChild != NULL )
                pTemp = pFindNode->pRightChild;
    
    
            //该节点为其父节点的左孩子
            if ( pParentNode->pLeftChild == pFindNode )
                //将该节点的子树变为其父节点的左子树
                pParentNode->pLeftChild = pTemp;
    
            //该节点为其父节点的有孩子
            else
                //将该节点的子树变为其父节点的右子树
                pParentNode->pRightChild = pTemp;
    
            delete pFindNode;
            pFindNode = NULL;
        }
    
    
        //该节点的左右子树均不为空
        else
        {
            pSTreeNode pTemp = pFindNode->pLeftChild;
            pSTreeNode pTempParent = pFindNode;
    
            //循环找到该节点左子树的右侧尽头的节点
            //即待删除节点的前驱节点pTemp(中序遍历的前驱)
            //该节点的前驱节点为左子树中关键字值最大的节点
            while ( pTemp->pRightChild != NULL )
            {
                pTempParent = pTemp;//前驱结点的父节点
                pTemp = pTemp->pRightChild; //一直往右下方走
            }
    
            pFindNode->key = pTemp->key;//pTemp替换pFindNode
            pTempParent->pRightChild = pTemp->pLeftChild;
    
            delete pTemp;
            pTemp = NULL;
        }
    }

    遍历:

    1、前序遍历(递归):先根节点,后左孩子节点,再右孩子结点。
    2、中序遍历(递归):先左孩子结点,后根节点,再右孩子结点。
    3、后序遍历(递归):先做孩子节点,后右孩子结点,再根节点。

    //前序遍历
    void CBinTree::PreorderRecursively( pSTreeNode pNode )
    {
        if (pNode == NULL)
            return;
    
        cout << " " << pNode->key << " ";
        PreorderRecursively( pNode->pLeftChild );//左子树
        PreorderRecursively( pNode->pRightChild );//右子树
    }
    
    //中序遍历
    void CBinTree::InorderRecursively( pSTreeNode pNode )
    {
        if (pNode == NULL)
            return;
    
        InorderRecursively( pNode->pLeftChild );
        cout << " " << pNode->key << " ";
        InorderRecursively( pNode->pRightChild );
    }
    
    //后序遍历
    void CBinTree::PostorderRecursively( pSTreeNode pNode )
    {
        if (pNode == NULL)
            return;
    
        PostorderRecursively( pNode->pLeftChild );
        PostorderRecursively( pNode->pRightChild );
        cout << " " << pNode->key << " ";
    }

    原文链接 https://blog.csdn.net/lining0420/article/details/76167901

  • 相关阅读:
    eclipse中的项目无法在build/classes目录下生成.class字节码
    nginx的权限问题(Permission denied)解决办法
    application/x-www-form-urlencoded、application/json、multipart/form-data、text/xml简单总结
    jackson的使用和详解
    博客园自定义样式
    java基础
    k8s
    系统服务构建运维
    私有云技术
    工程文档编写
  • 原文地址:https://www.cnblogs.com/yongjin-hou/p/14533790.html
Copyright © 2020-2023  润新知