zoukankan      html  css  js  c++  java
  • 数据结构与算法之二叉搜索树

      与链表不同,树是一种非线性的数据结构。树中最常用的是二叉树,二叉树限制了子树的数量,也就是每个结点的子树至多2个,并且这两个子树是有顺序的。而二叉搜索树(二叉查找树,二叉排序树)是指根节点的关键字大于左子树的,而小于右子树,并且,左右子树也是一颗二叉搜索树。也就是说中序遍历一颗二叉搜索树,它的输出是从小到大排序好的。

      除了普通的二叉搜索树之外,还有很多关于它的变形。

      二叉平衡搜索树,即即是一颗二叉平衡树,也是一颗搜索树,平衡树即任意一个结点的左子树的高度与右子树的高度之差的绝对值不大于1。

      红黑树,也是一种特殊的二叉查找树,除了具备查找树的特点,它的每个结点上还有一个记录红黑颜色的元素。

      这里我们主要讨论一般的二叉搜索树。

      二叉搜索树,其实就是一颗特殊的树,任何适用于树的算法都适用于二叉搜索树。当然它也是图,任何适用于图的算法也适用于二叉搜索树。图中的深度优先搜索(DFS)其实就是树中的前序遍历,广度优先搜索(BFS)就是树中的层序遍历。当然图中还有很多其他算法也都适用于树。

    1、二叉树的数据结构

    typedef struct binSrcTreeNode{
        int element;
        struct binSrcTreeNode *pLeft;
        struct binSrcTreeNode *pRight;
    }BSTNode;

    2、动态分配一个二叉树的结点

    BSTNode* allocNode(int element){
        BATNode *pNode = (BSTNode*)malloc(sizeof(BSTNode));
        if(NULL != pNode){
            pNode->element = element;
            pNode->pLeft = NULL;
            pNode->pRight = NULL;
        }
        return pNode;
    }

    3、二叉搜索树的查找

    由于二叉搜索树是已经排序了的二叉树,所以可以通过二分查找来搜索。先判断是否等于根节点,如果大于根节点的关键字,搜索右子树,小于根节点的关键字,搜索左子树。

    bool searchInBSTree(const BSTNode *pRoot,int element,BSTNode **pNode){
        if(NULL == pRoot)
            return false;
        *pNode = pRoot;
        if(pRoot->element == element){
            return true;
        }
        else if(pRoot->element > element)
            return searchInBSTree(pRoot->pLeft,element,pNode);
        else
            return searchInBSTree(pRoot->pRight,element,pNode);
    }

    4、二叉搜索树的插入

    首先查找二叉树是是否已经存在该元素,如果已经存在返回false;如果不存在,插入该结点,插入元素大于根节点,则插入右子树,否则,插入左子树中。

    bool insertIntoBSTree(BSTNode **pRoot,int element){
        if(NULL == pRoot)
            return false;
        if(NULL == *pRoot){
            *pRoot = allocNode(element);
            return NULL==*pRoot?false:true;
        }
        BSTNode **pSrc = NULL;
        if(searchInBSTree(pRoot,element,pSrc))
            return false;
        BSTNode *pNode = allocNode(element);
        if(element < *pSrc->element)
            *pSrc->pLeft = pNode;
        else
            *pSrc->pRight = pNode;
        return true;
    }

    5、二叉搜索树的删除

    二叉搜索树的删除分为三种情况:

    (1) 删除结点为叶子结点,直接删除该结点,再修改其父结点的指针(注意分是根结点和不是根节点)。

    (2) 删除结点为单支结点(即只有左子树或右子树)。

    (3) 删除结点的左子树和右子树均不空。

    bool deleteFromBSTree(BSTNode **pRoot,int element){
        if(NULL == pRoot || NULL == *pRoot)
            return false;
        BSTNode **pSrc = NULL;
        BSTNode **pParent = NULL;
        if(searchInBSTree(*pRoot,element,pParent,pSrc)){
            if(NULL == *pSrc->pLeft && NULL == *pSrc->pRight){
                free(*pSrc);
                *pSrc = NULL;
                return true;
            }
            else if(NULL == *pSrc->pLeft){
                if(*pSrc == *pParent->pLeft)
                    *pParent->pLeft = *pSrc->pRight;
                else if(*pSrc == *pParent->pRight)
                    *pParent->pRight = *pSrc->pRight;
                free(*pSrc);
                return true;
            }
            else if(NULL == *pSrc->pRight){
                if(*pSrc == *pParent->pLeft)
                    *pParent->pLeft = *pSrc->pLeft;
                else if(*pSrc == *pParent->pRight)
                    *pParent->pRight = *pSrc->pLeft;
                free(*pSrc);
                return true;
            }
            else{
                BSTNode *pNode = *pSrc;
                BSTNode *pChild = *pSrc->pLeft;
                while(pChild->pRight){
                    pNode = pChild;
                    pChild = pChild->pRight;
                }
                if(pNode == *pSrc) pNode->pLeft = pChild->pLeft;
                else pNode->pRight = pChild->pLeft;
                
                if(*pSrc == *pParent->pLeft) *pParent->pLeft = pChild;
                else *pParent->pRight = pChild;
                
                pChild->pLeft = *pSrc->pLeft;
                pChild->pRight = *pSrc->pRight;
                
                return true;
            }
        }
        
        return false;
    }

    6、二叉搜索树的前序中序后序遍历

    /* preOrder to traverse the binarySearchTree.*/
    void preOrderBinarySearchTree(const BSTNode *pRoot){
        if(NULL == pRoot)
            return ;
        printf("%d ",pRoot->element);
        preOrderBinarySearchTree(pRoot->pLeft);
        preOrderBinarySearchTree(pRoot->pRight);
    }
    
    /* inOrder to traverse the binarySearchTree.*/
    void inOrderBinarySearchTree(const BSTNode *pRoot){
        if(NULL == pRoot)
            return ;
        inOrderBinarySearchTree(pRoot->pLeft);
        printf("%d ",pRoot->element);
        inOrderBinarySearchTree(pRoot->pRight);
    }
    
    /* posOrder to traverse the binarySearchTree.*/
    void posOrderBinarySearchTree(const BSTNode *pRoot){
        if(NULL == pRoot)
            return ;
        posOrderBinarySearchTree(pRoot->pLeft);
        posOrderBinarySearchTree(pRoot->pRight);
        printf("%d ",pRoot->element);
    }

    7、释放结点

    void freeBinarySearchTree(BSTNode *pRoot){
        if(NULL == pRoot)
            return ;
        freeBinarySearchTree(pRoot->pLeft);
        freeBinarySearchTree(pRoot->pRight);
        free(pRoot);
    }

    完整代码详见:https://github.com/whc2uestc/DataStructure-Algorithm/tree/master/tree

  • 相关阅读:
    [Codeforces 339D] Xenia and Bit Operations
    [Codeforces 459D] Pashmak and Parmida's problem
    [Codeforces 460C] Present
    [Codeforces 466C] Number of Ways
    [Codeforces 650A] Watchmen
    Linux系统中‘dmesg’命令处理故障和收集系统信息的7种用法
    select函数详解
    都是stm32的JTAG引脚惹的祸
    uboot中的快捷菜单的制作说明
    卷积的本质及物理意义(全面理解卷积)
  • 原文地址:https://www.cnblogs.com/whc-uestc/p/4638349.html
Copyright © 2011-2022 走看看