`
128kj
  • 浏览: 601347 次
  • 来自: ...
社区版块
存档分类
最新评论

学习“五大经典查找”(3)

阅读更多
今天就聊聊这个”五大经典查找“中的最后一个”二叉排序树“,又叫二叉查找树。

1. 概念


如图就是一棵二叉排序树:


2.实际操作:

    我们都知道,对一个东西进行操作,无非就是增删查改,接下来我们就聊聊其中的基本操作。

    <1> 插入:相信大家对“排序树”的概念都清楚了吧,那么插入的原理就很简单了。
比如说我们插入一个20到这棵树中。

首先:20跟50比,发现20是老小,不得已,得要归结到50的左子树中去比较。
然后:20跟30比,发现20还是老小。
再然后:20跟10比,发现自己是老大,随即插入到10的右子树中。
最后: 效果呈现图如下:



<2>查找:相信懂得了插入,查找就跟容易理解了。

就拿上面一幅图来说,比如我想找到节点10.

首先:10跟50比,发现10是老小,则在50的左子树中找。
然后:10跟30比,发现还是老小,则在30的左子树中找。
再然后:  10跟10比,发现一样,然后就返回找到的信号。
        
<3>删除:删除节点在树中还是比较麻烦的,主要有三种情况。

《1》 删除的是“叶节点20“,这种情况还是比较简单的,删除20不会破坏树的结构。如图:



《2》删除”单孩子节点90“,这个情况相比第一种要麻烦一点点,需要把他的孩子顶上去。


《3》删除“左右孩子都有的节点50”,这个让我在代码编写上纠结了好长时间,问题很直白,我把50删掉了,谁顶上去了问题,是左孩子呢?还是右孩子呢?还是另有蹊跷?这里我就坦白吧,不知道大家可否知道“二叉树”的中序遍历,现在可以当公式记住吧,就是找到右节点的左子树最左孩子。

比如:首先 找到50的右孩子70。
然后  找到70的最左孩子,发现没有,则返回自己。
最后  原始图和最终图如下。





3.说了这么多,上代码说话。

//二叉搜索树
public class BinarySearchTree<T extends Comparable<? super T>>
{

   /** 二叉排序树的根 */
    private BinaryNode<T> root;

    /**
     * 构造一棵空树.
     */
    public BinarySearchTree( )
    {
        root = null;
    }

    /**
     * 在二叉搜索树中插入数据.
     * @param x the item to insert.
     */
    public void insert( T x )
    {
        root = insert( x, root );
    }

    /**
     * 从二叉搜索中删除数据(节点).
     * @param x the item to remove.
     */
    public void remove( T x )
    {
        root = remove( x, root );
    }

    /**
     * 找最小数据.
     * @return smallest item or null if empty.
     */
    public T findMin( )
    {
        if( isEmpty( ) )
            throw new UnderflowException( );
        return findMin( root ).element;
    }

    /**
     * 找最大数据.
     * @return the largest item of null if empty.
     */
    public T findMax( )
    {
        if( isEmpty( ) )
            throw new UnderflowException( );
        return findMax( root ).element;
    }

    //二叉搜索树中是否包含x
    public boolean contains( T x )
    {
        return contains( x, root );
    }

   
    public void makeEmpty( )
    {
        root = null;
    }

   
    public boolean isEmpty( )
    {
        return root == null;
    }

   //中序遍历输出二叉搜索树的内容
    public void printTree( )
    {
        if( isEmpty( ) )
            System.out.println( "Empty tree" );
        else
            printTree( root );
    }

    //插入
    private BinaryNode<T> insert( T x, BinaryNode<T> t )
    {
        if( t == null )
            return new BinaryNode<T>( 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<T> remove( T x, BinaryNode<T> t )
    {
         //先在树中查找x   
        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 );
        //在树中找到了节点值为x的节点
        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 BinaryNode<T> findMin( BinaryNode<T> t )
    {
        if( t == null )
            return null;
        else if( t.left == null )
            return t;
        return findMin( t.left );
    }

    //在二叉搜索树中找最大值节点
    private BinaryNode<T> findMax( BinaryNode<T> t )
    {
        if( t != null )
            while( t.right != null )
                t = t.right;

        return t;
    }

   //是否包含
    private boolean contains( T x, BinaryNode<T> t )
    {
        if( t == null )
            return false;
            
        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;    // Match
    }

   //中序遍历二叉树
    private void printTree( BinaryNode<T> t )
    {
        if( t != null )
        {
            printTree( t.left );
            System.out.print(t.element+"  ");
            printTree( t.right );
        }
       
    }

    // 二叉搜索树节点
    private static class BinaryNode<T>
    {
            // Constructors
        BinaryNode( T theElement )
        {
            this( theElement, null, null );
        }

        BinaryNode( T theElement, BinaryNode<T> lt, BinaryNode<T> rt )
        {
            element  = theElement;
            left     = lt;
            right    = rt;
        }

        T element;            // The data in the node
        BinaryNode<T> left;   // Left child
        BinaryNode<T> right;  // Right child
    }


      

        // 测试
    public static void main( String [ ] args )
    {
         //创建二叉排序树   
        int list[]={ 50, 30, 70, 10, 40, 90, 80};
        BinarySearchTree<Integer> bsTree = new BinarySearchTree<Integer>( );
         for( int i = 0; i<list.length;i++)
            bsTree.insert( list[i] );
      
           System.out.println("中序遍历的原始数据:");  
            //中序遍历   
           bsTree.printTree( );
           System.out.printf("\n--------------------------------");  

         //查找一个节点   
       System.out.printf("\n10在二叉树中是否包含:" + bsTree.contains(new Integer(10)));  
   
           System.out.printf("\n---------------------------------");  

        //插入一个节点   
             bsTree.insert(20);  
   
             System.out.printf("\n20插入到二叉树,中序遍历后:");  
   
             //中序遍历   
             bsTree.printTree();  
             System.out.printf("\n-----------------------------------\n");  

          System.out.printf("删除叶子节点 20, \n中序遍历后:");  
   
             //删除一个节点(叶子节点)   
             bsTree.remove(new Integer(20));  
   
             //再次中序遍历   
             bsTree.printTree();   
             System.out.printf("\n****************************************\n");  
   
             System.out.printf("删除单孩子节点 90, \n中序遍历后:");  
   
             //删除单孩子节点   
             bsTree.remove(new Integer(90));  
   
             //再次中序遍历   
             bsTree.printTree();  
             System.out.printf("\n****************************************\n");  

             System.out.printf("删除根节点 50, \n中序遍历后:");  
             //删除根节点   
             bsTree.remove(new Integer(50));  
             bsTree.printTree();      
           
    }
}

public class UnderflowException extends RuntimeException{}


运行结果:

D:\java>java   BinarySearchTree
中序遍历的原始数据:
10  30  40  50  70  80  90
------------------------------------------------
10在二叉树中是否包含:true
--------------------------------------------------
20插入到二叉树,中序遍历后:10  20  30  40  50  70  80  90
-------------------------------------------------
删除叶子节点 20,
中序遍历后:10  30  40  50  70  80  90
*************************************************
删除单孩子节点 90,
中序遍历后:10  30  40  50  70  80
************************************************
删除根节点 50,
中序遍历后:10  30  40  70  80

值的注意的是:二叉排序树同样采用“空间换时间”的做法。

突然发现,二叉排序树的中序遍历同样可以排序数组,呵呵,不错!

PS:  插入操作:O(LogN)。

       删除操作:O(LogN)。

       查找操作:O(LogN)。

下载源码:
  • 大小: 15.4 KB
  • 大小: 17.6 KB
  • 大小: 19.7 KB
  • 大小: 21 KB
  • 大小: 21.3 KB
  • 大小: 21.1 KB
  • 大小: 17.2 KB
分享到:
评论

相关推荐

    算法系列15天速成 第六天 五大经典查找【下】

    由于它的有序性,可以快速定位数据,使得搜索时间复杂度降低至O(log n),在数据量大时具有明显优势。 ### 总结 掌握二叉排序树的原理及其操作是数据结构与算法学习中的一个重要里程碑。理解其动态平衡的过程和对...

    解析lookup的经典查找方式.docx

    本篇主要解析lookup的经典查找方式,特别是向量形式的应用,以及如何利用lookup函数进行条件查找。 **一、lookup函数基本用法** lookup函数的向量形式语法为:`LOOKUP(lookup_value, lookup_vector, result_vector...

    算法系列15天速成 第四天 五大经典查找【上】

    在本篇中,我们将探讨两种经典的查找算法:顺序查找和折半查找。这两种算法在日常生活中有着广泛的应用,例如寻找班级中最漂亮的女生或猜测年龄等。 首先,我们来看顺序查找(Sequential Search)。顺序查找是最...

    数据结构课程设计-查找

    本课程设计主要关注五种不同的查找算法:顺序查找、折半查找、二叉树查找、二叉排序树查找以及哈希查找。这些方法在不同的场景下各有优势,理解并比较它们的性能对于优化算法和提高程序效率至关重要。 一、实践目的...

    第五章:查找-2021-11

    《第五章:查找》 本章内容主要涵盖了数据结构与算法中的查找技术,适用于计算机科学与技术学院的学生学习。查找是数据处理中的基础操作,它根据给定的值在数据集合中寻找相应记录或元素的过程。本章将深入探讨多种...

    C++数据结构折半查找法(二分查找)

    总的来说,二分查找法是C++数据结构学习中的一个重要部分,对于提高程序的运行效率有着重要作用。理解并能熟练运用二分查找法,将有助于提升作为程序员的数据处理能力。通过不断的实践和练习,初学者可以更好地掌握...

    C++ 二分查找法

    ### C++ 二分查找法详解 在计算机科学领域,数据结构与算法是核心课程之一,其中二分查找法(Binary Search)是一种高效的查找技术...在未来的学习和工作中,合理运用二分查找法将极大地提升数据处理的效率和准确性。

    acm折半查找法参考代码

    在ACM(国际大学生程序设计竞赛)中...总结,折半查找法是编程中的一种高效查找策略,尤其适用于处理大规模有序数据。通过熟练掌握这种算法,可以提升在ACM等编程竞赛中的竞争力,并在实际项目开发中优化数据处理性能。

    算法系列15天速成 第五天 五大经典查找【中】

    ### 知识点详解 #### 一、哈希查找简介 哈希查找是一种高效的数据查找方法,能够在平均情况下实现O(1)的时间复杂度。...通过这段代码的学习,可以帮助我们更好地理解哈希查找的工作原理及其应用场景。

    二分查找算法FLASH演示

    综上所述,二分查找算法是数据结构与算法学习中的重要概念,理解其原理并能熟练运用,对于提升编程能力大有裨益。通过提供的"二分查找.swf"文件,初学者可以通过动画演示更直观地理解和掌握这一算法。

    数据结构实验五查找的实现.doc

    数据结构实验五主要探讨了两种查找方法的实现:线性查找和折半查找。这两种查找方法都是在数组或表中定位特定元素的关键技术,在实际编程和数据处理中有着广泛的应用。 1. 线性查找(Linear Search): 线性查找是...

    数据结构7.3树表查找

    通过这些知识点的学习,可以帮助读者更好地理解如何利用二叉排序树进行高效的查找操作。 #### 二、二叉排序树简介 二叉排序树(Binary Search Tree, BST),又称二叉查找树,是一种特殊的二叉树,具有以下性质: 1....

    数据结构 查找

    #### 五、哈希查找 **5.1 系统简介** 哈希查找是一种高效的数据查找方法,它利用哈希函数将关键字映射到一个特定的索引位置,从而快速定位元素。 **5.2 设计思路** 哈希查找的基本步骤: 1. 选择合适的哈希函数...

    深大算法实验五——查找所有的桥

    在深大算法实验五中,主题是“查找所有的桥”,这是一个经典的图论问题,与数据结构和算法密切相关。桥在图论中指的是图中的一种特殊连接结构,如果去掉这个边,会导致原来的连通分量数量增加,即桥是维持图连通性的...

    数据结构查找教学,内含五个视频(前版).zip

    在本教学资料中,主要介绍了五种不同的查找方法,这些方法是数据结构和算法学习的基础,对于理解和优化程序性能至关重要。 首先,我们来看**顺序查找**。顺序查找是最基础的查找方法,它遍历数据序列,逐个比较元素...

    C#查找窗口句柄的方法

    - Pinvoke.net: 一个关于P/Invoke签名的在线数据库,可以快速查找和学习API函数的C#实现。 - CodeProject: 包含许多C#与Windows API交互的实例项目和技术文章。 总结,C#查找窗口句柄是通过调用Windows API实现的,...

    谭浩强c语言第五版教材学习课件

    "谭浩强C语言第五版教材学习课件"正是基于他的经典著作,为学习者提供了一套系统的、易于理解的教学资源。 这个课件可能包含PPT演示文稿、习题解答、代码示例和教学视频等多种形式,旨在帮助初学者掌握C语言的基础...

    任意文件中查找字符串程序_

    通过对其使用方法及源代码的解析,我们不仅了解了如何在DOS环境下进行字符串查找,还学习了如何利用C语言实现文件操作及字符串处理的基本技巧。这对于深入理解早期操作系统的工作原理以及编程实践具有重要意义。

    基于二分法的从词库中查找单词源代码

    ### 基于二分法的从词库中查找单词 ...通过对基于二分法的词库查找算法的学习,我们了解到了如何高效地在一个有序数组中查找特定元素。这种算法在实际应用中具有广泛的价值,尤其是在处理大量数据时能够显著提升性能。

Global site tag (gtag.js) - Google Analytics