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

最后更新: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
}
posted @ 2017-12-18 21:13  洒水先生  阅读(128)  评论(0编辑  收藏  举报