1. 程式人生 > >資料結構之二叉搜尋樹(BST)

資料結構之二叉搜尋樹(BST)

JavaScript實現二叉搜尋樹(BST)

  • 二叉搜尋樹定義
  • 二叉搜尋樹JavaScript程式碼實現

1. 二叉搜尋樹 二叉查詢樹(英語:Binary Search Tree),也稱為二叉搜尋樹、有序二叉樹(ordered binary tree)或排序二叉樹(sorted binary tree),是指一棵空樹或者具有下列性質的二叉樹:

  1. 若任意節點的左子樹不空,則左子樹上所有節點的值均小於它的根節點的值;
  2. 若任意節點的右子樹不空,則右子樹上所有節點的值均大於它的根節點的值;
  3. 任意節點的左、右子樹也分別為二叉查詢樹;
  4. 沒有鍵值相等的節點。 –(wiki百科) 2. 二叉搜尋樹程式碼實現
const BinarySearchTree = function() {

    let Node = function(key) {
        this.key = key;
        this.left = null;
        this.rigth = null;
    };
    let root = null;

    this.insert = function(key) {
        // 向樹中插入一個新的鍵

        let newNode = new Node(key);

        if (root === null) {
            root = new Node(key);
        } else {
            insertNode(root, newNode);
        };

        const insertNode = function(node, newNode) {
            if (newNode.key < node.key) {
                if (node.left === null) {
                    node.left = newNode;
                } else {
                    // 遞迴
                    insertNode(node.left, newNode);
                }
            } else {
                if (node.rigth === null) {
                    node.rigth = newNode;
                } else {
                    insertNode(node.rigth, newNode);
                }
            }
        };
    };

    const inOrderTraverseNode = function(node, callback) {
        if (node !== null) {
            inOrderTraverseNode(node.left, callback);
            callback(node.key);
            inOrderTraverseNode(node.rigth, callback);
        }
    };

    this.inOrderTraverse = function(callback) {
        // 通過中序遍歷遍歷所有節點, 即從小到大順序訪問節點
        inOrderTraverseNode(root, callback);
    };

    const preOrderTraverseNode = function(node, callback) {
        if (node !== null) {
            callback(node.key);
            preOrderTraverseNode(node.left, callback);
            preOrderTraverseNode(node.rigth, callback);
        }
    };

    this.preOrderTraverse = function(callback) {
        // 先序遍歷,即優先於後代節點的順序訪問每個節點。
        preOrderTraverseNode(root, callback)

    };

    const postOrderTraverseNode = function(node, callback) {
        if (node !== null) {
            preOrderTraverseNode(node.left, callback);
            preOrderTraverseNode(node.rigth, callback);
            callback(node.key);
        }
    };

    this.postOrderTraverse = function(callback) {
        // 後序遍歷,即先訪問節點的後代節點再訪問節點本身。
        postOrderTraverseNode(root, callback);
    };
    const minNode = function(node) {
        if(node) {
            while(node && node.left !== null) {
                node = node.left;
            }
            return node.key;
        }
        return null;
    };

    this.min = function() {
        // 搜尋最小值
        return minNode(root);
    };

    const maxNode = function(node) {
        if(node) {
            while(node && node.rigth !== null) {
                node = node.right;
            }
            return node.key;
        }
        return null;
    };

    this.max = function() {
        // 搜尋最大值
        return maxNode(root);
    };

    const 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;
        }
    };

    this.search = function(key) {
        // 在樹中查詢一個鍵,如果節點存在,返回true,不存在,返回false
        return searchNode(root, key);
    };

    const findMinNode = function(node) {
        while (node && node.left !== null) {
            node = node.left;
        }
        return node;
    };

    const removeNode = function(node, key) {
        if (node === null) {
            return null;
        }
        if (key < node.key) {
            node.left = removeNode(node.left, key);
            return node;
        } else if (key > node.key) {
            node.right = removeNode(node.right, key);
            return node;
        } else {
            // key == node.key
            if (node.left === null && node.right ===null) {
                // 該節點是葉節點(沒有子節點)
                node = null;
                return node;
            } else if (node.left === null) {
                // 該節點有一個右節點
                node = node.rigth;
                return node;
            } else if (node.right === null) {
                node = node.left;
                return node;
            } else {
                // 有兩個子節點
                let aux = findMinNode(node.right);
                node.key = aux.key;
                node.right = removeNode(node.right, aux.key);
                return node;
            }            
        }
    };

    this.remove = function(key) {
        // 移除某個鍵
        root = removeNode(root, key);

    };

}