JavaScript數據結構之 二叉排序樹

/**
 * 二叉排序樹(Binary Sort Tree)又稱二叉查找樹(Binary Search Tree),亦稱二叉搜索樹。
 * 左邊子節點的值 < 父節點的值 < 右邊子節點的值
 * 包括的方法有:插入、遍歷、查詢、查詢父節點、右樹上最小節點、
 * 前中後序遍歷、清空、刪除、是否爲空、求寬度、求深度
 */

function BinarySortTree(value){
    this.root = null;
    if(typeof value === "number"){
        this.root = this.insert(value);
    }else{
        return false;
    }
}
BinarySortTree.prototype = {
    //創建節點
    createNode: function(value){
        return {
            value:value,
            left:null,
            right:null
        };
    },
    //插入一個新節點,如果沒有root就創建root
    insert: function(value){
        if(typeof value !== "number"){
            return false;
        }
        var node = this.createNode(value);
        if(!this.root){
            this.root = node;
            return this.root;
        }else{
            return this.insertNode(this.root, node);
        }
    },
    //通過遞歸來插入
    insertNode: function(fNode, newNode){
        if(fNode.value>newNode.value){
            if(fNode.left===null){
                fNode.left = newNode;
                return newNode;
            }else{
                return this.insertNode(fNode.left, newNode);
            }
        }else if(fNode.value<newNode.value){
            if(fNode.right===null){
                fNode.right = newNode;
                return newNode;
            }else{
                return this.insertNode(fNode.right, newNode);
            }
        }else{
            return false;
        }
    },
    //查找第一個值相同的節點
    findFirst: function(value){
        console.log(this.root);
        if(!this.root)return false;
        return this.findFirstNode(this.root, value)
    },
    //採用的是前序查找 中>左>右
    findFirstNode: function(node, value){
        if(node === null)return false;
        if(node.value === value)return node;
        else if(node.value > value){
            return this.findFirstNode(node.left, value);
        }
        else{
            return this.findFirstNode(node.right, value);
        }
    },
    //判斷空樹
    isEmpty: function(){
        if(this.root)return false;
        return true;
    },
    //清空二叉樹
    clear: function(){
        this.clearTree(this.root);
        this.root = null;
    },
    //清理某個子樹, 需要找到父節點,然後設爲null,不能直接將node設爲null
    clearTree: function(node){
        if(node === null)return;
        this.clearTree(node.left);
        this.clearTree(node.right);
        var fNode = this.findFather(node);
        if(fNode.left === node)fNode.left=null;
        else if(fNode.right === node)fNode.right=null;
    },
    //尋找父節點
    findFather: function(node){
        return this.findFatherNode(this.root,node);
    },
    findFatherNode: function(fNode, node){
        if(fNode===null)return false;
        if(fNode.left === node || fNode.right === node)return fNode;
        if(fNode.value>node.value)return this.findFatherNode(fNode.left, node);
        else return this.findFatherNode(fNode.right, node);
    },
    //計算二叉樹深度
    getDepth: function(){
        return this.getTreeDepth(this.root);
    },
    //計算子樹深度
    getTreeDepth: function(node){
        if(node === null)return 0;
        var leftDepth = this.getTreeDepth(node.left) + 1;
        var rightDepth = this.getTreeDepth(node.right) + 1;

        if(leftDepth>rightDepth)
            return leftDepth;
        return rightDepth;
    },
    //計算樹的寬度
    getWidth: function(){
        return this.getLeftTreeWidth(this.root)+this.getRightTreeWidth(this.root)-1;
    },
    //計算子樹寬度
    getLeftTreeWidth: function(node){
        if(node === null)return 0;
        return 1+this.getLeftTreeWidth(node.left);
    },
    getRightTreeWidth: function(node){
        if(node === null)return 0;
        return 1+this.getRightTreeWidth(node.right);
    },
    //前序遍歷
    preOrderTraverse: function(callback){
        this.preOrderTraverseNode(this.root, callback);
    },
    preOrderTraverseNode: function(node, callback){
        if(node === null)return;
        //left
        this.preOrderTraverseNode(node.left, callback);
        //callback
        callback(node.value);
        //right
        this.preOrderTraverseNode(node.right, callback);
    },

    //中序遍歷
    inOrderTraverse: function(callback){
        this.inOrderTraverseNode(this.root, callback);
    },
    inOrderTraverseNode: function(node, callback){
        if(node === null)return;
        //callback
        callback(node.value);
        //left
        this.inOrderTraverseNode(node.left, callback);
        //right
        this.inOrderTraverseNode(node.right, callback);
    },

    //後序遍歷
    postOrderTraverse: function(callback){
        this.postOrderTraverseNode(this.root, callback);
    },
    postOrderTraverseNode: function(node, callback){
        if(node === null)return;
        //left
        this.postOrderTraverseNode(node.left, callback);
        //right
        this.postOrderTraverseNode(node.right, callback);
        //callback
        callback(node.value);
    },
    //找到右樹的最小值
    findRightMinNode: function(node){
        if(node.left===null)return node;
        else return this.findRightMinNode(node.left);
    },

    //移除
    remove: function(value){
        return this.removeNode(this.root, value);
    },
    removeNode: function(node, value){
        var targetNode = this.findFirstNode(node, value);
        var fNode = this.findFather(targetNode);
        if(targetNode===this.root){
            return false;//暫不考慮移除根節點情況
        }
        //target爲葉子節點
        if(targetNode.left===null&&targetNode.right===null){
            fNode.left === targetNode?fNode.left=null:fNode.right=null;
            return true;
        }
        //target只有一個子節點
        if(targetNode.left===null&&targetNode.right){
            fNode.left === targetNode?fNode.left=targetNode.right:fNode.right=targetNode.right;
            delete targetNode.value;
            delete targetNode.right;
            delete targetNode.left;
            return true;
        }
        if(targetNode.right===null&&targetNode.left){
            fNode.left === targetNode?fNode.left=targetNode.left:fNode.right=targetNode.left;
            delete targetNode.value;
            delete targetNode.right;
            delete targetNode.left;
            return true;
        }
        //target有兩個子節點
        var minNode = this.findRightMinNode(targetNode.right);
        targetNode.value = minNode.value;
        return this.removeNode(targetNode.right, targetNode.value);
    }
};


var root = new BinarySortTree(0);
root.insert(1);
root.insert(2);
root.insert(8);
root.insert(4);
root.insert(9);
root.insert(-7);
root.insert(-1);
root.insert(-8);

console.log(root);

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