数据结构实战java实现二叉查找树

此方法参考自数据结构与算法分析-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树的分析

这里写图片描述
这里写图片描述

插入时的旋转操作

这里写图片描述
这里写图片描述
而双旋转可以看做时俩次单旋转

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值