数据结构-二叉搜索树

二叉搜索树:BST(Binary Search Tree)

二叉搜索树是二叉树,可以为空,如果不为空,满足以下性质:

  • 非空左子树的所有键值小于其根节点的键值
  • 非空右子树的所有键值大于其根节点的键值
  • 左、右字数本身也都是二叉搜索树

二叉搜索树的特点:

  • 二叉搜索树的特点就是相对较小的值总是保存在左节点上,相对较大的值总是保存在右节点上
  • 查找效率非常高

二叉搜索树常见的操作:

  • insert(key, value):向树中插入数据
  • search(key):在树中查找
  • remove(key):从树中移除
  • update(key,value):修改节点数据
  • inOrderTraverse:通过中序遍历方式遍历所有节点
  • preOrderTraverse:通过先序遍历方式遍历所有节点
  • postOrderTraverse:通过后序遍历方式遍历所有节点
  • min:返回树中最小的键/值
  • max:返回树中最大的键/值
javascript 复制代码
class Node {
    constructor(key) {
        this._key = key;
        this._left = null;
        this._right = null;
    }
}
class BinarySearchTree {
    constructor() {
        this._root = null;
    }
    
    insert(key) {
        const insertNode = (node, newNode) => {
            if(newNode._key <= node._key) {
                if(node._left === null) {
                    node._left = newNode;
                } else {
                    insertNode(node._left, newNode);
                }
            } 
            else {
                if(node._right === null) {
                    node._right = newNode;
                } else {
                    insertNode(node._right, newNode);
                }
            }
        }
        const newNode = new Node(key)
        if (this._root === null) {
            this._root = newNode
        } else {
            insertNode(this._root, newNode)   
        }

    }

    preOrderTraverse(handler = (value) => {console.log(value)}) {
        const preOrderTraverseNode = (node) => {
            if (node === null) {
                return 
            }
            handler(node._key)
            preOrderTraverseNode(node._left)
            preOrderTraverseNode(node._right)
            
        }
        preOrderTraverseNode(this._root)
    }

    midOrderTraverse(handler = (value) => {console.log(value)}) {
        const midOrderTraverseNode = (node) => {
            if (node === null) {
                return 
            }
            midOrderTraverseNode(node._left)
            handler(node._key)
            midOrderTraverseNode(node._right)
            
        }
        midOrderTraverseNode(this._root)
    }

    postOrderTraverse(handler = (value) => {console.log(value)}) {
        const postOrderTraverseNode = (node) => {
            if (node === null) {
                return 
            }
            postOrderTraverseNode(node._left)
            postOrderTraverseNode(node._right)
            handler(node._key)
            
        }
        postOrderTraverseNode(this._root)
    }

    min() {
        if (this._root === null) {
            return null
        }
        let node = this._root
        while(true) {
            if (node._left === null) {
                return node._key
            }
            node = node._left
        }
    }

    max() {
        if (this._root === null) {
            return null
        }
        let node = this._root
        while(true) {
            if (node._right === null) {
                return node._key
            }
            node = node._right
        }
    }

    search(key) {
        const searchNode = (node, key) => {
            if (node === null) {
                return false
            }

            if (node._key === key) {
                return true
            }

            if (key < node._key) {
                return searchNode(node._left, key)
            } else {
                return searchNode(node._right, key)
            }
        }

        return searchNode(this._root, key)
    }

    remove(key) {
        if (this._root === null) {
            return false
        }
        let current = this._root
        let parent = null
        let isLeftChild = true
        while (current._key !== key) {
            parent = current
            if (key < current._key) {
                isLeftChild = true
                current = current._left
            } else {
                isLeftChild = false
                current = current._right
            }
            if (current === null) {
                return false
            }
        }

        

        // 删除叶子节点
        if (current._left === null && current._right === null) {
            if (current === this._root) {
                this._root = null
            } else {
                if (isLeftChild) {
                    parent._left = null
                } else {
                    parent._right = null
                }
            }
        }

        // 删除有一个子节点

        else if (current._left === null ) {
            if (current === this._root) {
                this._root = current._right
            } else if (isLeftChild) {
                parent._left = current._right
            } else {
                parent._right = current._right
            }

        } else if (current._right === null) {
            if (current === this._root) {
                this._root = current._left
            } else if (isLeftChild) {
                parent._left = current._left
            } else {
                parent._right = current._left
            }
        } 


        else {
            const getExChangeTargetNode = (current) => {
                let node = current._right
                let parentNode = current
                let isRightClick = true
                while(true) {
                    if (node._left === null) {
                        if (isRightClick)  {
                            parentNode._right = node._right
                        } else  {
                            parentNode._left = node._right
                        }
                        return node
                    }
                    isRightClick = false
                    parentNode = node
                    node = node._left
                }
            }

            const targetNode = getExChangeTargetNode(current);
            if (current !== this._root) {
                if (isLeftChild)  {
                    parent._left = targetNode
                } else  {
                    parent._right = targetNode
                }
            } else {
                this._root = targetNode
            }

            targetNode._right = current._right
            targetNode._left = current._left
            
        }

        return true
    }

}
相关推荐
前端爆冲7 分钟前
项目中无用export的检测方案
前端
旧味清欢|18 分钟前
关注分离(Separation of Concerns)在前端开发中的实践演进:从 XMLHttpRequest 到 Fetch API
javascript·http·es6
逸狼32 分钟前
【Java 优选算法】二分算法(下)
数据结构
热爱编程的小曾35 分钟前
sqli-labs靶场 less 8
前端·数据库·less
gongzemin1 小时前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox1 小时前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
-代号95271 小时前
【JavaScript】十四、轮播图
javascript·css·css3
树上有只程序猿1 小时前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼2 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX187302 小时前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式