数据结构与算法分析java——树2(二叉树类型)

 

1. 二叉查找树

  二叉查找树(Binary Search Tree)/  有序二叉树(ordered binary tree)/ 排序二叉树(sorted binary tree)

    1). 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;

    2). 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

    3). 任意节点的左、右子树也分别为二叉查找树。

    4). 没有键值相等的节点(no duplicate nodes)。

public class BinarySearchTree<AnyType extends Comparable<? super AnyType>>{
    private static class BinaryNode<AnyType>{
        BinaryNode(AnyType theElement){
        this(theElement,null,null);
        }
    
        BinaryNode(AnyType theElement, BinaryNode<AnyType> lt, BinaryNode<AnyType>){
            element=theElement; left=lt; right= rt;
        }
    
        AnyType element;
        BinaryNode<AnyType> left;
        BinaryNode<AnyType> right;
    }
    
    private BinaryNode<AnyType> root;
    
    //构造函数
    public BinarySearchTree(){
        root=null;
    }
    
    public void makeEmpty(){
        root=null;
    }
    
    public booolean isEmpty(){
        return root==null;
    }
    
    public boolean contains(AnyType x){
        return contains(x,root);
    }
    
    public AnyType findMin()
    {
        if(isEmpty()) throw new UnderflowException();
        return findMin(root).element;
    }
    
    public AnyType findMax()
    {
        if(isEmpty()) throw new UnderflowException();
        return findMax(root).element;
    }
    
    public void insert(AnyType x){
        root=insert(x,root);
    }
    
    public void remove(AnyType x){
        root=remove(x,root);
    }
    
    public void printTree(){
        if(isEmpty())
            System.out.println("Empty tree");
        else
            printTree(root);
    }
    
    
    //二叉树的contains操作
    private boolean contains(AnyType x, BinaryNode<AnyType> t){
        
        if(t==null)
            return false;
        
        //Comparable接口的compareTo方法比较两个值
        int compareResult=x.compareTo(t.element); 
        if(compareResult<0)
            return contains(x,t.left);
        else if (compareResult>0)
            return contains(x,t.right);
        else
            return true;
    }
    
    
    //查找最小值节点
    private BinaryNode<AnyType> findMin(BinaryNode<AnyType> t){
        if(t==null) 
            return null;
        else if(t.left==null)
            return t;
        return findMin(t.left);
    }
    
    //查找最大值节点
    private BinaryNode<AnyType> findMax(BinaryNode<AnyType> t){
        if(t !=null)
            while(t.right!=null)
                t=t.right;
        return t;
    }
    
    //insert插入,返回对 新树根的引用
    private BinaryNode<AnyType> insert(AnyType x, BinaryNode<AnyType> t){
        if(t==null)
            return new BinaryNode<AnyType>(x,null,null);
        
        int compareResult=x.compareTo(t.element);
        if(compareResult<0)
            t.left=insert(x,t.left); 
        else if(compareResult >0)
            t.right=insert(x,t.right);
        else
            ;
        return t;
    }
    
    //删除节点
    private BinaryNode<AnyType> remove(AnyType x, BinaryNode<AnyType> t){
        if(t==null)
            return t;
        int compareResult=x.compareTo(t.element);
        
        if(compareResult<0)
            t.left=remove(x,t.left);
        else if(compareResult>0)
            t.right=remove(x,t.right);
        else if(t.left != null && t.right!=null){
            //两个孩子的情况,将右子树的最小值填充到该节点;
            //在右子树删除最小值节点
            t.element=findMin(t.right).element;
            t.right=remove(t.element.t.right);
        }
        else
            //只有一个孩子
            t=(t.left != null) ? t.left: t.right;
        return t;
    }
    
    private void printTree(BinaryNode<AnyType> t){
        if(t!=null)
        {
            printTree(t.left);
            System.out.println(t.element);
            printTree(t.right);
        }
    }
    
}
View Code

 

 

