數據結構之「二叉搜索樹」

二叉搜索樹

二叉搜索樹也叫二叉查找樹或者二叉排序樹,它要麼是一顆空樹,要麼知足如下幾點:
1.若任意節點的左子樹不空,則左子樹上全部節點的值均小於它的根節點的值。
2.若任意節點的右子樹不空,則右子樹上全部節點的值均大於它的根節點的值。
3.任意節點的左、右子樹也分別爲二叉搜索樹。
4.沒有鍵值相等的節點。
imagejava

二叉搜索樹的實現

1.二叉搜索樹的存儲結構微信

public class BinarySearchTree {
    public static  Node root;
    public BinarySearchTree(){
        this.root = null;
    }
}
class Node{
    int data;
    Node left;
    Node right;
    public Node(int data){
        this.data = data;
        left = null;
        right = null;
    }
}

2.二叉搜索樹的插入
a.循環二分查找到須要插入的地方。
b.假如插入的值小於當前的值,而且當前左節點爲空,那麼左節點就指向新節點。
c.假如插入的值大於當前的值,而且當前右節點爲空,那麼右節點就指向新節點。this

public void insert(int id){
    Node newNode = new Node(id);
    if(root == null){
        root = newNode;
        return;
    }
    Node current = root;
    Node parent = null;
    while(true){
        parent = current;
        if(id < current.data){
            current = current.left;
            if(current == null){
                parent.left = newNode;
                return;
            }
        } else {
            current = current.right;
            if(current == null){
                parent.right = newNode;
                return;
            }
        }
    }
}

3.二叉搜索樹的刪除
a.當刪除節點爲葉子節點時,直接刪除節點。
b.當刪除節點只有左子樹時,重接左子樹。
c.當刪除節點只有右子樹時,重接右子樹。
d.當刪除節點既有左子樹,又有右子樹時,先找一個能夠替換刪除節點的節點。因爲二叉樹的性質,左子樹的值小於根節點的值,右子樹的值大於根節點的值。因此右子樹的最左的節點就是替換刪除的節點,而後在重接右子樹。
第 d 點的圖例:
imagespa

public boolean delete(int id) {
    Node parent = root;
    Node current = root;
    boolean isLeftChild = false;
    while (current.data != id) {
        parent = current;
        if (current.data > id) {
            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 == root) {
            root = null;
        }
        if (isLeftChild == true) {
            parent.left = null;
        } else {
            parent.right = null;
        }
    }
    //刪除的節點只有左節點
    else if (current.right == null) {
        if (current == root) {
            root = current.left;
        } else if (isLeftChild) {
            parent.left = current.left;
        } else {
            parent.right = current.left;
        }

    }
    //刪除的節點只有右節點
    else if (current.left == null) {
        if (current == root) {
            root = current.right;
        } else if (isLeftChild) {
            parent.left = current.right;
        } else {
            parent.right = current.right;
        }
    }
    //刪除的節點既有左節點,又有右節點
    else if (current.left != null && current.right != null) {
        //找到右子樹的最左節點
        Node successor = getSuccessor(current);
        if (current == root) {
           root = successor;
            } else if (isLeftChild) {
                parent.left = successor;
            } else {
                parent.right = successor;
            }
            successor.left = current.left;
        }
        return true;
    }

    public Node getSuccessor(Node deleleNode) {
        Node successsor = null;
        Node successsorParent = null;
        Node current = deleleNode.right;
        while (current != null) {
            successsorParent = successsor;
            successsor = current;
            current = current.left;
        }
        if (successsor != deleleNode.right) {
            successsorParent.left = successsor.right;
            successsor.right = deleleNode.right;
        }
        return successsor;
    }

4.二叉搜索樹的查找code

public boolean find(int id) {
    Node current = root;
    while (current != null) {
        if (current.data == id) {
            return true;
        } else if (current.data > id) {
            current = current.left;
        } else {
            current = current.right;
        }
    }
    return false;
    }

總結

因爲它是一顆有序的樹,就能夠進行折半查找,每一次查找,假如不是匹配的值,均可以排除一半的值。因此通常的時間複雜度是 O(log n)。假如這棵樹退化爲斜樹,就差很少是線性表了,它的時間複雜度就是 O(n)。排序

雖然二叉搜索樹的最壞時間複雜度是 O(n),但經過一些改進能夠把最壞時間複雜度降至 O(log n),好比 AVL樹、紅黑樹等。紅黑樹不須要絕對的平衡,因此插入和刪除效率上要高,在 JDK1.8 中哈希表存儲大於等於 8 個節點的鏈表就是採用的紅黑樹。rem

因此二叉搜索樹在查找上是很是快的,在一些須要很高查詢效率上推薦使用。get

PS:
清山綠水始於塵,博學多識貴於勤。
我有酒,你有故事嗎?
微信公衆號:「清塵閒聊」。
歡迎一塊兒談天說地,聊代碼。
it

相關文章
相關標籤/搜索