• 数据结构-树(中)-二叉搜索树


    最后更新:2017-12-18

    前言

    此文内容来自于 中国大学Mooc(慕课)-浙江大学-数据结构-第四讲-树(中), 老师原本内容是 C语言,本文把内容改为Swift.

    1.1 定义

    二叉搜索树又称二叉排序树或二叉查找树; 当该树不为空的时候,满足如下性质:

    • 非空 左子树所有键值小于其根节点的 键值;
    • 非空 右子树所有键值大于其根节点的 键值;
    • 左右子树都是二叉搜索树

    如下图:

    2.1 二叉搜索树操作函数

    二叉搜索树的操作函数:

    • 查找某个元素返回节点地址;
    • 查找最小/最大元素返回节点地址;
    • 插入某个元素(Insert);
    • 删除某个元素(delete);

    2.1.1 查找某个元素值

    步骤:

    1. 查找从根节点开始, 如果树为空, 返回 nil
    2. 非空树, 则根节点值与X相比较
    • 如果 X 与根节点值相等(==), 搜索完成,返回此节点的地址;
    • 如果 X 比根节点值小(<), 只需在 左子树 中继续搜索;
    • 如果 X 比根节点值大(>), 只需在 右子树 中继续搜索;

    递归方式

    为了使函数有更好的扩展性, 此处使用了泛型

    //  Swift 语言实现
    
    class Node <Element> {
        
        var value : Element
        var left : Node?
        var right : Node?
        
        init(value : Element) {
            self.value = value
        }
    }
    
    func find <T : Comparable> (_ value : T, in tree: Node<T>?) -> Node<T>? {
            guard let node = tree else { return nil }
            
            if value == node.value {
                return node
            } else if value < node.value {
                return find(value, in: node.left) // 尾递归
            } else {
                return find(value, in: node.right) // 尾递归
            }
    }
    

    更多尾递归信息可参考: http://www.ruanyifeng.com/blog/2015/04/tail-call.html

    迭代函数

    func iterFind <T: Comparable>(_ value : T, in tree: Node<T>?) -> Node<T>? {
        var tmpNode = tree
        while let node = tmpNode {
            if value == node.value {
                return node
            } else if value < node.value {
                tmpNode = node.left
            } else {
                tmpNode = node.right
            }
        }
        return nil
    }   
    

    2.1.2 查找最大最小值

    根据二叉树的特性,我们很容易得到:

    • 最大元素 一定是在树的最右分枝的端节点
    • 最小元素 一定是在树的最左分枝的端节点

    // 最大值迭代方式实现
    func findMaxNode<T : Comparable>(in tree: Node<T>?) -> Node<T>? {
        guard var node = tree else { return nil }
        
        while let right = node.right {
            node = right
        }
        return node
    }
    
    // 最小值采用递归方式
     func findMinNode<T : Comparable>(in tree: Node<T>?) -> Node<T>? {
        guard let node = tree else { return nil }
        if node.left == nil {
            return node
        } else {
            return findMinNode(in: node)
        }
    }
    

    练习: 实现最大值采用递归方式 以及 最小值采用迭代方式


    2.1.3 插入(Insert)某个元素

    与查找相似,需要找到对应的位置. 然后递归/循环来处理。

    // 递归
    func insert<T:Comparable>(_ node: Node<T> , in tree : Node<T>?) -> Node<T> {
        guard let tree = tree else { return node }
        if node.value < tree.value {
            tree.left = insert(node, in: tree.left)
        } else if node.value > tree.value {
            tree.right = insert(node, in: tree.right)
        } else {
            fatalError("Node value can not be equal")
        }
        return tree
    }
    

    2.1.4 删除(delete)某个元素

    删除元素需要考虑三种情况:

    1. 删除的是叶节点,即没有子节点的节点;

      • 直接删除, 然后将其父节点的指针置空,
    2. 删除只有一个子节点的节点;

      • 将其父节点指向其子节点
    3. 删除具有左右子树的节点。

      • 左边最大的节点 或者 右边最小的节点来替换,然后删除被替换的节点
    // 删除某个节点
    func delete<T:Comparable>(_ node: Node<T> , in tree : Node<T>?) -> Node<T>? {
        guard var tree = tree else {
            print("Tree 没有, 找不到对应的Node")
            return nil
        }
        
        if node.value < tree.value {
            tree.left = delete(node, in: tree.left)
        } else if node.value > tree.value {
            tree.right = delete(node, in: tree.right)
        } else {
            // 左右都不为空,取右边的最小值
            if tree.left != nil && tree.right != nil {
                guard let rightMinNode = findMinNode(in: tree.right) else {
                    return tree
                }
                
                // 将节点的值替换
                tree.value = rightMinNode.value
                
                // 删除右边最小的节点
                tree.right = delete(rightMinNode, in: tree.right)
            } else if tree.left != nil {
                // 一个左节点, 直接置空就好了
                tree.left = nil
                
            } else if tree.right != nil {
                // 一个右节点, 直接置空就好了
                tree.right = nil
            } else {
                
                // 两个节点都为nil
                return nil
            }
        }
        return tree
    }
    
  • 相关阅读:
    云原生时代已来,计算机教育如何因「云」而变?
    征文投稿丨在轻量应用服务器上部署SpringBoot项目
    无影云电脑支持企业快速实现居家办公
    投稿开奖丨轻量应用服务器征文活动(2月)奖励公布
    使用云服务器ECS搭建DoH服务的开发实践
    深度解读「无影云电脑远程办公解决方案」
    三步搞定android应用底部导航栏
    问题总结211118至220208
    在centos5中配置yum源
    Android开发环境搭建(各种问题,各种解决)
  • 原文地址:https://www.cnblogs.com/gaox97329498/p/12070238.html
Copyright © 2020-2023  润新知