二叉搜索树

1 二叉搜索树简介

二叉搜索树(Binary Search Tree)一般结构:

struct TreeNode {
    int val;         //节点值
    TreeNode *parent;//指向父节点
    TreeNode *left;  //指向左子树
    TreeNode *right; //指向右子树
    TreeNode(int x) : val(x), parent(NULL),left(NULL), right(NULL) {}
};

性质:对于任意节点,左子树的节点值都小于该节点值,右子树的节点值均大于该节点值。

根据该性质,对二叉搜索树做中序遍历便可以顺序(由大到小或由小到大)输出树中所有节点值。

对于一颗高为 h 的二叉搜索树,对二叉树的操作查询、最小、最大、后继、前驱、插入、删除的时间复杂度均为O(h)

2 查询

查询某元素、最大最小值、前驱后继

2.1 查询某元素

在二叉搜索树中查询某个元素k。

  • 若k大于当前节点值,则搜索其右子树;
  • 若k小于当前节点值,则搜索其左子树;
  • 若k等于当前节点值或当前节点为空,返回当前节点。

递归版本伪代码:

node初始化为树的根节点root

//输入:node为当前子树的根节点,k为待搜索的节点值
//输出:搜索到的节点
TREE-SEARCH(node,k)
    if(node==NULL || k==node->val)
        then return node
    if(k<node->val)
        return TREE-SEARCH(node->left,k)
    else
        return TREE-SEARCH(node->right,k)

非递归版本伪代码:

TreeNode* ITERATIVE-TREE-SEARCH(TreeNode *node,int k)
    while(k!=node->val && node != NULL)
        if(k<node->val)
            node=node->left
        else node=node->right
    return node

2.2 最大最小节点值

最大节点值:二叉搜索树最右下方节点值即是树中最大节点值
最小节点值:二叉搜索树最左下方节点值即使树中最小节点值

最大节点值伪代码:

//输入:node为当前子树的根节点
//输出:该子树最大值节点
TreeNode* TREE-MINIMUM(TreeNode* node)
    while(node->right != NULL)
        node=node->right
    return node

最小节点值伪代码:

//输入:node为当前子树的根节点
//输出:该子树最小值节点
TreeNode* TREE-MINIMUM(TreeNode* node)
    while(node->left != NULL)
        node=node->left
    return node

2.3 前驱和后继

后继:指节点值大于某节点值的节点中,节点值最小的节点。即,对树进行中序遍历,节点值紧随其后的节点。

求某个节点的后继分为两种情况:

  • 该节点有右子树,则其后继是其右子树最左下方的节点;
  • 该节点无右子树,则其后继节点满足:该节点在后继节点的左子树中,且后继节点是符合条件的最低的父节点。

求节点后继的伪代码:

//输入:待寻找其后继节点的节点
//输出:后继节点
TREE-SUCCESSOR(node)
    if(node->right != NULL)
        return TREE-MINIMUN(node->right)
    tmp=node->parent;
    while(tmp!=NULL and node==tmp->right)
        node=tmp
        tmp=tmp->parent
    return tmp

3 插入和删除

插入和删除需要在保持二叉搜索树性质的情况下,对树进行修改。

3.1 插入

若插入节点小于当前节点值,则插入其子树,大于则插入其子树,直至当前节点为叶节点,则将插入节点变为当前节点的左或右子节点。

向树中插入节点的伪代码:

//输入:root为树的根节点指针,node为当前待插入节点
//输出:更新后树的根节点
TREE-INSERT(root,node)
    cur=root
    leafNode=NULL
    while(cur!=NULL)
        leafNode=cur
        if(node->val>=cur->val)
            cur=cur->right
        else
            cur=cur->left
    node->parent=leafNode//此处本应使用取值符
    if leafNode==NULL
        root=node
    else
        if(node->val>=leafNode->val)
            leafNode->right=node
        else
            leafNode->left=node

3.2 删除

相比插入,删除操作较为复杂。删除操作分为三种情况:

  • 若删除节点为叶子节点,则直接将其删除;
  • 若删除节点只有一个子节点,则用子节点替代删除节点的位置,此处称该子节点为“替代节点”;
  • 若删除节点有两个子节点,则使用其后继节点替代删除节点的位置;

如下图所示的树,若要删除节点8(叶节点),则直接将其删除即可,若删除节点11(一个子节点),则使用其子节点**12替代其位置即可,若要删除节点13(两个子节点),则使用其后继节点**15替代替位置即可。

删除节点伪代码:

/*
* 输入:root为树根节点,node为待删除元素
* 输出:替待元素
*/
TREE-DELETE(root,node)
    //删除替代节点
    if(node->left==NULL or node->right==NULL)//当前节点无子节点或只有一个子节点
        tmp=node
    else                              //当前节点有两个子节点
        tmp=TREE-SECCESSOR(node)      //后继节点无子节点
    if(tmp->left!=NULL)
        childNode=tmp->left           //childNode为删除节点的子节点
    else
        childNode=tmp->right
    if(childNode!=NULL)               //替换节点为后继节点的情况
        childNode->parent=node->parent//设置替代节点的父节点,将替代节点删除
    if(node->parent==NULL)
        root=childNode
    else if(tmp==tmp->parent->left)
            childNode=tmp->parent->left
        else
            childNode=tmp->parent->right
    if(tmp->val!=node->val)
        node->val=tmp->val//拷贝节点的值
    return tmp

参考资料

《算法导论》第12章 二叉查找树

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值