5.1.1 二叉搜索树

5.1.1 二叉搜索树

二叉树是指任何节点最多只有两个子节点;而二叉搜索树(也称二叉查找树)的规则如下:

  • 对数时间的元素插入和访问(O(h) == O(lgn))
  • 任何节点键值一定大于其左子树中的每一个节点的键值,一定小于其右子树节点的键值。

根据上面的定义,判断下图中的树哪个不是二叉搜索树:

左边的是,右边的不是;因为根节点的键值6小于左子树中其中一个节点的键值7。请记住:从根节点一直往左(右)走,直到无左(右)路可走,即得最小(大)元素。如下图所示:

5.1.2 操作

二叉搜索树的常用操作有:查找最小/大元素,插入及删除元素。下面给出具体的操作步骤。注意:这里以int型数据作为研究对象,当然可以写成模板,这里一切从简,以聚焦于算法的原理。树中存放节点数据的结构体如下:

struct Node
{
    int key;              // 以int型数据为例
    Node *Left, *Right;   // 指向左右子节点的指针
};

每个节点的数据结构包含一个int型键值,两个分别指向左、右子节点的节点指针,当不存在左(或右)子节点时,Left(或Right)为NULL。

5.1.2.1 查找最小节点

要在一颗二叉搜索树中查找最大值或最小值,一直往右或往左走即可。这里只给出查找最小节点的程序,查找最大节点类似,下面代码中的Left换成Right即可;注意边界条件的判断也相当重要,尤其在面试时,不可忘记!!!

// 递归实现
Node* findMin(Node* T)
{
    // 边界条件判断
    if(T == NULL)
        return NULL;
    else if(T->Left == NULL)
        return T;
    else
        return findMin(T->Left);
}

// 非递归实现
Node* findMin(Node* T)
{
    if(T == NULL)
        return NULL;
    while(T->Left != NULL)
    {
        T = T->Left;
    }
    return T;
}

这里找到了最小的节点(Node* node),那么结构体中的数据轻而易得(node->key)!

5.1.2.2 插入

插入新元素到二叉搜索树中的规则很简单:从根节点开始,遇到键值大的(即新元素的值<节点的键值)往左走,遇到键值小的往右走。

// 递归实现
Node* insert(Node* T, int x)
{
    if(!T)// T == NULL
    {// 空树->构造一个节点
        T = malloc(sizeof(Node));
        if(T){
            T->key = x;
            T->Left = NULL;
            T->Right = NULL;
            return T;
        }else{
            //FetalError("Out of space!");
        }
    }

    if(x < T->key)      // 向左走
        insert(T->Left, x);
    else if(x > T->key) // 向右走
        insert(T->Right, x);

    return T;  
}

// 非递归实现
Node* insert(Node* T, int x)
{
    if(!T)// T == NULL
    {// 空树->构造一个节点
        T = malloc(sizeof(Node));
        if(T){
            T->key = x;
            T->Left = NULL;
            T->Right = NULL;
            return T;
        }else{
            //FetalError("Out of space!");
        }
    }

    while(x != T->key)
    {
        if(x < T->key)
            T = T->Left;
        else
            T = T->Right;

        if(!T){// 判断是否到达尾端
            T = malloc(sizeof(Node));
            T->key = x;
            T->Left = T->Right = NULL;
            break;
        }
    }

    return T;
}

5.1.2.3 删除

图5-6是二叉搜索树的元素移除操作图解。欲删除旧节点A,有两种情况:

  • 情形1:节点A(当前根节点)只有一个子节点。即要么有左子节点,要么有子节点;那么,仅需把该子节点连至A节点的父节点,而后再删除节点A;
  • 情形2:节点A(当前根节点)有两个子节点。根据二叉搜索树的性质,左子树所有节点的键值 < 根节点的键值 < 右子树所有节点的键值;那么,欲删除旧节点A,需找到右子树中的最小元素节点(使用findMin函数),而后更新旧节点A的键值(不需要更新指向子节点的指针),最后递归调用delete函数删除右子树的最小元素的节点并更新旧节点A的右子树的根节点(A->Right)。

程序如下:

// 《数据结构和算法分析——C语言描述》,该方法永远返回根节点
Node* Delete(Node* T, int x)
{
    Node* tmpNode;
    // 依然是边界条件判断
    if(!T)
        return NULL;
    else{// 先找到要删除元素的节点
        if(x < T->key)
            T->Left = delete(T->Left, x);
        else if(x > T->key)
            T->Right = delete(T->Right, x);
        else{// 找到,要删除的节点为T
            if(T->Left && T->Right){// 2个孩子
                tmpNode = findMin(T->Right);// 复制一份
                T->key = tmpNode->key;
                T->Right = Delete(T->Right, T->key);
            }else{ // 0或1个孩子
                tmpNode = T; // 复制一份
                if(!T->Left)
                    T = T->Right;
                else if(!T->Right)
                    T = T->Left;
                free(tmpNode);
            }
        }

    }
    return T;
}   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值