Skip to content

Latest commit

 

History

History
271 lines (252 loc) · 8.4 KB

二叉查找树.md

File metadata and controls

271 lines (252 loc) · 8.4 KB
/**
 * 时间:2019/3/29
 * 公众号: 「一个不甘平凡的码农」
 * 二叉查找树的增、删、改、查
 * 功能:
 * 1)插入数据
 * 2)查找数据
 * 3)删除数据
 * 4)查找最大值
 * 5)查找最小值
 * 6)前、中、后序遍历
 * @author 小鹿
 *
 */

//定义树节点
class Node{
    constructor(data){
        this.data = data;
        this.left = null;
        this.right = null;
    }

    //插入数据
    //步骤:
    // 1、判断是否为空树(是:将数据加入到第一个结点)
    // 2、循环根节点不等于 null
    // 3、判断与根节点的大小
    // 4、判断左/右子树是否为 null
    // 5、递归左子树/递归右子树
    insertValue = (tree,val) =>{
        //封装节点
        let newNode = new Node(val);

        //判断是否为空树
        if(tree === null) {
            tree = newNode;
            return true;
        }else{
            while(tree != null){
                //判断与根节点的大小
                if(newNode.data < tree.data){
                    //判断左子树是否为null
                    if(tree.left == null){
                        tree.left = newNode;
                        return true;
                    }else{
                        tree = tree.left;
                    }
                }else{
                    //val 大于根节点
                    if(tree.right == null){
                        tree.right = newNode;
                        return true;
                    }else{
                        tree = tree.right;
                    }
                }
            }
        }
    }


    //查找数据
    //步骤:
    // 1、判断树是否为 null
    // 2、判断查找数据于根节点大小
    // 3、递归左/右子树
    findData = (tree,val) =>{
        //判断树是否为 null
        if(tree == null){
            return false;
        }

        while(tree !== null){
            //判断查找值与根节点的大小
            if(val == tree.data){
                return tree.data;
            }else if(val < tree.data){
                if(tree.left == null){
                    return false;
                }else{
                    tree = tree.left;
                }
            }else{
                if(tree.right == null){
                    return false;
                }else{
                    tree = tree.right;
                }
            }
        }
    }

    //删除数据
    //步骤:
    // 1、定义两个节点(p用来存放删除节点,pp用来存放删除节点的父节点)
    // 2、遍历树查找要删除的节点(条件:找不到该值/找到了该值)
    // 2、判断是否找到该值
    // 3、判断要删除的树节点子节点个数(无子节点、一个子节点、两个子节点)
    //    1)情况一(节点的两个子节点都不等于null):两个子节点:在右子树先寻找最小值(同时记录最小值的父节点),做数值交换,
    // 然后让删除节点的p指针指向最小值,同时让删除节点的父节点指向删除值的父节点。转化为删除叶子节点问题。
    //    2)情况二(节点的其中一个结点为 null):用 child 存储删除节点的子节点
    //    3)情况三(删除叶子节点):让 child 存储 null
    // 4、对标记好的节点进行删除
    // 5、判断树中只剩下根节点
    // 6、判断父节点下哪个子节点删除了,让父节点直接指向 child
    deleteData = (p,val) =>{
        //定义父节点(记录删除节点的父节点)
        let pp = null;  

        //寻找该删除节点
        while(p !== null && p.data != val){
            //记录删除节点的父节点
            pp = p;
            //判断删除值与根节点大小关系
            if(val > p.data){
                p = p.right;
            }else{
                p = p.left;
            }
        }

        // 如果树为 null 或者找不到该删除节点
        if(p == null){
            return false;
        }

        //情况一:该删除节点有两个子节点
        if(p.left != null && p.right != null ){
            //寻找右子树最小节点(默认右子树最小节点)
            let minP = p.right;
            //记录最小值的父节点
            let minPP = p;
            //判断右子节点是否有左子树
            while(minP.left != null){
                //记录最小节点的父节点
                minPP = minPP;
                //找到最小节点
                minP = minP.left;
            }
            //节点值交换
            p.data = minP.data;
            //最小值节点交换,随之指向删除节点的指针和父节点的指针变换
            p = minP;
            //父节点交换
            pp = minPP;
        }

        //如果为情况一,经上述变换,成为了删除一个叶子节点(情况三)
        //情况二:删除节点是叶子节点或仅有一个节点
        let child = null;
        if(p.left != null){
            child = p.left;
        }else if(p.right != null){
            child = p.right;
        }else{
            //情况三:删除节点为叶子节点
            child = null;
        }

        //对删除节点进行删除操作
        if(pp == null){
            //树的根节点为 null(树中只有一个节点)
            this.tree = child;
        }else if(pp.left == p){
            //该删除节点在父节点的左边的情况
            pp.left = child;
        }else{
            //该删除节点在父节点的右边情况
            pp.right = child;
        }
    }
}

//求树中最大节点
treeMaxNode = (tree)=>{
    // 
    if(tree === null) return false;
    // 
    while(tree.right != null){
        tree = tree.right;
    }
    return tree.data;
}

//求树中最小节点
treeMinNode = (tree)=>{
    // 
    if(tree === null) return false;
    // 
    while(tree.left != null){
        tree = tree.left;
    }
    return tree.data;
}

//遍历二叉查找树
//前序遍历
preorderTraversal = (tree) =>{
    //判断树是否为空
    if(tree == null) return false;
    //根节点
    console.log(tree.data)
    //左子树
    this.preorderTraversal(tree.left)
    //右子树
    this.preorderTraversal(tree.right)
}

//中序遍历
inorderTraversal = (tree) =>{
    //判断树是否为空
    if(tree == null) return false;
    //左子树
    this.inorderTraversal(tree.left);
    //根节点
    console.log(tree.data)
    //右节点
    this.inorderTraversal(tree.right);
}

//后序遍历
postorderTraversal = (tree) =>{
    //判断树是否为空
    if(tree == null) return false;
    //左子树
    this.postorderTraversal(tree.left);
    //右子树
    this.postorderTraversal(tree.right);
    //根节点
    console.log(tree.data)
}

//测试
const tree = new Node(1);
console.log('------------------------------插入数据--------------------------')
tree.insertValue(tree,12)
tree.insertValue(tree,9)
tree.insertValue(tree,24)
tree.insertValue(tree,8)
tree.insertValue(tree,10)
tree.insertValue(tree,13)
tree.insertValue(tree,30)
tree.insertValue(tree,7)
inorderTraversal(tree);
console.log('-----------------------------查找数据--------------------------')
console.log(tree.findData(tree,30))
console.log('-----------------------------删除数据--------------------------')
console.log('--------------------------删除只有一个节点----------------------')
tree.deleteData(tree,8)
inorderTraversal(tree);
console.log('----------------------------删除叶子节点-----------------------')
tree.deleteData(tree,30)
inorderTraversal(tree);
console.log('---------------------------删除有两个节点----------------------')
tree.deleteData(tree,9)
inorderTraversal(tree);
console.log('------------------------------前序遍历-------------------------')
preorderTraversal(tree);
console.log('------------------------------中序遍历-------------------------')
inorderTraversal(tree);
console.log('------------------------------后序遍历-------------------------')
postorderTraversal(tree);
console.log('------------------------------求最大值-------------------------')
console.log(treeMaxNode(tree))
console.log('------------------------------求最小值-------------------------')
console.log(treeMinNode(tree))