此方法参考自数据结构与算法分析-java描述
二叉树简介
形如这样的上级节点的值大于它的左支所有值,小于它的右支所有值,就叫做二叉树。
二叉树的作用
- 迅速查找
- 构造表达式
不平衡二叉树的链表实现
public class MyBinarySearchTree<AnyType extends Comparable<? super AnyType>> {
//ci此内部类构建每个的节点
private static class BinaryNode<AnyType> {
//声明节点数据,左支和右支
AnyType element;
BinaryNode<AnyType> left;
BinaryNode<AnyType> right;
//初始化一个节点
BinaryNode( AnyType theElement ) {
this( theElement, null, null);
}
//创建一个节点
BinaryNode( AnyType theElement, BinaryNode<AnyType> leftTree, BinaryNode<AnyType> rightTree ) {
element = theElement;
left = leftTree;
right = rightTree;
}
}
//声明字段 root 的类型为 BinaryNode<AnyType>
private BinaryNode<AnyType> root;
//初始化二叉查找树
public MyBinarySearchTree() {
root = null;
}
//清空树
public void makeEmpty() {
root = null;
}
//判断树是否为空
public boolean isEmpty() {
return root == null;
}
//判断树是否存在 含有项value的节点
public boolean contains( AnyType value ) {
return contains( value, root );
}
public AnyType findMin() {
try {
if ( isEmpty( ))
throw new UnderflowException("树上没有叶子");
}
catch(UnderflowException e) {
System.out.println(e);
}
return findMin( root ). element;
}
public AnyType findMax() {
try {
if ( isEmpty( ))
throw new UnderflowException("树上没有叶子");
//return findMin( root ). element;
}
catch(UnderflowException e) {
System.out.println(e);
}
return findMax( root ). element;
}
public void insert ( AnyType value ) {
root = insert( value, root );
}
public void remove( AnyType value ) {
root = remove( value, root );
}
public void printTree() {
printTree( root);
}
//判断 value是否在 tree中
private boolean contains( AnyType value, BinaryNode<AnyType> tree ) {
// 递归退出条件
if ( tree == null )
return false;
//将 value 与 节点的值进行比较
int compareResult = value.compareTo( tree.element );
if ( compareResult < 0 )
return contains( value, tree.left );
else if ( compareResult > 0 )
return contains( value, tree.right );
// 递归退出条件
else
return true;
}
//一直向左支走就是最小值
private BinaryNode<AnyType> findMin( BinaryNode<AnyType> tree ) {
if ( tree == null )
return null;
else if ( tree.left == null )
return tree;
return findMin( tree.left );
}
//一直向右支走就是最大值
private BinaryNode<AnyType> findMax( BinaryNode<AnyType> tree ) {
if ( tree == null )
return null;
else if ( tree.right == null )
return tree;
return findMin( tree.right );
}
//二叉树插入方法,此实现对于重复得数值不进行插入
private BinaryNode<AnyType> insert( AnyType value, BinaryNode<AnyType> tree ) {
if ( tree == null)
return new BinaryNode<AnyType>( value, null, null );
int compareResult = value.compareTo( tree.element);
if ( compareResult < 0)
tree.left = insert( value, tree.left );
else if ( compareResult > 0 )
tree.right = insert( value, tree.right );
// java的语言设定中,如果你创建了一个 有返回值得函数 那么在函数的第一级必须要有return。
else
;
return tree;
}
//删除节点值后需要对剩下的节点进行重排以维持一个二叉树
private BinaryNode<AnyType> remove( AnyType value, BinaryNode<AnyType> tree ) {
//删除共有4种可能性
//1 删除节点是叶片
//2 删除节点有一个子树
//3 删除节点有俩个子树
//4 删除节点不存在
if ( tree == null )
return tree;
int compareResult = value.compareTo( tree.element );
if (compareResult < 0 )
tree.left = remove( value, tree.left );
else if ( compareResult > 0 )
tree.right = remove( value, tree.right );
//俩个子树的情况
else if ( tree.left != null && tree.right != null) {
//将右子树的最小值替代 tree的数值
tree.element = findMin( tree.right ).element;
//转变为只有一个子树的情况
tree.right = remove( tree.element, tree.right );
}
else
//java 三元表达式
tree = ( tree.left != null) ? tree.left : tree.right;
return tree;
}
//打印树我选择后序遍历这种方式
private void printTree( BinaryNode<AnyType> tree ) {
if (tree == null)
return;
printTree(tree.left);
printTree(tree.right);
System.out.println(tree.element);
}
private static class UnderflowException extends Exception {
public UnderflowException() {
}
public UnderflowException(String message) {
super(message);
}
}
}
测试代码
//测试代码
public static void main(String[] args) {
MyBinarySearchTree test = new MyBinarySearchTree();
test.insert(3);
test.insert(1);
test.insert(4);
//System.out.println(test.root.right.element);
test.printTree();
}
运行结果
1
4
3
写法分析
此种方法实现的二叉树如输入一串连续的排练好的数字,此时树就会都由只有右树的节点构成。并不能很好的进行查找。
一种最古老的二叉平衡树(AVL)的实现
AVL :Adelson-Velskii 和 Landis的名字缩写。
AVL树的实现
在上面的基础上
//此内部类构建每个AVL树的节点
private static class AvlNode<AnyType> {
AnyType element;
AvlNode<AnyType> left;
AvlNode<AnyType> right;
int height;
//构建一个节点
AvlNode( AnyType theElement ) {
this( theElement, null, null);
}
AvlNode( AnyType theElement, AvlNode<AnyType> lt, AvlNode<AnyType> rt ) {
element = theElement;
left = lt;
right = rt;
height = 0;
}
}
//返回 当前节点的深度
private int height( AvlNode<AnyType> tree ) {
return tree == null ? -1 : tree.height;
}
//avl插入
private AvlNode<AnyType> AVLinsert( AnyType value, AvlNode<AnyType> tree ) {
//递归退出条件
if ( tree == null )
return new AvlNode<AnyType>( value, null, null);
int compareResult = value.compareTo( tree.element);
if( compareResult < 0) {
tree.left = AVLinsert(value, tree.left);
// 如果左树的深度要比右树深度大2,调用旋转。
if (height( tree.left) - height( tree.right) == 2)
// 如果 value 比左树的节点大调用左单旋 ,否则左双旋。
if ( value.compareTo( tree.left.element) < 0 )
tree = rotateWithLeftChild( tree);
else
tree = doubleWithleftChild( tree);
}
else if ( compareResult > 0) {
tree.right = AVLinsert(value, tree.right);
// 如果右树的深度要比左树深度大2,调用旋转。
if (height( tree.right) - height( tree.left) == 2)
// 如果 value 比右树的节点大调用右单旋 ,否则右双旋。
if ( value.compareTo( tree.right.element) < 0 )
tree = rotateWithRightChild( tree);
else
tree = doubleWithRightChild( tree);
}
else
;
//更新深度值
tree.height = Math.max(height(tree.left), height(tree.right)) + 1;
return tree;
}
//左单旋转
private AvlNode<AnyType> rotateWithLeftChild( AvlNode<AnyType> k2 ) {
AvlNode<AnyType> k1 = k2.left;
k2.left = k1.right;
k1.right = k2;
k2.height = Math.max(height( k2.left), height( k2.right)) + 1;
k1.height = Math.max(height( k1.left), k2.height) + 1;
return k1;
}
//右单旋转
private AvlNode<AnyType> rotateWithRightChild( AvlNode<AnyType> k1 ) {
AvlNode<AnyType> k2 = k1.right;
k1.right = k2.left;
k2.left = k1;
k1.height = Math.max(height( k1.left), height( k1.right)) + 1;
k2.height = Math.max(height( k2.right), k1.height) + 1;
return k2;
}
//左双旋转
private AvlNode<AnyType> doubleWithleftChild( AvlNode<AnyType> k3 ) {
//转化为俩次单旋转
k3.left = rotateWithRightChild(k3.left);
return rotateWithLeftChild(k3);
}
//右双旋转
private AvlNode<AnyType> doubleWithRightChild( AvlNode<AnyType> k3 ) {
//转化为俩次单旋转
k3.right = rotateWithLeftChild(k3.right);
return rotateWithRightChild(k3);
}
AVL树的分析
插入时的旋转操作
而双旋转可以看做时俩次单旋转