树集合了数组(查找速度快)和链表(插入、删除速度快)的优点

二叉树是一种特殊的树,即:树中的每个节点最多只能有两个子节点

二叉搜索树是一种特殊的二叉树,即:节点的左子节点的值都小于这个节点的值,节点的右子节点的值都大于等于这个节点的值

节点类:

public class Node {
public int id;
public String name;
public Node leftChild;
public Node rightChild; public Node(int id, String name) {
this.id = id;
this.name = name;
}
}

实现类(如果树中允许存在重复数据,处理起来比较麻烦,故实现中不允许树中存在重复数据,即节点的右子节点的值必须大于节点的值):

搜索二叉树有一个特点,即如果使用中序遍历遍历搜索二叉树,将得到包含搜索二叉树中所有节点值的升序排序结果

public class BinarySearchTree {
public Node root; public Node find(int key){
if(root == null){
System.out.println("The tree is empty!");
return null;
}
Node current = root;
while(current.id != key){
if(key > current.id)
current = current.rightChild;
else
current = current.leftChild;
if(current == null)
return null;
}
return current;
} public boolean insert(Node node){
if(root == null){
root = node;
return true;
}
//树中不允许插入重复的数据项
if(this.find(node.id) != null){
System.out.println("Node with id '" +
node.id + "' has already existed!");
return false;
}
Node current = root;
while(current != null){
if(node.id > current.id){
if(current.rightChild == null){
current.rightChild = node;
return true;
}
current = current.rightChild;
}else{
if(current.leftChild == null){
current.leftChild = node;
return true;
}
current = current.leftChild;
}
}
return false;
} //前序遍历
public void preorder_iterator(Node node){
System.out.print(node.id + " ");
if(node.leftChild != null)
this.preorder_iterator(node.leftChild);
if(node.rightChild != null)
this.preorder_iterator(node.rightChild);
} //中序遍历
//中序遍历二叉搜索树将会得到包含二叉搜索树
//所有数据项的有序数列
public void inorder_iterator(Node node){
if(node.leftChild != null)
this.inorder_iterator(node.leftChild);
System.out.print(node.id + " ");
if(node.rightChild != null)
this.inorder_iterator(node.rightChild);
} //后序遍历
public void postorder_iterator(Node node){
if(node.leftChild != null)
this.postorder_iterator(node.leftChild);
if(node.rightChild != null)
this.postorder_iterator(node.rightChild);
System.out.print(node.id + " ");
} //获取树(子树)中的最小节点
public Node getMinNode(Node node){
if(this.find(node.id) == null){
System.out.println("Node dosen't exist!");
return null;
}
if(node.leftChild == null)
return node;
Node current = node.leftChild;
while(current.leftChild != null)
current = current.leftChild;
return current;
} //获取树(子树)中的最大节点
public Node getMaxNode(Node node){
if(this.find(node.id) == null){
System.out.println("Node dosen't exist!");
return null;
}
if(node.rightChild == null)
return node;
Node current = node.rightChild;
while(current.rightChild != null)
current = current.rightChild;
return current;
} //删除节点需要分3种情况进行讨论
public boolean delete(int key){
if(root == null){
System.out.println("The tree is empty!");
return false;
}
Node targetParent = root;
Node target = root;
boolean isLeftChild = true;
while(target.id != key){
if(key > target.id){
targetParent = target;
target = target.rightChild;
isLeftChild = false;
}else{
targetParent = target;
target = target.leftChild;
isLeftChild = true;
}
if(target == null)
break;
}
if(target == null){
System.out.println("Node dosen't exist!"
+ "Can not delete.");
return false;
}
//被删除节点为叶子节点
if(target.leftChild == null &&
target.rightChild == null){
if(target.id == root.id){
root = null;
return true;
}
if(isLeftChild)
targetParent.leftChild = null;
else
targetParent.rightChild = null;
}
//被删除节点有1个子节点
//被删除节点只有右子节点
else if(target.leftChild == null &&
target.rightChild != null){
if(target.id == root.id){
root = root.rightChild;
return true;
}
if(isLeftChild)
targetParent.leftChild = target.rightChild;
else
targetParent.rightChild = target.rightChild;
}
//被删除节点只有左子节点
else if(target.leftChild != null &&
target.rightChild == null){
if(target.id == root.id){
root = root.leftChild;
return true;
}
if(isLeftChild)
targetParent.leftChild = target.leftChild;
else
targetParent.rightChild = target.leftChild;
}
//被删除节点有2个子节点
else{
Node followingNode = this.getFollowingNode(target);
if(target.id == root.id)
root = followingNode;
else if(isLeftChild)
targetParent.leftChild = followingNode;
else
targetParent.rightChild = followingNode;
followingNode.leftChild = target.leftChild;
followingNode.rightChild = target.rightChild;
}
return true;
} //获取被删除节点的后续节点
private Node getFollowingNode(Node node2Del){
Node nodeParent = node2Del;
//只有被删除节点有左右子节点时,才会调用该方法
//这里直接调用rightChild是没有问题的
Node node = node2Del.rightChild;
while(node.leftChild != null){
nodeParent = node;
node = node.leftChild;
}
if(node.id != node2Del.rightChild.id)
nodeParent.leftChild = node.rightChild;
else
nodeParent.rightChild = node.rightChild;
return node;
} public static void main(String[] args) {
//插入
BinarySearchTree bst = new BinarySearchTree();
Node n1 = new Node(20, "root");
Node n2 = new Node(10, "left");
Node n3 = new Node(30, "right");
bst.insert(n1);
bst.insert(n2);
bst.insert(n3);
//遍历
bst.preorder_iterator(bst.root);
System.out.println();
bst.inorder_iterator(bst.root);
System.out.println();
bst.postorder_iterator(bst.root);
System.out.println();
//删除
Node n4 = new Node(5, "");
Node n5 = new Node(15, "");
Node n6 = new Node(40, "");
Node n7 = new Node(35, "");
Node n8 = new Node(45, "");
bst.insert(n4);
bst.insert(n5);
bst.insert(n6);
bst.insert(n7);
bst.insert(n8);
bst.inorder_iterator(bst.root);
System.out.println();
bst.delete(20);
bst.inorder_iterator(bst.root);
System.out.println();
}
}

