1. 程式人生 > >JS 實現二叉查詢樹(Binary Search Tree)

JS 實現二叉查詢樹(Binary Search Tree)

知識點

  • 二叉查詢樹,也稱二叉搜尋樹、有序二叉樹(英語:ordered binary tree)是指一棵空樹
  • 任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
  • 任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
  • 任意節點的左、右子樹也分別為二叉查詢樹;
  • 沒有鍵值相等的節點;
  • 二叉查詢樹相比於其他資料結構的優勢在於查詢、插入的時間複雜度較低。為O(log n)。
  • 二叉查詢樹是基礎性資料結構,用於構建更為抽象的資料結構,如集合、multiset、關聯陣列等。

實現程式碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>二叉查詢樹</title>
</head>
<body>
<script>
    // 單個節點物件
    class Node {
        constructor (data, left, right) {
            this.data = data;
            this.left = left;
            this.right = right;
        }
    }

    // 樹
    class BinarySearchTree {
        constructor () {
            this.root = null;
        }

        // 插入成功返回樹
        insert (data) {
            let cNode = new Node(data, null, null);
            // 空樹
            if (!this.root) {
                this.root = cNode;
                return ;
            }
            // 非空樹
            let currentNode = this.root;
            let parent = null;
            // 遍歷
            while(1) {
                // 得到一個指向  即將改變 或 其子節點將要被改變 的節點的 變數
                parent = currentNode;
                // 左子樹
                if (data < currentNode.data) {
                    // currentNode 指向為空,賦值到currentNode無效
                   /* currentNode = parent.left;
                    if (currentNode === null) {
                        currentNode = n;
                        break;
                    }*/
                    currentNode = currentNode.left;
                    if (currentNode === null) {
                        parent.left = cNode;
                        break
                    }
                }
                // 右子樹
                else if ( data > currentNode.data ) {
                    // currentNode 指向為空,賦值到currentNode無效
                    /*currentNode = parent.right;
                    if (currentNode === null) {
                        currentNode = n;
                        break;
                    }*/
                    currentNode = currentNode.right;
                    if (currentNode === null) {
                        parent.right = cNode;
                        break;
                    }
                }
                // 相等
                else {
                    break;
                }
            }
        }

        // 傳入陣列,建立樹
        create (arr) {
            if (!arr.length) {
                this.root = null;
            }else {
                let length = arr.length;
                for (let i = 0; i < length; i++) {
                    console.log()
                    this.insert(arr[i]);
                }
            }
        }

        // 刪除
        remove (data) {
            this.root = this.removeNodeByData(this.root, data);
        }

        // 返回刪除對應值後的  "node"
        removeNodeByData (node, data) {
            if (node === null) {
                return null;
            }
            // 資料等於傳入樹的根節點資料
            if (data === node.data) {
                // 子節點都為空
                if (node.left === null && node.right === null) {
                    // 返回為空 樹為空
                    return null;
                }
                // 左節點為空
                if (node.left === null){
                    // 刪除的資料等於根節點的資料,且根節點左節點為空,刪除根節點,返回右節點
                    return node.right
                }
                // 右節點為空
                if (node.right === null){
                    return node.left;
                }

                // 思路:子節點都不為空的處理函式,找到刪除節點的中序遍歷的直接前驅(或直接後驅)結點,用該結點來替換要刪除的節點,再刪除該節點
                // 得到直接的後驅節點(節點的右子樹最左邊的節點,或最右邊的節點)
                let getAftNode = function (node) {
                    if (node.left === null && node.right === null) {
                        return node;
                    }
                    if (node.left !== null) {
                        return getAftNode(node.left);
                    }
                    if (node.right !== null) {
                        return node.right;
                    }
                }
                //相等,且左右節點都不為空
                let tempNode = getAftNode(node.right);
                // 要刪除的節點的值等於 其直接後繼的值
                node.data = tempNode.data;
                // 刪除 要刪除的節點 的直接後繼
                node.right = this.removeNodeByData(node.right, tempNode.data);

               /* {
                    // 得到直接的前驅節點(節點的左子樹最右邊的節點,或最左邊的節點)
                    let getPreNode = function (node) {
                        if (node.left === null && node.right === null) {
                            return node
                        }
                        if (node.right !== null) {
                            return getPreNode(node.right)
                        }
                        if (node.left !== null) {
                            return node.left
                        }
                    }
                    let tempNode = getPreNode(node.left);
                    node.data = tempNode.data;
                    node.left = this.removeNodeByData(node.left, tempNode.data);
                }*/

                return node;
            }
            else if (data < node.data) {
                node.left = this.removeNodeByData(node.left, data);
                // 當前的節點不變
                return node;
            }else {
                node.right = this.removeNodeByData(node.right, data);
                // 當前的節點不變
                return node
            }
        }

        // 非遞迴查詢, 返回查詢到的節點
        findByNonRecur(data) {
            let current = this.root;
            let tagNode = null;
            while (current !== null) {
                console.log(current);
                if (data === current.data) {
                    tagNode = current;
                    break;
                }else if (data < current.data) {
                    current = current.left;
                } else if (data > current.data) {
                    current = current.right;
                }
            }
            // 查詢到返回節點,沒查詢返回null

            return tagNode
        }

        // 遞迴查詢,返回節點
        findByRecur (data) {
            // let current = node||this.root;  --- 造成無限迴圈
            let current = this.root;
            return (function _selfCall(data, current) {
                if (current === null) {
                    return null;
                }
                if (current.data === data) {
                    return current
                }else if (data < current.data) {
                    current = current.left;
                    // 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
                    // return arguments.callee(data, current)
                    return _selfCall(data, current)
                } else {
                    current = current.right;
                    // 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
                    // return arguments.callee(data, current)
                    return _selfCall(data, current)
                }
            })(data, current)
        }

        // 獲取最大值
        findMax(){
            let current = this.root;
            while(current.right !== null) {
                current = current.right;
            }
            return current.data
        }

        // 獲取最小值
        findMin(){
            let current = this.root;
            while(current.left!==null){
                current = current.left
            }
            return current.data
        }

        // 先序遍歷 -- 根、左、右
        preTravel(node){
            let preTravelArr = [];
            (function _preTravel (node) {
                if (node !== null) {
                    preTravelArr.push(node.data);
                    _preTravel(node.left);
                    _preTravel(node.right);
                }
            })(node)
            return preTravelArr;
        }
        // 中序遍歷 -- 左、根、右
        midTravel(node){
            let midTravelArr = [];
            (function _midTravel (node) {
                if (node !== null) {
                    _midTravel(node.left);
                    midTravelArr.push(node.data);
                    _midTravel(node.right);
                }
            })(node)
            return midTravelArr;
        }
        // 後序遍歷 -- 左、右、根
        aftTravel(node){
            let aftTravelArr = [];
            (function _aftTravel (node) {
                if (node !== null) {
                    _aftTravel(node.left);
                    _aftTravel(node.right);
                    aftTravelArr.push(node.data);
                }
            })(node)
            return aftTravelArr;
        }
    }

    let BSTree = new BinarySearchTree();
	//  建立樹 
    BSTree.create([62,58,47,35,29,37,36,51,49,48,50,56,88,73,99,93]);
    // 操作
</script>
</body>
</html>