Java Binary Search Tree

Java實現二叉查找樹(Binary Search Tree)node

二叉查找樹(英語:Binary Search Tree),也稱二叉搜索樹、有序二叉樹(英語:ordered binary tree),排序二叉樹(英語:sorted binary tree),是指一棵空樹或者具備下列性質的二叉樹:算法

  1. 若任意節點的左子樹不空,則左子樹上全部結點的值均小於或等於它的根結點的值;數據結構

  2. 任意節點的右子樹不空,則右子樹上全部結點的值均大於它的根結點的值;this

  3. 任意節點的左、右子樹也分別爲二叉查找樹。spa

  4. 沒有鍵值相等的節點(英語:no duplicate nodes)。code

二叉查找樹相比於其餘數據結構的優點在於查找、插入的時間複雜度較低。排序

以下所示的二叉查找樹,遞歸

 

查找

根據數據表示的遞歸結構,咱們能夠獲得查找一個鍵的遞歸算法:若是樹是空樹,則查找爲命中;若是查找的鍵值和根節點的鍵值相等,則查找命中,不然就遞歸地在相應的子樹中繼續查找。若是查找的鍵值較小,就選擇左子樹,較大則選擇右子樹。對於命中的查找,路徑在含有被查找的鍵的節點處結束。對於未命中的查找,路徑的終點是一個空連接。get

在二叉搜索樹b中查找x的過程爲:class

  1. 若b是空樹,則搜索失敗,不然:

  2. 若x等於b的根結點的數據域之值,則查找成功;不然:

  3. 若x小於b的根結點的數據域之值,則搜索左子樹;不然:

  4. 查找右子樹。

 

插入

遞歸實現的put方法的實現邏輯和遞歸查找很類似:若是樹是空的,就返回一個含有該鍵值對的新節點;若是被查找的鍵小於根節點的鍵,咱們會繼續在左子樹中插入該鍵,不然在右子樹中插入該鍵。這些遞歸調用值得咱們花點時間去理解其中的運行細節。能夠將遞歸調用前的代碼想象成沿着樹向下走:他會將給定的鍵和每一個節點 的鍵相比較並根據結果向左或者向右移動到下一個節點。而後能夠將遞歸調用後的代碼想象成沿着樹向上爬。對於get方法,這對應着一系列的返回指令return,可是對於put方法,這意味着重置搜索路徑上每一個父節點指向子節點的連接,並增長路徑上每一個節點中的計數器的值。在一棵簡單的二叉查找樹中,惟一的新連接就是在最底層指向新節點的連接。

 

分析

使用二叉查找樹的算法的運行時間取決於樹的形狀,而樹的形狀取決於鍵值被插入的前後順序。在最好的狀況下,一棵含有N個節點的樹是平衡的,每條空連接和根節點的距離都爲

~lgN 。在最壞的狀況下,搜索路徑上可能有N個節點。

命題一:在由N個隨機構造的二叉查找樹中,查找命中平均所需的比較次數爲 ~2lnN(大約 1.39lgN)。

命題一:在由N個隨機構造的二叉查找樹中,插入操做和查找未命中平均所需的比較次數爲 ~2lnN(大約 1.39lgN)。

 

代碼實現

package com.usoft;

/**
 * @author: Lenovo(2015-06-30 16:32)
 */
public class BinarySearchTree2<Key extends Comparable<Key>, Value> {

    private Node root; //根節點

    public int size() {
        return size(root);
    }

    private int size(Node x) {
        if (x == null) {
            return 0;
        } else {
            return x.N;
        }
    }

    public Value get(Key key) {
        return get(root, key);
    }

    private Value get(Node x, Key key) {
        if (x == null) {
            return null;
        }
        int cmp = key.compareTo(x.key);
        if (cmp < 0) {
            return get(x.left, key);
        } else if (cmp > 0) {
            return get(x.right, key);
        } else {
            return x.val;
        }
    }

    public void put(Key key, Value val) {
        root = put(root, key, val);
    }

    private Node put(Node x, Key key, Value val) {
        //若是key存在於以x爲根節點的子樹中則更新他的值;
        //不然將以key和val的鍵值對爲新節點插入到該子樹中
        if (x == null) {
            return new Node(key, val, 1);
        }
        int cmp = key.compareTo(x.key);
        if (cmp < 0) {
            x.left = put(x.left, key, val);
        } else if (cmp > 0) {
            x.right = put(x.right, key, val);
        } else {
            x.val = val;
        }
        x.N = size(x.left) + size(x.right) + 1;
        return x;
    }

    private class Node {
        private Key key; // 鍵值
        private Value val;
        private Node left, right;
        private int N;  // 以該節點爲根的子樹中的節點總數(節點計數器)

        public Node(Key key, Value val, int N) {
            this.key = key;
            this.val = val;
            this.N = N;
        }
    }

}

=============END=============

相關文章
相關標籤/搜索