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=============