数据结构——排序二叉树

类型

  • 二叉树(Binary Tree):每个节点最多含有两个子节点。
  • 满二叉树(Full Binary Tree):在满二叉树中,每个不是尾结点的节点都有两个子节点
  • 完全二叉树(Complete Binary Tree):假设一个二叉树的深度(depth) 为d(d>1),除了第d层外,其他各层的节点数量均已达到最大值,且第d层所有节点从左向右紧密排列,这样的二叉树就是完全二叉树。
  • 排序二叉树(Binary Search Tree):在此树中,每个节点的数值比左子树的每个节点都大,比所有右子树上的节点都小。
  • 平衡二叉树(AVL Tree):任何节点的两颗子树的高度差不大于1的排序二叉树。
  • B树(B-Tree):B树和平衡二叉树一样,只不过它是一种多叉树(一个节点的子节点数量可以超过二)
  • 红黑树(Red-Black Tree):是一种自平衡二叉寻找树

排序二叉树实现

class TreeNode {
    val: number
    left: TreeNode | null
    right: TreeNode | null
    constructor(val: number) {
        this.val = val
        this.left = this.right = null
    }

    show () {
        return this.val
    }
}

class BST {
    root: null | TreeNode
    constructor() {
        this.root = null
    }

    insert (val: number): void {
        if (!val) {
            return
        }
        const node = new TreeNode(val)
        if (!this.root) {
            this.root = node
            return
        }
        let current = this.root
        let parent = null
        while (current) {
            parent = current
            if (val < current.val) {
                current = current.left
                if (!current) {
                    parent.left = node
                }
            } else {
                current = current.right
                if (!current) {
                    parent.right = node
                }
            }
        }
    }

    remove (val: number): boolean {
        if (!val) {
            return false
        }
        let { root } = this
        let current = root
        let parent = null
        let isLeftChild = false

        while (current && current.val !== val) {
            parent = current
            if (val < current.val) {
                current = current.left
                isLeftChild = true
            } else {
                current = current.right
                isLeftChild = false
            }
        }

        if (!current) {
            return false
        }

        // 1.删除的元素没有子元素
        if (!current.left && !current.right) {
            if (current === root) {
                root = null
            } else {
                isLeftChild ? (parent.left = null) : (parent.right = null)
            }
        }

        // 2.删除的元素只有一个子元素
        else if (!current.left) {
            if (current === root) {
                root = current.right
            } else {
                isLeftChild ? (parent.left = current.right) : (parent.right = current.right)
            }

        } else if (!current.right) {
            if (current === root) {
                root = current.left
            } else {
                isLeftChild ? (parent.left = current.left) : (parent.right = current.left)
            }
        }

        // 3. 被删除的元素有两个子元素
        else {
            const successor = this.getSuccessor(current)
            if (current === root) {
                root = successor
            } else {
                isLeftChild ? (parent.left = successor) : (parent.right = successor)
            }
            // 将被删除的元素的右边赋值给新节点的右边
            successor.right = current.right
        }
        return true
    }

    /**
     * 
     * @param node 被删除的元素
     * @description 返回被删除元素左边最大的子元素
     */
    private getSuccessor (node: TreeNode): TreeNode {
        let successor = null
        let successorPerent = null
        let current = node.left
        while (current) {
            successorPerent = successor
            successor = current
            current = current.right
        }
        if (successor !== node.left) {
            successorPerent.right = successor.left
            successor.left = node.left
        }
        return successor
    }

    search (val: number): TreeNode | null {
        if (!val) {
            return null
        }
        let current = this.root
        let parent = null
        while (current && current.val !== val) {
            parent = current
            if (val < current.val) {
                current = current.left
            } else if (val > current.val) {
                current = current.right
            }
        }
        return current ? current : null
    }

    /**
     * 
     * @param node 
     * @param arr 
     * @description 自己 -> 左 -> 右
     */
    preOrder (node?: TreeNode, arr?: number[]): number[] {
        if (!node && !arr) {
            node = this.root
        }
        arr = arr ? arr : []
        if (node) {
            arr.push(node.val)
            this.preOrder(node.left, arr)
            this.preOrder(node.right, arr)
            return arr
        }
    }

    /**
     * 
     * @param node 
     * @param arr 
     * @description  左 -> 自己 -> 右
     */
    inOrder (node?: TreeNode, arr?: number[]): number[] {
        if (!node && !arr) {
            node = this.root
        }
        arr = arr ? arr : []
        if (node) {
            this.inOrder(node.left, arr)
            arr.push(node.val)
            this.inOrder(node.right, arr)
            return arr
        }
    }

    /**
     * 
     * @param node 
     * @param arr 
     * @description 左 -> 右 -> 自己
     */
    postOrder (node?: TreeNode, arr?: number[]): number[] {
        if (!node && !arr) {
            node = this.root
        }
        arr = arr ? arr : []
        if (node) {
            this.postOrder(node.left, arr)
            this.postOrder(node.right, arr)
            arr.push(node.val)
            return arr
        }
    }

    /**
     * 
     * @param node 查找的节点
     * @param deep 累加的层数
     * @description 查找当前树的层级,不传参表示从根节点开始数
     */
    getDeep (node?: TreeNode, deep?: number): number {
        if (!node && !deep) {
            node = this.root
        }
        deep = deep || 0
        if (!node) {
            return deep
        }

        deep++;
        let deepLeft = this.getDeep(node.left, deep)
        let deepRight = this.getDeep(node.right, deep)
        return Math.max(deepLeft, deepRight)
    }

    getMin (): number {
        let current = this.root
        while (current) {
            if (!current.left) {
                return current.val
            }
            current = current.left
        }
    }

    getMax (): number {
        let current = this.root
        while (current) {
            if (!current.right) {
                return current.val
            }
            current = current.right
        }
    }
}

遍历

  • Pre-order Traveral:先访问节点自己,然后访问左子树,最后再访问右子树
  • In-order Traveral: 先访问左子树上的节点,再访问自己,最后再访问右子树的节点, 结合排序二叉树 可以从小到大排序
  • Post-order Traveral: 先访问左右子树,最后访问自己

测试一下

var bst = new BST()
bst.insert(8)
bst.insert(1)
bst.insert(3)
bst.insert(2)
bst.insert(14)
bst.insert(11)
bst.insert(9)
bst.insert(10)
bst.insert(13)
bst.insert(12)
bst.insert(18)

bst.inOrder() // [1, 2, 3, 8, 9, 10, 11, 12, 13, 14, 18]
bst.preOrder() // [8, 1, 3, 2, 14, 11, 9, 10, 13, 12, 18]
bst.postOrder() // [2, 3, 1, 10, 9, 12, 13, 11, 18, 14, 8]

参考资料