Java實現二叉查找樹(Binary Search Tree)node
二叉查找樹(英語:Binary Search Tree),也稱二叉搜索樹、有序二叉樹(英語:ordered binary tree),排序二叉樹(英語:sorted binary tree),是指一棵空樹或者具備下列性質的二叉樹:算法
若任意節點的左子樹不空,則左子樹上全部結點的值均小於或等於它的根結點的值;數據結構
任意節點的右子樹不空,則右子樹上全部結點的值均大於它的根結點的值;this
任意節點的左、右子樹也分別爲二叉查找樹。spa
沒有鍵值相等的節點(英語:no duplicate nodes)。code
二叉查找樹相比於其餘數據結構的優點在於查找、插入的時間複雜度較低。排序
以下所示的二叉查找樹,遞歸
根據數據表示的遞歸結構,咱們能夠獲得查找一個鍵的遞歸算法:若是樹是空樹,則查找爲命中;若是查找的鍵值和根節點的鍵值相等,則查找命中,不然就遞歸地在相應的子樹中繼續查找。若是查找的鍵值較小,就選擇左子樹,較大則選擇右子樹。對於命中的查找,路徑在含有被查找的鍵的節點處結束。對於未命中的查找,路徑的終點是一個空連接。get
在二叉搜索樹b中查找x的過程爲:class
若b是空樹,則搜索失敗,不然:
若x等於b的根結點的數據域之值,則查找成功;不然:
若x小於b的根結點的數據域之值,則搜索左子樹;不然:
查找右子樹。
遞歸實現的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=============