二叉搜索树需要满足的条件:
1. 所有节点最多只能有2个节点(left节点,right节点)
2. 左子树 < 根节点 < 右子树
思路: 在二叉搜索树内部,先定义一个节点对象,除了包含关键字之外,还要包含其左右节点以及父节点
每个二叉搜索树初始化时先定义一个根节点,插入的时候都从根节点开始插入, 根节点不为空,则比较其大小,
小的跟左节点比较,大的跟右节点比较, 直到找到一个符合条件的空节点
程序中不允许有相等的值插入,如果需要插入相等的值, 可以稍微修改下代码: 把所有相等的都看作是大于, 遇到第一个相等节点时, 直接插入其right节点
如果right节点已经存在,那么把已经存在的这个节点当做新节点的右节点. 对应的搜索算法也需要改变,在搜索到相等的时候,还要继续搜索下去
搜索二叉树在左右节点均衡时,性能基本接近二分搜索,但是二叉搜索树性能是否均衡严重依赖其节点加入顺序
如果按升序或者降序来逐个添加节点,那么得到的将是一个只有右子树 或者 只有左子树的二叉树, 完全是一个线性结构了
这个缺点可以通过平衡二叉树(深度差不超过1),或者红黑树(深度差不能超出1倍)来改进(jdk中多使用红黑树)
基本原理就是在插入节点导致不平衡后,需要通过旋转不平衡的节点,来保持平衡
package com.xp.test;
/**
* 二叉搜索树
* @author admin
*
* @param <T>
*/
public class MyBinaryTree<T extends Comparable<T>> {
//定义一个跟节点,初始化时为空
private TreeNode root = null;
public MyBinaryTree() {
}
/**
* 新增对象
* @param i
*/
public void add(T i) {
TreeNode node = new TreeNode(i);
//加入第一个节点时,直接将root节点指向新增的节点
if(root == null) {
root = node;
} else {
//递归新增
add(node,root);
}
}
/**
* 递归新增节点
*
* @param node1
* @param node2
*/
private void add(TreeNode node1, TreeNode node2) {
if(node2 == null) {
node2 = node1;
} else {
//等于比较节点,抛出异常
if(node1.value.compareTo(node2.value) == 0 ) {
//相同元素不允许插入
throw new RuntimeException(" 重复元素! ");
} else if(node1.value.compareTo(node2.value) > 0 ){
//大于比较的节点,那么应该插入right节点
if(node2.right != null) {
//right不为空的话,应该递归搜索右子树
add(node1,node2.right);
} else {
//right节点为空,那么将其作为比较节点的right节点并且parent指向比较节点
node2.right = node1;
node1.parent = node2;
}
} else if(node1.value .compareTo(node2.value) < 0 ) {
if(node2.left != null) {
add(node1,node2.left);
} else {
node2.left = node1;
node1.parent = node2;
}
}
}
}
/**
* 获取最小值
* @return
*/
public T getMin() {
if(root == null) {
throw new RuntimeException(" 元素为空无法获取最小值! ");
} else {
return getLeft(root).value;
}
}
/**
* 递归搜索左子树
* @param node
* @return
*/
private TreeNode getLeft(TreeNode node) {
if(node.left == null) {
return node;
} else {
return getLeft(node.left);
}
}
/**
* 获取最大值
* @return
*/
public T getMax() {
if(root == null) {
throw new RuntimeException(" 元素为空无法获取最大值! ");
} else {
return getRight(root).value;
}
}
/**
* 递归搜索右子树
* @param node
* @return
*/
private TreeNode getRight(TreeNode node) {
if(node.right == null) {
return node;
} else {
return getRight(node.right);
}
}
/**
* 从根节点开始,进行中序遍历
*/
public void iteratorLNR() {
if(root != null) {
iteratorLNR(root);
}
}
/**
* 递归遍历
* @param node
*/
private void iteratorLNR(TreeNode node) {
if(node != null) {
iteratorLNR(node.left);
System.out.println(node.value);
iteratorLNR(node.right);
}
}
/**
* 从根节点开始搜索指定的对象
* @param t
* @return
*/
public T search(T t) {
return search(root,t);
}
/**
* 对每个节点递归搜索指定的对象
* @param node
* @param t
* @return
*/
private T search(TreeNode node, T t) {
if(node == null) {
return null;
} else {
int i = t.compareTo(node.value);
if(i == 0) {
return node.value;
} else if(i > 0) {
return search(node.right,t);
} else if(i < 0) {
return search(node.left,t);
}
}
return null;
}
/**
* 内部节点,除了包含关键字之外,还包含了这个节点的left,right,parent节点的指向
* @author admin
*
*/
private class TreeNode {
private T value;
private TreeNode left;
private TreeNode right;
private TreeNode parent;
public TreeNode(T value) {
this.value = value;
}
}
public static void main(String[] args) {
MyBinaryTree<Integer> t = new MyBinaryTree<Integer>();
t.add(50);
t.add(1);
t.add(2);
t.add(5);
t.add(3);
t.add(-50);
t.add(-1);
t.add(-100);
t.add(100);
t.add(1000);
t.add(99);
t.add(10000);
System.out.println("min:" + t.getMin());
System.out.println("max:" + t.getMax());
t.iteratorLNR();
System.out.println("search value = 2 :" + t.search(2));
System.out.println("search value = 4 :" + t.search(4));
System.out.println("search value = -3 :" + t.search(-3));
}
}
执行结果:
min:-100
max:10000
-100,-50,-1,1,2,3,5,50,99,100,1000,10000,
search value = 2 :2
search value = 4 :null
search value = -3 :null