二叉樹(三): 二叉查找樹

什麼是二叉查找樹

二叉查找樹(英語:Binary Search Tree),也稱爲二叉查找樹、有序二叉樹(ordered binary tree)或排序二叉樹(sorted binary tree)

他擁有如下性質:node

  • 若任意節點的左子樹不空,則左子樹上全部節點的值均小於它的根節點的值;
  • 若任意節點的右子樹不空,則右子樹上全部節點的值均大於它的根節點的值;
  • 任意節點的左、右子樹也分別爲二叉查找樹;


圖中的二叉樹就是一顆二叉查找樹git

const nodes = {
    value: 6,
    left: {
        value: 3,
        left: {
            value: 1,
            left: {
                value: 0
            },
            right: {
                value: 2
            }
        },
        right: {
            value: 5
        }
    },
    right: {
        value: 8,
        left: {
            value: 7
        },
        right: {
            value: 9
        }
    }
}

查找節點

在二叉查找樹b中查找x的過程爲:github

  1. 若b是空樹,則搜索失敗,不然:
  2. 若x等於b的根節點的數據域之值,則查找成功;不然:
  3. 若x小於b的根節點的數據域之值,則搜索左子樹;不然:
  4. 查找右子樹。
const SearchBST = (tree, value) => {
    if (!tree) {
        return false
    }
    if (value === tree.value) {
        return tree
    }
    if (value < tree.value) {
        return SearchBST(tree.left, value)
    }
    return SearchBST(tree.right, value)
}

插入節點

向一個二叉查找樹b中插入一個節點s的算法,過程爲:算法

  1. 若b是空樹,則將s所指節點做爲根節點插入,不然:
  2. 若s->data等於b的根節點的數據域之值,則返回,不然:
  3. 若s->data小於b的根節點的數據域之值,則把s所指節點插入到左子樹中,不然:
  4. 把s所指節點插入到右子樹中。(新插入節點老是葉子節點)
const InsertBST = (tree, value, parent, key) => {
    if (!tree) {
        parent[key] = {
            value
        }
        return true
    }
    if (tree.value === value) {
        return false
    }
    if (tree.value > value) {
        return InsertBST(tree.left, value, tree, 'left')
    }
    return InsertBST(tree.right, value, tree, 'right')
}

相比較其餘算法, JS 的實現感受有些不足數據庫

刪除節點

二叉搜索樹的節點刪除包括兩個過程,查找和刪除。segmentfault

在二叉查找樹刪去一個結點,分三種狀況討論:數組

  • 待刪除節點度爲零;
  • 待刪除節點度爲一;
  • 待刪除節點度爲二。

節點度能夠當作分支數數據結構

const DeleteBST = (root, value) => {
    if (!root) {
        return false
    }
    if (root.value === value) {
        return DELETE(root)
    }
    if (root.value > value) {
        return DeleteBST(root.left, value, root, 'left')
    }
    return DeleteBST(root.right, value, root, 'left')
}

const DELETE = (root, parent, key) => {
    // 在這裏實現三種狀況
    // 狀況 1 沒有左右子節點 可直接刪除
    if (!root.left && !root.right) {
        parent[key] = null
        return true
    }

    // 狀況 2 只有一個子節點 從新鏈接便可
    if (!root.right) {
        const q = root.left
        root.value = q.value
        root.left = q.left
        root.right = q.right
        return true
    }
    if (!root.left) {
        const p = root.right
        root.value = p.value
        root.left = p.left
        root.right = p.right
        return true
    }

    // 狀況 3
    // 刪除節點後,爲了維持二叉搜索樹的結構特性,須要從其左子樹中選出一個最大值的節點,「上移」到刪除的節點位置上
    let temp = root
    let l = root.left
    while (l.right) {
        temp = l
        l = l.right
    }
    root.value = l.value
    if (root != temp) {
        temp.right = l.left
    } else {
        temp.left = l.left
    }
    return true
}

複雜度

雖然二叉查找樹的最壞效率是O(n),但它支持動態查詢,且有不少改進版的二叉查找樹可使樹高爲O(log n),從而將最壞效率降至O(log n),如AVL樹、紅黑樹等。spa

結語

二叉查找樹它既有鏈表的快速插入與刪除操做的特色,又有數組快速查找的優點,應用十分普遍,例如在文件系統和數據庫系統通常會採用這種數據結構進行高效率的排序與檢索操做code

倉庫地址: https://github.com/Grewer/notes

參考:

相關係列

相關文章
相關標籤/搜索