数据结构与算法之二叉搜索树

  与链表不同,树是一种非线性的数据结构。树中最常用的是二叉树,二叉树限制了子树的数量,也就是每个结点的子树至多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

 

posted @   牛逼的码农  阅读(804)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示