美文网首页
算法学习--二叉搜索树接口设计

算法学习--二叉搜索树接口设计

作者: 清风徐云去 | 来源:发表于2019-09-25 14:18 被阅读0次
二叉树-1.png
    function BinaryTree() {
        //构建二叉树结构
        let Node  = function(key){
            this.key = key;
            this.left = null;
            this.right = null;
        }
        //创建二叉树根节点
        let root = null;
        /**
         * [insertNode description]插入数据方法
         * @param  {[type]} node    [description]
         * @param  {[type]} newNode [description]
         * @return {[type]}         [description]
         */
        let insertNode = function(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);
                }
            }
        }
        /**
         * [insert description]插入数据操作
         * @param  {[type]} key [description]
         * @return {[type]}     [description]
         */
        this.insert = function(key){
            let newNode = new Node(key);
            if(root === null){
                //根节点为空时,直接将此数据作为根节点
                root = newNode;
            }else{
                //否则排序插入数据
                insertNode(root, newNode);
            }
        }
        /**
         * [inOrderTraverseNode description]中序遍历排序方法(顺序:左-父-右),遇到父节点,先进入左子树,再进入右子树,当右子树遍历完成时,返回父节点
         * @param  {[type]}   node     [description]
         * @param  {Function} callback [description]
         * @return {[type]}            [description]
         */
        let inOrderTraverseNode = function(node, callback){
            if(node !== null){
                inOrderTraverseNode(node.left, callback);
                callback(node.key);
                inOrderTraverseNode(node.right, callback);
            }
        }
        /**
         * [inOrderTraverse description]中序遍历排序
         * @param  {Function} callback [description]
         * @return {[type]}            [description]
         */
        this.inOrderTraverse = function(callback){
            inOrderTraverseNode(root, callback);
        }
        /**
         * [preOrderTraverseNode description]前序遍历方法(顺序:父-左-右),先打印当前父节点,然后进入父节点的左子树进行打印,当左子树没有下层左子树时,再进入右子树进行打印,右子树没有下层左子树和右子树时,返回父节点
         * @param  {[type]}   node     [description]
         * @param  {Function} callback [description]
         * @return {[type]}            [description]
         */
        let preOrderTraverseNode = function(node, callback){
            if(node !== null){
                callback(node.key);
                preOrderTraverseNode(node.left, callback);
                preOrderTraverseNode(node.right, callback);
            }
        }

        /**
         * [preOrderTraverse description]前序遍历
         * @param  {Function} callback [description]
         * @return {[type]}            [description]
         */
        this.preOrderTraverse = function(callback){
            preOrderTraverseNode(root, callback);
        }
        /**
         * [postOrderTraverseNode description]后序遍历方法(顺序:左-右-父)
         * @param  {[type]}   node     [description]
         * @param  {Function} callback [description]
         * @return {[type]}            [description]
         */
        let postOrderTraverseNode = function(node, callback){
            if(node !== null){
                postOrderTraverseNode(node.left, callback);
                postOrderTraverseNode(node.right, callback);
                callback(node.key);
            }
        }
        /**
         * [postOrderTracerse description]后序遍历
         * @param  {Function} callback [description]
         * @return {[type]}            [description]
         */
        this.postOrderTracerse = function(callback){
            postOrderTraverseNode(root, callback);
        }
        /**
         * [minNode description]查找最小值方法
         * @param  {[type]} node [description]
         * @return {[type]}      [description]
         */
        let minNode = function(node){
            if(node) {
                while(node && node.left !== null){
                    node = node.left;
                }
                return node.key;
            }
        }
        /**
         * [min description]查找最小值
         * @return {[type]} [description]
         */
        this.min = function(){
            return minNode(root);
        }
        /**
         * [maxNode description]查找最大值方法
         * @param  {[type]} node [description]
         * @return {[type]}      [description]
         */
        let maxNode = function(node) {
            if(node){
                while(node && node.right !== null){
                    node = node.right;
                }
                return node.key;
            }
        }
        /**
         * [max description]查找最大值
         * @return {[type]} [description]
         */
        this.max = function() {
            return maxNode(root);
        }
        /**
         * [searchNode description]查找值方法
         * @param  {[type]} node [description]
         * @param  {[type]} key  [description]
         * @return {[type]}      [description]
         */
        let searchNode = function(node, key){
            if(node == null){
                return false;
            }
            if(key < node.key){
                return searchNode(node.left, key);
            }else if(key > node.key){
                return searchNode(node.right, key);
            }else{
                return true;
            }
        }
        /**
         * [search description]查找对应值
         * @param  {[type]} key [description]
         * @return {[type]}     [description]
         */
        this.search = function(key){
            return searchNode(root, key);
        }
        /**
         * [findMinNode description]查找最小值并返回该对象(上面的查找最小值返回的是数值)
         * @param  {[type]} node [description]
         * @return {[type]}      [description]
         */
        let findMinNode = function(node){
            if(node){
                while(node && node.left !== null){
                    node  = node.left;
                }
                return node;
            }
            return null;
        }
        /**
         * [removeNode description]删除方法
         * @param  {[type]} node [description]
         * @param  {[type]} key  [description]
         * @return {[type]}      [description]
         */
        let removeNode = function(node, key){
            //情况一:删除最底层节点。判断在根节点左子树还是右子树,再依次对节点的左子树或右子树进行对比,找到对应节点后删除并返回删除后的二叉树,找不到就返回null。如删除1,1先跟根节点8对比,比8小(key < node.key),进入左子树中,此时再将3当做父节点再次调用removeNode方法,直到找到节点为1的值进行匹配。如果找到匹配值,就进入if(node.left === null && node.right === null)判断中,通过设置当前节点node为null删除该节点,return node将删除的节点null return给父节点3,,父节点3再将自身的节点情况通过return node return给跟父节点8(return node在递归调用removeNode的之后,也是递归返回的,如不理解,可以将注释的node节点打印放开,断点调试即可),这样,就将整个删除节点后的二叉树都返回回去了。
            //情况二:删除的节点是含有单侧子节点的父节点。左子树节点(只有左子树子节点):删除该节点后,将该节点下的左子树节点指针替换为该节点指针;右子树节点(只有右子树子节点):删除该节点后,将该节点的右子树节点指针替换为该节点指针
            //情况三:删除的节点有左右两个子节点父节点。找到该父节点下右子树中的最小值节点,将该父节点的值更新为最小值节点的值,最后删除最小值节点并返回删除后的二叉树
            
            if(node === null)return null;
            if(key < node.key) {
                node.left = removeNode(node.left, key);
                                // console.log('node-- ',node)
                return node;
            }else if(key > node.key) {
                node.right = removeNode(node.right, key);
                                // console.log('node-- ',node)
                return node;
            }else {
                if(node.left === null && node.right === null){
                    node = null;
                                        // console.log('node-- ',node)
                    return node;
                }
                if(node.left === null){
                    node = node.right;
                    return node;
                }else if(node.right === null){
                    node = node.left;
                    return node;
                }

                let aux = findMinNode(node.right);
                node.key = aux.key;
                node.right = removeNode(node.right, aux.key);
                return node;
            }
        }
        /**
         * [remove description]删除
         * @param  {[type]} key [description]
         * @return {[type]}     [description]
         */
        this.remove = function(key){
            root = removeNode(root, key);
        }

    }

    let nodes = [8, 3, 10, 1, 6, 14, 4, 7, 13];
    let binaryTree = new BinaryTree();
    nodes.forEach(function(key) {
        binaryTree.insert(key);
    })

    let callback = function(key){
        console.log(key);
    }
    
    // binaryTree.inOrderTraverse(callback);
    // binaryTree.preOrderTraverse(callback);
    binaryTree.postOrderTracerse(callback);
    console.log('min is ', binaryTree.min());
    console.log('max is ', binaryTree.max());
    console.log('search 7', binaryTree.search(7));
    console.log('search 100', binaryTree.search(100));
    binaryTree.remove(1) //删除情况一
    binaryTree.remove(10) //删除情况二
    binaryTree.remove(4) //删除情况三

相关文章

网友评论

      本文标题:算法学习--二叉搜索树接口设计

      本文链接:https://www.haomeiwen.com/subject/uryructx.html