执行结果:

20 10 30
10 20 30
10 30 20
5 10 15 20 30 35 40 45
5 10 15 30 35 40 45

二叉搜索树的效率:

树的大部分操作需要从上至下一层层的查找树的节点,对于一棵满树,大约有一半的节点处于最底层(最底层节点数 = 其它层节点数的和 + 1),故节点操作大约有一半需要找到最底层节点,大约有四分之一的节点处于倒数第二层,故节点操作大约有四分之一需要找到倒数第二层节点,依此类推

查找过程中,需要访问每一层的节点,故只要知道了查找的层数,就能知道操作所需的时间,如果节点总数为N,层数为L,L=log2(N+1)

如果为查找操作或删除操作,被操作的节点可能是是树的任意节点,故查找操作或删除操作的时间复杂度为:1/21*log2(N+1) + 1/22*log2(N/2+1) + ... + 1/2N*1

如果为插入操作,由于每次都在树的最低层插入新的节点,故插入操作的时间复杂度为:log2(N+1)

总的来说可以认为二叉搜索树操作的时间复杂度为为O(logN)

如果树不是一棵满树,则判断起来比较复杂,但是如果层数相同,对满树的操作肯定比对不满树的操作更耗时

对于一个含有10000个数据项的有序链表,查找操作平均需要比较5000次,对于一个含有10000个节点的二叉搜索树,查找操作大约需要13次

对于一个含有10000个数据项的有序数组,插入操作平均需要移动5000次(对于比较次数,使用不同的算法比较次数并不相同),对于一个含有10000个节点的二叉搜索树,插入操作只需大约13次比较就可找到待插入节点的插入位置,并且由于该位置总是处于二叉搜索树的最底层,并不需要移动其它的节点

可以看出,二叉搜索树集合了有序链表插入删除效率高和有序数组查询效率高的优点

