【JavaScript】二叉查找树(BST)

文章目录

原理

二叉查找树,又称二叉排序树,二叉搜索树。二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

  • 若左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  • 若右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  • 左、右子树也分别为二叉排序树;
  • 没有键值相等的节点。

遍历方式:

  • 中序:按照节点键值,以升序的方式遍历树所有节点
  • 先序:先访问根节点,然后在以同样的方式访问左子树和右子树
  • 后序:先访问子节点,从左子树到右子树,最后访问根节点

查找方式:

  • 查找给定值
  • 查找最小值
  • 查找最大值

复杂度:O(logn)

实现

<script>
    // 节点对象
    class Node {
      constructor(data) {
        this.root = this;
        this.data = data;
        this.left = null;
        this.right = null;
      }
    }

    // 二叉树
    class BinarySearchTree {
        constructor() {
            this.root = null;
        }

        /**
         * insert 递归插入节点
         * @param {[ type ]} data [description]
         * @return {[ void ]}  [description]
         */
        insert(data) {
            let newNode = new Node(data);
            let insertNode = (node, newNode) => {
                if (newNode.data < node.data) {
                    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)
                    }
                }
            };

            if (!this.root) {
            this.root = newNode;
            } else {
            insertNode(this.root, newNode)
            }
        }

        /* 中序遍历 =>
        1.访问左子树(先访问左子树中的左子树,再访问左子树中的右子树);
        2.访问根
        3.访问右子树(先访问右子树中的左子树,再访问右子树中的右子树)
 
        可以起到排序作用
        
        * [inOrderTraverse 中序遍历]
        * @return {[ Array ]} [description]
        */
        inOrderTraverse() {
            let backs = [];
            let inOrderNode = (node, callback) => {
                if (node !== null) {
                    inOrderNode(node.left, callback);
                    backs.push(callback(node.data));
                    inOrderNode(node.right, callback);
                }
            }

            let callback = function (v) {
                return v
            }
            inOrderNode(this.root, callback);
            return backs
        }

        /**
        * 前序遍历 => 1.访问根节点; 2.访问左子树; 3.访问右子树
        * [preOrderTraverse 先序遍历]
        * @return {[ Array ]} [description]
        */
        preOrderTraverse() {
            let backs = [];
            let preOrderNode = (node, callback) => {
                if (node !== null) {
                    backs.push(callback(node.data));
                    preOrderNode(node.left, callback);
                    preOrderNode(node.right, callback);
                }
            }
            let callback = function (v) {
                return v
            }
            preOrderNode(this.root, callback);
            return backs
        }

        /* 后序遍历 =>
            1.访问左子树。(先访问左子树中的左子树,再访问左子树中的右子树)
            2.访问右子树。(先访问右子树中的左子树,再访问右子树中的右子树)
            3.访问根
        */
        postOrderTraverse() {
            let backs = [];
            const postOrderNode = (node, callback) => {
	            if (node !== null) {
	                postOrderNode(node.left, callback);
	                postOrderNode(node.right, callback);
	                backs.push(callback(node.data))
	            }
            };

            let callback = function (v) {
            return v
            }
            postOrderNode(this.root, callback);
            return backs
        }

        // 查找最小值
        getMin(node) {
            let minNode = node => {
                return node ? (node.left ? minNode(node.left) : node) : null
            }
            return minNode(node || this.root)
        }

        // 查找最大值
        getMax(node) {
            let maxNode = node => {
                return node ? (node.right ? maxNode(node.right) : node) : null
            }
            return maxNode(node || this.root)
        }

        // 查找特定值
        find(data) {
            let findNode = (node, data) => {
            if (node == null) return false
            if (node.data === data) return node;
                return findNode((data < node.data) ? node.left : node.right, data);
            }
            return findNode(this.root, data);
        }

        // 删除节点
        // 返回新的二叉树?
        remove(data) {
            let removeNode = (node, data) => {
	            if (node === null) return null;
	            if (node.data === data) {
	                if (node.left === null && node.right === null) return null
	                if (node.left === null) return node.right;
	                if (node.right === null) return node.left;
	                if (node.left !== null && node.right !== null) {
	                let _node = this.getMin(node.right);
	                node.data = _node.data;
	                node.right = removeNode(node.right, data);
	                return node
	                }
	            } else if (data < node.data) {
	                node.left = removeNode(node.left, data);
	                return node;
	            } else {
	                node.right = removeNode(node.right, data);
	                return node;
	            }
            }
            return removeNode(this.root, data)
        }
    }
</script>

验证

    let datas = [11, 7, 5, 3, 6, 9, 8, 10, 20, 14, 12, Tree25, 18];
    let bst = new BinarySearchTree();
    datas.forEach(data => {
      BinarySearchTree.insert(data)
    })

    console.log(BinarySearchTree.getMax())
    console.log(BinarySearchTree.getMin())
    console.log(BinarySearchTree)
    console.log(BinarySearchTree.remove(20))
    console.log(BinarySearchTree)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值