天天看點

javascript封裝二叉搜尋樹(BST)

二叉搜尋樹(Binary Search Tree) 特點: 1、若它的左子樹不空,則左子樹上所有結點的值均小于它的根結點的值 2、若它的右子樹不空,則右子樹上所有結點的值均大于它的根結點的值.

如圖示:

javascript封裝二叉搜尋樹(BST)

二叉搜尋樹的插入節點:

//插入資料
    BinarySearchTree.prototype.insert = function (key) {
        let newNode = new Node(key)  //建立新節點

        //判斷跟節點是否有值
        if (this.root === null) {
            this.root = newNode
        } else {
            this.insertNode(this.root,newNode)
        }

    }

    //遞歸尋找适合的節點插入新節點
    BinarySearchTree.prototype.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)
            }
        }
    }
           

二叉搜尋樹的三種周遊方式:

先序周遊:

javascript封裝二叉搜尋樹(BST)

代碼遞歸實作:

//先序周遊的遞歸函數
    BinarySearchTree.prototype.preOrderTraversalNode = function (node) {
        if (node !== null) {
            console.log(node.key) //列印周遊的節點的值
            this.preOrderTraversalNode(node.left) //處理左節點
            this.preOrderTraversalNode(node.right) //處理右節點
        }
    }
           

中序周遊

javascript封裝二叉搜尋樹(BST)

代碼遞歸實作:

//中序周遊的遞歸函數
    BinarySearchTree.prototype.midOrderTraversalNode = function (node) {
        if (node !== null) {
            this.midOrderTraversalNode(node.left)
            console.log(node.key)
            this.midOrderTraversalNode(node.right)
        }
    }
           

後序周遊

javascript封裝二叉搜尋樹(BST)

代碼遞歸實作:

//後序周遊的遞歸函數
    BinarySearchTree.prototype.postOrderTraversalNode = function (node) {

        if (node !== null) {
            this.postOrderTraversalNode(node.left)

            this.postOrderTraversalNode(node.right)
            console.log(node.key)
        }
    }
           

二叉搜尋樹的最大值和最小值:

//最小值
    BinarySearchTree.prototype.min = function () {
        let node = this.root

        while (node.left !== null) {
            node = node.left
        }
        return node.key
    }

    //最大值
    BinarySearchTree.prototype.max = function () {
        let node = this.root

        while (node.right !== null) {
            node = node.right
        }
        return node.key
    }
           

二叉搜尋樹尋找特定的值

