关闭

数据结构 ---- 二叉搜索树

标签: 数据结构二叉搜索树
541人阅读 评论(0) 收藏 举报

一直对于二叉搜索树(又叫二叉排序树,也叫二叉查找树),没有很好的理解,决定花点时间来学习and总结。。


二叉搜索树也是二叉树的一种。(就像堆也就二叉树的一种一样。。。)

只不过,二叉搜索树也是有其他要求:对于所有的子树,其根节点的值大于左子树上的所有结点的值,而小于右子树上所有结点的值的值。。

对于错误的理解:对于所有的结点,要大于其左结点,小于其右结点。。(PS:这种理解是错误的,一定要注意。。)

还有一点需要注意的是:我们的大于和小于都应该是严格的。


========== 下面主要针对,其建立、增删改查这些操作来进行说明 ==============

====== 对于所有的数据结构,我们对其增删改查都应该有比较清楚的认识==========

首先我们定义一下二叉树的结构(链式结构):

<span style="font-size:18px;"><span style="font-size:18px;"># 结点的数据结构
typedef int ElementType;
typedef struct
{
    ElementType Element;
    ElementType *left;
    ElementType *right;
}TreeNode;

# 有必要区别一下结点和树的区别。
具体来说的话:
结点的话,就是有数据+空间。
树的话,就是一个指向树的头结点的指针。
现在,我说给你你棵树,肯定就是给你一个指向头结点的指针。

</span></span>


MakeEmpty:

所谓makeempty就是一个用来初始化一个空的二叉搜索树。(注意这个‘为’字 = =)

这里是初始化,我们理解为:现在给你一棵树(可能不是一棵空树),我们如何来初始化。

========== 插一腿 =========

有必要解释一下,新建和初始化,我对这两个概念理解上的区别。

比如:
现在我要新建一棵二叉树:

       新建二叉树的话,就是要新建一个的root结点(或者说新建一个指向root结点的指针)。

现在我要初始化一棵二叉树:

       初始化二叉树的话,就是现在一棵二叉树已经建好了,我要初始化他。在没有插入任何一个结点的时候,初始化就显的比较尴尬了。不用分配空间,不用初始化数据。

ppps:对于这两个概念的区别还是有待更加深刻的理解(特别是树)。有待以后学习。

对于这个 问题,我又了解了一些情况。这儿有一个帖子,讨论的比较有>>>>>>http://bbs.csdn.net/topics/360102904

加上自己的一点理解:创建的话,你只需要指定,你现在已经创建了一个你的数据结构;而初始化的话,就是你需要对你的数据进行处理。。。

比如现在你要创建和初始化一棵树(无论是什么样的数):

创建一棵树,就是你要个给出这棵树的一个接口(头结点)。想一想,对于给你一棵树,你会得到什么?就是该树得头结点啊。。

那么对于初始化呢?初始化一棵树的话,我们就需要对说有的结点进行空间的分配和数据的存储。。

现在对于新建和初始化应该有很清楚的理解。。。


=========================

Code:

<span style="font-size:18px;"><span style="font-size:18px;">返回的是一棵树。而不是。。。。
TreeNode* MakeEmpty(TreeNode* tree)
{
    if(tree != NULL){
        MakeEmpty(tree -> left);
        MakeEmpty(tree -> right);
        free(tree);
    }
    return NULL;
}
</span></span>


Find, FindMin and FindMax:

对于查找来说,我们的二叉搜索树还是有一定的优势的。(这也是为什么我们的二叉搜索树也叫二叉查找树)。

对于所有类型的查找(无论是找什么样元素,存在的,不存在的,最大的,最小的),我们的平均查找时间为log(n),n为该树中的所有结点。



<span style="font-size:18px;">// 返回值为结点的地址。
// 寻找值为x的结点。。
TreeNode* Find(ElementType x, TreeNode* T)
{
    if(T == NULL) return NULL;
    
    if(T -> Element > x ){
        return Find(x, TreeNode -> left);
    }
    else if(T -> Element < x) {
        return Find(x, TreeNode -> right);
    } 
    return T;
}

// 寻找最小值的结点。。
TreeNode* FindMin(TreeNode* T)
{
    if(T == NULL) return NULL;
    if(T -> left == NULL){
        return T;
    }
    return FindMin(T -> left);
}


// 寻找最大值的结点。。
TreeNode* FindMax(TreeNode* T)
{
    if(T == NULL) return NULL;
    if(T -> right == NULL) {
        return T;
    }
    return FindMax(T -> right);
}

</span>

对于二叉搜索树的查找操作还是比较简单的。。。

对于他的递归写法很是简单;当然,对于其的循环写法就更加的简单了。。。


Insert:

插入的话,我们最优(或者说,最简单)的做法就是,把需要插入的结点插入为叶子结点。

时间复杂度的话,就是logn。

<span style="font-size:18px;">// 插入
TreeNode* Insert(ElementType x, TreeNode* T)
{
    if(T == NULL){
        T = (TreeNode*)malloc(sizeof(TreeNode));
        T -> Element = x;
        T -> right = T -> left = NULL;
    }
    if(x > T -> Element){
        T -> right = Insert(x, T -> right);
    }
    else if(x < T -> Element){
        T -> left = Insert(x, left);
    }
    return T; // 不要忘了返回插入以后的二叉树。
    
}</span>


Delete:
对于二叉搜索树的删除,  是所有操作中最难的一个。(这和其他的数据结构一样,最难的操作就是删除。)

删除的情况有很多情况:
1,删除的是叶子结点:

      最简单的应该就是删除的叶子结点了。删除叶子对于其他的结点没有任何的联系,所以,直接删除就可以了。

2,删除的结点只有一个棵子树:

      对于只有一棵只树的结点,也是比较简单的,我们直接把该结点的唯一子树把该结点替换了就可以了。。

3,删除的结点有两棵子树:

     最麻烦的应该就是删除这种类型的结点了,那么我们具体应该怎么做呢?我们这样想,我们删除这个结点以后应该用谁来代替他的位置,以至于仍然还是棵二叉搜索树呢?   该节点应该小于其右子树的所有节点,大于其左子树的结点。 ------   这就是我们的线索。所以我们应该找到其左子树上的最大的结点,或者是其右子树上的最小的结点。


Code:


TreeNode* Delete(ElementType x, TreeNode* T)
{
    if(T == NULL) return NULL;
    
    if(x > T -> Element){
        T -> right = Delete(x, T -> right);
    }
    else if(x < T -> Element){
        T -> left = Delete(x, T -> left);
    }
    // 找到需要删除的结点= =
    if(x -> left && x -> right){ // 有两棵子树
        // 用其右子树上最小值的结点代替该结点
        TreeNode* submin = FindMin(T -> right);
        T -> Element = submin -> Element;
        T -> right = Delete(T -> Element, T -> right);
        // 用其左子树上最大值的结点代替该结点
        TreeNode* summax = FindMax(T -> left);
        T -> Element = summax -> Element;
        T -> left = Delete(T -> Element, T -> left);
    }
    else{ // 有一棵子树或者没有子树
        TreeNode* tmp = T;
        if(T -> left == NULL){
            T = T -> right;
        }
        else if(T -> right == NULL){
            T = T -> left;
        }
        free(tmp);
    }
}

到此为止,我们的二叉搜索树的基本操作就是这些,只是一些很基础的一些东西,希望以后有所补充。



0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:317305次
    • 积分:6413
    • 等级:
    • 排名:第4205名
    • 原创:320篇
    • 转载:75篇
    • 译文:1篇
    • 评论:30条