2. AVL树

  

  平衡二叉树定义(AVL) /  Balanced Binary Tree 或 Height-Balanced Tree:它或者是一棵空树,或者是具有一下性质的二叉查找树-- 它的结点左子树和右子树的深度之差不超过1,而且该结点的左子树和右子树都是一棵平衡二叉树。      平衡因子:结点左子树的深度-结点右子树的深度。(0、1、-1)。

  四种情况导致二叉树不平衡:

  针对四种种情况可能导致的不平衡,可以通过旋转使之变平衡。有两种基本的旋转:

      1)左旋转:将根节点旋转到(根节点的)右孩子的左孩子位置

      2)右旋转:将根节点旋转到(根节点的)左孩子的右孩子位置

(1)LL:插入一个新节点到根节点的左子树(Left)的左子树(Left),导致根节点的平衡因子由1变为2

  第一列中,在2节点左子树插入D,为了平衡,应该将{2,D}上移一层,A下移一层,以3为根即可,而原来树中B介于3和5之间,因此将B作为5的左子树;

  第二列中,在2节点的右子树插入D,同理

         

 

 

(2)RR:插入一个新节点到根节点的右子树(Right)的右子树(Right),导致根节点的平衡因子由-1变为-2

 

(3)LR:插入一个新节点到根节点的左子树(Left)的右子树(Right),导致根节点的平衡因子由1变为2

 

(4)RL:插入一个新节点到根节点的右子树(Right)的左子树(Left),导致根节点的平衡因子由-1变为-2

 

 

package com.kiritor;  
/** 
 *二叉平衡树简单实现 
 */  
public class AvlTree< T extends Comparable< ? super T>>  
{  
     private static class AvlNode< T>{//avl树节点  
          
        AvlNode( T theElement )  
        {  
            this( theElement, null, null );  
        }  
        AvlNode( T theElement, AvlNode< T> lt, AvlNode< T> rt )  
        {  
            element  = theElement;  
            left     = lt;  
            right    = rt;  
            height   = 0;  
        }  
        T           element;      // 节点中的数据  
        AvlNode< T>  left;         // 左儿子  
        AvlNode< T>  right;        // 右儿子  
        int         height;       // 节点的高度  
    }  
       
    private AvlNode< T> root;//avl树根  
     
    public AvlTree( )  
    {  
        root = null;  
    }  
   //在avl树中插入数据,重复数据复略  
    public void insert( T x )  
    {  
        root = insert( x, root );  
    }  
     
    //在avl中删除数据,这里并未实现  
    public void remove( T x )  
    {  
        System.out.println( "Sorry, remove unimplemented" );  
    }  
    
     //在avl树中找最小的数据  
    public T findMin( )  
    {  
        if( isEmpty( ) )  
            System.out.println("树空");;  
        return findMin( root ).element;  
    }  
    //在avl树中找最大的数据  
    public T findMax( )  
    {  
        if( isEmpty( ) )  
            System.out.println("树空");  
        return findMax( root ).element;  
    }  
   //搜索  
    public boolean contains( T x )  
    {  
        return contains( x, root );  
    }  
     
    public void makeEmpty( )  
    {  
        root = null;  
    }  
      
    public boolean isEmpty( )  
    {  
        return root == null;  
    }  
    //排序输出avl树  
    public void printTree( )  
    {  
        if( isEmpty( ) )  
            System.out.println( "Empty tree" );  
        else  
            printTree( root );  
    }  
      
     
    private AvlNode< T> insert( T x, AvlNode< T> t )  
    {  
        if( t == null )  
            return new AvlNode< T>( x, null, null );  
          
        int compareResult = x.compareTo( t.element );  
          
        if( compareResult < 0 )  
        {  
            t.left = insert( x, t.left );//将x插入左子树中  
            if( height( t.left ) - height( t.right ) == 2 )//打破平衡  
                if( x.compareTo( t.left.element ) < 0 )//LL型(左左型)  
                    t = rotateWithLeftChild( t );  
                else   //LR型(左右型)  
                    t = doubleWithLeftChild( t );  
        }  
        else if( compareResult > 0 )  
        {  
            t.right = insert( x, t.right );//将x插入右子树中  
            if( height( t.right ) - height( t.left ) == 2 )//打破平衡  
                if( x.compareTo( t.right.element ) > 0 )//RR型(右右型)  
                    t = rotateWithRightChild( t );  
                else                           //RL型  
                    t = doubleWithRightChild( t );  
        }  
        else  
            ;  // 重复数据,什么也不做  
        t.height = Math.max( height( t.left ), height( t.right ) ) + 1;//更新高度  
        return t;  
    }  
     
