数据结构-二叉搜索树

二叉搜索树: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
    }

}
相关推荐
API_technology2 分钟前
电商API安全防护:JWT令牌与XSS防御实战
前端·安全·xss
yqcoder7 分钟前
Express + MongoDB 实现在筛选时间段中用户名的模糊查询
java·前端·javascript
十八朵郁金香28 分钟前
通俗易懂的DOM1级标准介绍
开发语言·前端·javascript
计算机小白一个1 小时前
蓝桥杯 Java B 组之背包问题、最长递增子序列(LIS)
java·数据结构·蓝桥杯
GDAL1 小时前
HTML 中的 Canvas 样式设置全解
javascript
m0_528723812 小时前
HTML中,title和h1标签的区别是什么?
前端·html
Dark_programmer2 小时前
html - - - - - modal弹窗出现时,页面怎么能限制滚动
前端·html
GDAL2 小时前
HTML Canvas clip 深入全面讲解
前端·javascript·canvas
禾苗种树2 小时前
在 Vue 3 中使用 ECharts 制作多 Y 轴折线图时,若希望 **Y 轴颜色自动匹配折线颜色**且无需手动干预,可以通过以下步骤实现:
前端·vue.js·echarts
卑微的小鬼2 小时前
数据库使用B+树的原因
数据结构·b树