//尋找特定的值
    BinarySearchTree.prototype.search = function (key) {
        return this.searchNode(this.root,key)
    }

    //遞歸尋找特定的值
    BinarySearchTree.prototype.searchNode = function (node,key) {
        if (node === null) { 
            return false
        }
        if (node.key > key) {
           return this.searchNode(node.left,key)
        } else if (node.key < key) {
            return this.searchNode(node.right,key)
        } else {
            return true
        }

           

删除節點:有三種情況 1、删除葉子節點 2、删除隻有一個子節點的節點3、删除有兩個子節點的節點

//删除節點
    BinarySearchTree.prototype.remove = function (key) {
        //1、找到要删除的節點
        //2、定義變量 儲存資訊
        let current = this.root
        let parent = null
        let isLeftChild = true //标記要删除的節點是父節點的左子節點還是右子節點

        //開始尋找删除的節點
        while (current.key !== key) {
            parent = current
            if (key < current.key) {
                isLeftChild = true
                current = current.left
            } else {
                isLeftChild = false
                current = current.right
            }
            if (current === null) return false //不存在 要删除的節點
        }

        //删除的是葉子節點
        if (current.left === null && current.right === null) {
            if (current === this.root) {
                this.root = null
            } else if (isLeftChild) {
                parent.left = null
            } else {
                parent.right = null
            }
        }

        //删除隻有一個子節點的節點
       else if (current.right === null) { //current 沒有右子節點
           if (current === this.root) {
               this.root = current.left
           } else if (isLeftChild) {
               parent.left = current.left
           } else {
               parent.right = current.left
           }
        }
       else if (current.left === null) { //current 沒有左子節點
           if (current === this.root) {
               this.root = current.right
           } else if (isLeftChild) {
               parent.left = current.right
           } else {
               parent.right = current.right
           }
        }
       else { //删除的節點有兩個子節點
           //擷取後繼節點
           let successor = this.getSuccessor(current)

            if (current === this.root) {
                this.root = successor
            } else if (isLeftChild) {
                parent.left = successor
            } else {
                parent.right = successor
            }
           //将删除節點的左子樹 = current.left
            successor.left = current.left
        }
    }

    //尋找後繼的辦法
    BinarySearchTree.prototype.getSuccessor = function (delNode) {
        //定義變量 儲存找到的後繼
        let successor = delNode
        let current = delNode.right
        let successorParent = delNode

        //循環查找
        while (current !== null) { //找到delNode右邊最小值的節點 為後繼節點
            successorParent = successor
            successor = current
            current = current.left
        }
        //判斷尋找的後繼節點是否直接就是delNode的right節點
        if (successor !== delNode.right) {
            successorParent.left = successor.right
            successor.right = delNode.right
        }

        return successor
    }
           

整體代碼

//封裝二叉搜尋樹
function BinarySearchTree() {

    //内部節點類
    function Node(key) {
        this.left = null
        this.key = key
        this.right = null
    }

    this.root = null

    //插入資料
    BinarySearchTree.prototype.insert = function (key) {
        let newNode = new Node(key)  //建立新節點

        //判斷跟節點是否有值
        if (this.root === null) {
            this.root = newNode
        } else {
            this.insertNode(this.root,newNode)
        }

    }

    //遞歸尋找适合的節點插入新節點
    BinarySearchTree.prototype.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)
            }
        }
    }

    //先序周遊
    BinarySearchTree.prototype.preOrderTraversal = function () {
        this.preOrderTraversalNode(this.root)
    }

    //先序周遊的遞歸函數
    BinarySearchTree.prototype.preOrderTraversalNode = function (node) {

        if (node !== null) {
            console.log(node.key) //列印周遊的節點的值
            this.preOrderTraversalNode(node.left) //處理左節點
            this.preOrderTraversalNode(node.right) //處理右節點
        }

    }

    //中序周遊
    BinarySearchTree.prototype.midOrderTraversal = function () {
        this.midOrderTraversalNode(this.root)
    }

    //中序周遊的遞歸函數
    BinarySearchTree.prototype.midOrderTraversalNode = function (node) {

        if (node !== null) {
            this.midOrderTraversalNode(node.left)
            console.log(node.key)
            this.midOrderTraversalNode(node.right)
        }
    }

    //後序周遊
    BinarySearchTree.prototype.postOrderTraversal = function () {
        this.postOrderTraversalNode(this.root)
    }

    //後序周遊的遞歸函數
    BinarySearchTree.prototype.postOrderTraversalNode = function (node) {

        if (node !== null) {
            this.postOrderTraversalNode(node.left)

            this.postOrderTraversalNode(node.right)
            console.log(node.key)
        }
    }

    //最小值
    BinarySearchTree.prototype.min = function () {
        let node = this.root

        while (node.left !== null) {
            node = node.left
        }
        return node.key
    }

    //最大值
    BinarySearchTree.prototype.max = function () {
        let node = this.root

        while (node.right !== null) {
            node = node.right
        }
        return node.key
    }

    //尋找特定的值
    BinarySearchTree.prototype.search = function (key) {
        return this.searchNode(this.root,key)
    }

    //遞歸尋找特定的值
    BinarySearchTree.prototype.searchNode = function (node,key) {
        if (node === null) {
            return false
        }
        if (node.key > key) {
           return this.searchNode(node.left,key)
        } else if (node.key < key) {
            return this.searchNode(node.right,key)
        } else {
            return true
        }

    }

    //删除節點
    BinarySearchTree.prototype.remove = function (key) {
        //1、找到要删除的節點
        //2、定義變量 儲存資訊
        let current = this.root
        let parent = null
        let isLeftChild = true //标記要删除的節點是父節點的左子節點還是右子節點

        //開始尋找删除的節點
        while (current.key !== key) {
            parent = current
            if (key < current.key) {
                isLeftChild = true
                current = current.left
            } else {
                isLeftChild = false
                current = current.right
            }
            if (current === null) return false //不存在 要删除的節點
        }

        //删除的是葉子節點
        if (current.left === null && current.right === null) {
            if (current === this.root) {
                this.root = null
            } else if (isLeftChild) {
                parent.left = null
            } else {
                parent.right = null
            }
        }

        //删除隻有一個子節點的節點
       else if (current.right === null) { //current 沒有右子節點
           if (current === this.root) {
               this.root = current.left
           } else if (isLeftChild) {
               parent.left = current.left
           } else {
               parent.right = current.left
           }
        }
       else if (current.left === null) { //current 沒有左子節點
           if (current === this.root) {
               this.root = current.right
           } else if (isLeftChild) {
               parent.left = current.right
           } else {
               parent.right = current.right
           }
        }
       else { //删除的節點有兩個子節點
           //擷取後繼節點
           let successor = this.getSuccessor(current)

            if (current === this.root) {
                this.root = successor
            } else if (isLeftChild) {
                parent.left = successor
            } else {
                parent.right = successor
            }
           //将删除節點的左子樹 = current.left
            successor.left = current.left
        }
    }

    //尋找後繼的辦法
    BinarySearchTree.prototype.getSuccessor = function (delNode) {
        //定義變量 儲存找到的後繼
        let successor = delNode
        let current = delNode.right
        let successorParent = delNode

        //循環查找
        while (current !== null) { //找到delNode右邊最小值的節點 為後繼節點
            successorParent = successor
            successor = current
            current = current.left
        }
        //判斷尋找的後繼節點是否直接就是delNode的right節點
        if (successor !== delNode.right) {
            successorParent.left = successor.right
            successor.right = delNode.right
        }

        return successor
    }
}

const  bst = new BinarySearchTree()

bst.insert(11)
bst.insert(7)
bst.insert(15)
bst.insert(5)
bst.insert(3)
bst.insert(9)
bst.insert(8)
bst.insert(10)
bst.insert(13)
bst.insert(12)
bst.insert(14)
bst.insert(20)
bst.insert(18)
bst.insert(25)
bst.insert(6)

//測試周遊

bst.preOrderTraversal()
bst.midOrderTraversal()
bst.postOrderTraversal()

console.log(bst.min());
console.log(bst.max());

console.log(bst.search(25))
console.log(bst.search(100))
console.log(bst.search(7))


bst.remove(7)
bst.remove(15)
bst.remove(10)
bst.postOrderTraversal()