Javascript之數據結構與算法的二叉樹和二叉搜索樹實現

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章