     //找最小  
    private AvlNode< T> findMin( AvlNode< T> t )  
    {  
        if( t == null )  
            return t;  
        while( t.left != null )  
            t = t.left;  
        return t;  
    }  
    //找最大  
    private AvlNode< T> findMax( AvlNode< T> t )  
    {  
        if( t == null )  
            return t;  
        while( t.right != null )  
            t = t.right;  
        return t;  
    }  
    //搜索(查找)  
    private boolean contains( T x, AvlNode t )  
    {  
        while( t != null )  
        {  
            int compareResult = x.compareTo( (T) t.element );  
              
            if( compareResult < 0 )  
                t = t.left;  
            else if( compareResult > 0 )  
                t = t.right;  
            else  
                return true;    // Match  
        }  
        return false;   // No match  
    }  
   //中序遍历avl树  
    private void printTree( AvlNode< T> t )  
    {  
        if( t != null )  
        {  
            printTree( t.left );  
            System.out.println( t.element );  
            printTree( t.right );  
        }  
    }  
  //求高度   
    private int height( AvlNode< T> t )  
    {  
        return t == null ? -1 : t.height;  
    }  
    //带左子树旋转,适用于LL型  
    private AvlNode< T> rotateWithLeftChild( AvlNode< T> k2 )  
    {  
        AvlNode< T> 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;  
    }  
    //带右子树旋转,适用于RR型  
    private AvlNode< T> rotateWithRightChild( AvlNode< T> k1 )  
    {  
        AvlNode< T> 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;  
    }  
    //双旋转,适用于LR型  
    private AvlNode< T> doubleWithLeftChild( AvlNode< T> k3 )  
    {  
        k3.left = rotateWithRightChild( k3.left );  
        return rotateWithLeftChild( k3 );  
    }  
    //双旋转,适用于RL型  
    private AvlNode< T> doubleWithRightChild( AvlNode< T> k1 )  
    {  
        k1.right = rotateWithLeftChild( k1.right );  
        return rotateWithRightChild( k1 );  
    }  
       // Test program  
    public static void main( String [ ] args )  
    {   
        AvlTree< Integer> t = new AvlTree< Integer>( );  
        final int NUMS = 200;  
        final int GAP  =   17;  
        System.out.println( "Checking... (no more output means success)" );  
        for( int i = GAP; i != 0; i = ( i + GAP ) % NUMS )  
            t.insert( i );  
           t.printTree( );  
            System.out.println(t.height(t.root));  
        
    }  
}  
View Code

 

 

3. 伸展树

伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它由Daniel Sleator和Robert Tarjan创造,后者对其进行了改进。

 

假设想要对一个二叉查找树执行一系列的查找操作。为了使整个查找时间更小,查频率高的那些条目就应当经常处于靠近树根的位置于是想到设计一个简单方法,在每次查找之后对树进行重构,把被查找的条目搬移到离树根近一些的地方。splaytree应运而生。splaytree是一种自调整形式的二叉查找树,它会沿着从某个节点到树根之间的路径,通过一系列的旋转把这个节点搬移到树根去。

 

伸展树能在O(logn)内完成插入、查找和删除作它的优势在于不需要记录用于平衡树的冗余信息。在伸展树上的一般操作都基于“伸展”操作。当查找到一个结点后,需要进行“伸展”操作,把这个结点移动到树根。至于伸展操作有两种方式:自底向上自顶向下

1)自底向上 

  所谓的自底向上就是像AVL树那样的“左旋”、“右旋”,多次操作之后把此结点旋转到树根,但这种方式,需要保存查找路径上的各个结点的指针以供旋转之用。

 

2)自顶向下

  当我们沿着树向下搜索某个节点X的时候,我们将搜索路径上的节点及其子树移走。我们构建两棵临时的树──左树和右树。

  没有被移走的节点构成的树称作中树。在伸展操作的过程中:

    1、当前节点X是中树的根。

    2、左树L保存小于X的节点。

    3、右树R保存大于X的节点。

  开始时候,X是树T的根,左右树L和R都是空的。我们以一个查找2结点的实例,来图解SplayTree的伸展过程。

 

 

 

4. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2016-04-22 15:24  zxqstrong  阅读(442)  评论(0编辑  收藏  举报