Java二叉搜索树实现的更多相关文章

  1. java二叉搜索树原理与实现

    计算机里面的数据结构 树 在计算机存储领域应用作用非常大,我之前也多次强调多磁盘的存取速度是目前计算机飞速发展的一大障碍,计算机革命性的的下一次飞跃就是看硬盘有没有质的飞跃,为什么这么说?因为磁盘是永 ...

  2. Java 二叉搜索树 实现和学习

    /** * <html> * <body> * <P> Copyright 1994 JsonInternational</p> * <p> ...

  3. java 二叉搜索树

    java二叉查找树实现: 二叉查找树,上图:比根节点小者在其左边,比根节点大者在其右边. 抽象数据结构,上代码: /** * 二叉查找树数据结构(非线程安全): * 范型类型须实现Comparable ...

  4. 【算法与数据结构】二叉搜索树的Java实现

    为了更加深入了解二叉搜索树,博主自己用Java写了个二叉搜索树,有兴趣的同学可以一起探讨探讨. 首先,二叉搜索树是啥?它有什么用呢? 二叉搜索树, 也称二叉排序树,它的每个节点的数据结构为1个父节点指 ...

  5. Java实现二叉搜索树的添加,前序、后序、中序及层序遍历,求树的节点数,求树的最大值、最小值,查找等操作

    什么也不说了,直接上代码. 首先是节点类,大家都懂得 /** * 二叉树的节点类 * * @author HeYufan * * @param <T> */ class Node<T ...

  6. 二叉搜索树Java实现(查找、插入、删除、遍历)

    由于最近想要阅读下 JDK1.8 中 HashMap 的具体实现,但是由于 HashMap 的实现中用到了红黑树,所以我觉得有必要先复习下红黑树的相关知识,所以写下这篇随笔备忘,有不对的地方请指出- ...

  7. Java与算法之(13) - 二叉搜索树

    查找是指在一批记录中找出满足指定条件的某一记录的过程,例如在数组{ 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }中查找数字15,实现代码很简单 ...

  8. 二叉搜索树(Java实现)

    二叉搜索树基本操作 求树中的结点个数 判断节点是否为空 向树中插入新结点key-value 树中是否存在key 返回树中key对应的value值 先序遍历 中序遍历 后续遍历 层序遍历 求树中key最 ...

  9. Java创建二叉搜索树,实现搜索,插入,删除操作

    Java实现的二叉搜索树,并实现对该树的搜索,插入,删除操作(合并删除,复制删除) 首先我们要有一个编码的思路,大致如下: 1.查找:根据二叉搜索树的数据特点,我们可以根据节点的值得比较来实现查找,查 ...

随机推荐

  1. JavaSE聊天室

    今天学习了一下简单聊天程序(类似QQ那种)的编写过程,从最初的0.1版本到最后的1.3版本,功能不断地增强,下面对一天的学习内容进行梳理. 版本0.1 我们的需求是显示一个窗体,其他什么也不用做,其他 ...

  2. mysql一些写常用命令

    参见pcttcnc2007博客腾飞 1.mysql的status信息命令: mysql> show global status; 2.可以列出mysql服务器运行各种状态值,另外,查询mysql ...

  3. Linux系统管理员应该了解的一些I/O统计工具

    作为一个Linux系统管理员,统计各类IO是一项必不可少的工作.其统计工具中iostat显然又是最重要的一个统计手段.但是这里iostat不是本文的重点,因为这个工具的使用在网络上已经有大量的教程,可 ...

  4. POJ 3468 A Simple Problem with Integers (线段树成段更新)

    题目链接:http://poj.org/problem?id=3468 题意就是给你一组数据,成段累加,成段查询. 很久之前做的,复习了一下成段更新,就是在单点更新基础上多了一个懒惰标记变量.upda ...

  5. SAE搭建WordPress教程 免费建WordPress博客站

    SAE搭建WordPress教程 免费建WordPress博客站 WordPress是一种使用PHP语言开发的博客平台,用户可以在支持PHP和MySQL数据库的服务器上架设自己的网志.当然,用户也可以 ...

  6. MVC基本学习

    asp.net MVC ViewData详解 http://www.cnblogs.com/gaopin/archive/2012/11/13/2767515.html Asp.net MVC中的Vi ...

  7. CloudStack 使用生态统计

    http://shapeblue.com/

  8. Vieta定理

    一元$n$次方程$$P(x)=a_{n}x^{n}+a_{n-1}x^{n-1}+\cdots+a_{a}x+a_{0}=a_{n}(x-x_{1})(x-x_{2})\cdots (x-x_{n}) ...

  9. ecshop的smarty库还原成smarty原生库方法

    写过ecshop模板的人都晓得,他们是用所谓的dwt的文件来嵌套lbi文件进行模板的彼此调用.在咱们调取数据的时分,ecshop的默许模板只提供给咱们几个简略的句子进行调用,那么有没有办法能够把这个精 ...

  10. 关于Token

    Token Token,即计算机术语:令牌 令牌是一种能够控制站点占有媒体的特殊帧,以区别数据帧及其他控制帧.token其实说的更通俗点可以叫暗号,在一些数据传输之前,要先进行暗号的核对,不同的暗号被 ...