Javascript之数据结构与算法的二叉树和二叉搜索树实现

版权声明:转载请注明出处 https://blog.csdn.net/wushichao0325/article/details/86155836

Javascript之数据结构与算法的二叉树和二叉搜索树实现

简介

二叉树中的节点最多只能有两个子节点:一个是左侧子节点,另一个是右侧子节点。
二叉搜索树( BST)是二叉树的一种,但是它只允许你在左侧节点存储(比父节点)小的值,
在右侧节点存储(比父节点)大(或者等于)的值。
中序遍历是一种以上行顺序访问BST所有节点的遍历方式,也就是以从最小到最大的顺序访
问所有节点。
先序遍历是以优先于后代节点的顺序访问每个节点的。先序遍历的一种应用是打印一个结构
化的文档。
后序遍历是先访问节点的后代节点,再访问节点本身。后序遍历的一种应用是计算一个目
录和它的子目录中所有文件所占空间的大小。

代码实现

let insertNode=Symbol();//伪私有函数
let inOrderTraverseNode=Symbol();//中序遍历
let preOrderTraverseNode=Symbol();//先序遍历
let postOrderTraverseNode=Symbol();//后序遍历
let minNode=Symbol();//最小值节点
let maxNode=Symbol();//最大值节点
let searchNode=Symbol();//搜索特定的值
let removeNode=Symbol();//移除一个节点
let findMinNode=Symbol();//搜索某个节点的最小值
class Node{
    constructor(key){
        this.key=key;
        this.left=null;
        this.right=null;
    }
}
class BinarySearchTree{
    constructor(){
        this.root=null;
        this[insertNode]=function(node,newNode){
            if(newNode.key<node.key){
                if(node.left==null){
                    node.left=newNode;
                }else{
                    this[insertNode](node.left,newNode);
                }
            }else{
                if(node.right==null){
                    node.right=newNode;
                }else{
                    this[insertNode](node.right,newNode);
                }
            }
        };
        //中序遍历是一种以上行顺序访问BST所有节点的遍历方式,也就是以从最小到最大的顺序访问所有节点。中序遍历的一种应用就是对树进行排序操作。
        this[inOrderTraverseNode]=function(node,callback){
            if(node!=null){
                this[inOrderTraverseNode](node.left,callback);//左
                callback(node.key);//根
                this[inOrderTraverseNode](node.right,callback);//右
            }
        };
        //先序遍历是以优先于后代节点的顺序访问每个节点的。先序遍历的一种应用是打印一个结构化的文档
        this[preOrderTraverseNode]=function(node,callback){
            if(node!=null){
                callback(node.key);//根
                this[inOrderTraverseNode](node.left,callback);//左
                this[inOrderTraverseNode](node.right,callback);//右

            }
        }
        //后序遍历则是先访问节点的后代节点,再访问节点本身。后序遍历的一种应用是计算一个目录和它的子目录中所有文件所占空间的大小。
        this[postOrderTraverseNode]=function(node,callback){
            if(node!=null){
                this[inOrderTraverseNode](node.left,callback);//左
                this[inOrderTraverseNode](node.right,callback);//右
                callback(node.key);//根
            }
        }
        //搜索最小值
        this[minNode]=function(node){
            if(node){
                while(node&&node.left!=null){
                    node=node.left;
                }
                return node.key;
            }
            return null;
        }
        //搜索最大值
        this[maxNode]=function(node){
            if(node){
                while(node&&node.right!=null){
                    node=node.right;
                }
                return node.key;
            }
            return null;
        }
        //搜索特定值
        this[searchNode]=function(node,key){
            if(node==null){
                return false;
            }
            if(key<node.key){
                return this[searchNode](node.left,key);
            }else if(key>node.key){
                return this[searchNode](node.right,key);
            }else{
                return true;
            }
        }
        //移除一个节点
        this[removeNode]=function(node,key){
            if(node==null){
                return null;
            }
            if(key<node.key){
                node.left=this[removeNode](node.left,key);
                return node;
            }else if(key>node.key){
                node.right=this[removeNode](node.right,key);
                return node;
            }else{
                if(node.left==null&&node.right==null){//无子节点
                    node=null;
                    return node;
                }
                if(node.left==null){//只有右子节点
                    node=node.right;//将原右子节点替换被删除根节点,即删除掉根节点
                    return node;
                }else if(node.right==null){
                    node=node.left;
                    return node;
                }else{//同时拥有两个子节点
                    let aux=this[findMinNode](node.right);//找到被删除节点的右支最小的值
                    node.key=aux.key;//右支最小值替换被删除的值
                    node.right=this[removeNode](node.right,aux.key);//删除原右支最小值的节点
                    return node;
                }
                
            }
        }
        this[findMinNode]=function(node){
            while(node&&node.left!=null){
                node=node.left;
            }
            return node;
        }
    }
    insert(key){
        let newNode=new Node(key);
        if(this.root==null){//树为空
            this.root=newNode;
        }else{//树不为空
            this[insertNode](this.root,newNode);
        }
    }
    inOrderTraverse(callback){
        this[inOrderTraverseNode](this.root,callback);
    }
    preOrderTraverse(callback){
        this[preOrderTraverseNode](this.root,callback);
    }
    postOrderTraverse(callback){
        this[postOrderTraverseNode](this.root,callback);
    }
    min(){
        return this[minNode](this.root);
    }
    max(){
        return this[maxNode](this.root);
    }
    search(key){
        return this[searchNode](this.root,key); 
    }
    remove(key){
        this.root=this[removeNode](this.root,key)
    }

}

let tree=new BinarySearchTree();
tree.insert(7);
tree.insert(15);
tree.insert(5);
tree.insert(3);
tree.insert(9);
tree.insert(8);
tree.insert(10);
tree.insert(13);
tree.insert(12);
tree.insert(14);
tree.insert(20);
tree.insert(18);
tree.insert(25);
tree.insert(6);
tree.inOrderTraverse(function(value){
    console.log("inOrderTraverse:",value);
})
tree.preOrderTraverse(function(value){
    console.log("preOrderTraverse:",value);
})
tree.postOrderTraverse(function(value){
    console.log("postOrderTraverse:",value);
})
console.log(tree.min());
console.log(tree.max());
console.log(tree.search(8))//true
tree.remove(8)
console.log(tree.search(8))//false

猜你喜欢

转载自blog.csdn.net/wushichao0325/article/details/86155836