手写数据结构之普通查找二叉树

本文介绍了查找二叉树的定义、特点及适用场景,并探讨了最佳与最差情况下的查找效率。通过中序遍历可以得到有序数组。文章还提及了平衡查找二叉树的概念,以解决普通查找二叉树分布不均的问题,并用Java实现了查找二叉树的基本操作。作者表达了对实现Iterator迭代器以高效遍历的期待。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前段时间去面试,不是算法就是源码,被问到崩溃,这是今年程序员多了,还是要求高了。算法还好吧,状态好还能写两个简单的,源码说实话我都不主动去看了,都是系统出问题了我再来以这个为切入点去看看。面试机会很多,但结果都是等通知或者薪资压榨太多,不上班就不上班把,再怎么也不能走倒退路。

哪里不会就学哪里吧,没有撤退可言。

查找二叉树的定义:所有的左子树都比节点小,所有的右子树都比节点大。(数据结构与算法分析上定义的,其实反过来定义也可以吧,左子树大右子树小)

示例图:

可以看到查找二叉树天然有序,查找某个元素,如果比节点大就往左,如果比节点小就往右。如果查找二叉树分布的好(标注1),它的查找时间是O(logN)。我们采用中序遍历它,直接可以得到一个从小到大排序的数组。

适用场景:它的综合性能很强,不论是查找,插入,删除都有很不错的性能。

标注1的解释:什么叫查找二叉树分布的好,我先讲一个最差的查找二叉树情形。如果一个按从小到大的数组转成查找二叉树会怎么样,是不是查找二叉树只有右子树这一边,其实它就成了一个链表。那么它的最坏查找时间就是O(N),但一般情况下,这个速度也是很快了,它的插入性能还不如普通的链表了。所以最好的查找二叉树就是要求趋向于完全二叉树。树的最高高度越低,它的查找就越快。

普通查找二叉树的进阶:普通的查找二叉树是很难做到分布完全,所以平衡查找二叉树应用而生。普通查找二叉树通过单旋转或双旋转操作变成平衡查找二叉树(元素分布完全,形状趋向于完全二叉树)

我用java语言来实现了一下普通的查找二叉树,增删查都有。

展望:我想内部实现一个Iterator迭代器的,方便遍历查询。但是没有想出树只遍历一遍,就迭代完成的算法。如果是两遍的话,我实现了toArray()树转数组的方法,然后数组再遍历,有思路的朋友可以分享一下。

package com.tczs.tree;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Arrays;

/**
 * 普通的查找二叉树
 * @param <T>
 * @author taoer.li
 * @date 2020.10.06
 */
public class BinarySearchTree<T extends Comparable<T>> implements Serializable{

    private int length;
    private BinaryNode root;

    private transient int index;

    public BinarySearchTree(){
        root = null;
    }

    public BinarySearchTree(T t){
        insert(t,null);
    }

    public int size(){
        return this.length;
    }

    /**
     * 插入 t 元素到树中,如果已含有t元素值大小一样的元素,则不插入
     * t 不能为 null
     * @param t
     */
    public void insert(T t){
        if(t == null) {
            throw new NullPointerException("element is null");
        }
        this.root = this.insert(t,this.root);
        length++;
    }

    private BinaryNode insert(T t, BinaryNode root){
        if(root == null){
            return new BinaryNode(t,null,null);
        }
        T old = root.element;
        if(t.compareTo(old) == -1){
            root.left = insert(t,root.left);
        }else if(t.compareTo(old) == 1) {
            root.right = insert(t,root.right);
        }
        return root;
    }

    /**
     * 去除数组中的null元素
     * @param array
     * @return
     */
    private T[] trimNull(T[] array){
        if(array.length == this.index)
            return array;
        int i;
        for(i=0;;i++){
            if(array[i] == null)
                break;
        }
        return Arrays.copyOfRange(array,0,i);
    }

    /**
     * 获取树中大于t的元素
     * @param t
     * @return
     */
    public T[] moreThan(T t){
        T[] array = initArray();
        array = moreThan(array,t,this.root);
        array = trimNull(array);
        this.index = 0;
        return array;
    }

    private T[] moreThan(T[] array,T t,BinaryNode root){
        if(root != null){
            if(t.compareTo(root.element) > -1){
                return moreThan(array,t,root.right);
            }else{
                array[index++] = root.element;
                array = traverse(root.right,array);
                return moreThan(array,t,root.left);
            }
        }
        return array;
    }

    /**
     * 获取树中比 t 小的元素
     * @param t
     * @return
     */
    public T[] lessThan(T t){
        T[] array = initArray();
        array = lessThan( array,t,this.root);
        array = trimNull( array);
        this.index = 0;
        return array;
    }

    private T[] lessThan(T[] array,T t,BinaryNode root){
        if(root != null){
            if(t.compareTo(root.element) < 1){
                return lessThan(array,t,root.left);
            }else{
                array[index++] = root.element;
                array = traverse(root.left,array);
                return lessThan(array,t,root.right);
            }
        }
        return array;
    }

    /**
     * 删除树中t元素
     * @param t
     */
    public void remove(T t){
        if(this.remove(t,this.root)){
            this.length--;
        }
    }

    private boolean remove(T o,BinaryNode root){
        //删除元素
        BinaryNode p;
        //是左还是右
        boolean pIsLeft,tIsLeft;
        //替换元素
        BinaryNode t,tParent;
        p = t = tParent = null;
        pIsLeft = tIsLeft = true;
        BinaryNode pParent = root;
        while(root != null){
            if(o.compareTo(root.element) == -1){
                pParent = root;
                root = root.left;
                pIsLeft = true;
            }else if(o.compareTo(root.element) == 1){
                pParent = root;
                root = root.right;
                pIsLeft = false;
            }else{
                p = root;
                break;
            }
        }
        if(p == null){
            return false;
        }
        tParent = root;
        if(root.right == null){
            t = root.left;
            tIsLeft = true;
        }else {
            root = root.right;
            tIsLeft = false;
            while (root != null) {
                if (root.left != null) {
                    tParent = root;
                    root = root.left;
                    tIsLeft = true;
                } else {
                    t = root;
                    break;
                }
            }
        }
        buildTree(p,pParent,pIsLeft,t,tParent,tIsLeft);
        return true;
    }

    private void buildTree(BinaryNode p,BinaryNode pParent,boolean pIsLeft,
                           BinaryNode t,BinaryNode tParent,boolean tIsLeft){
        if(t == null){
            if(pIsLeft){
                pParent.left = null;
            }else{
                pParent.right = null;
            }
        } else{
            if(tIsLeft){
                tParent.left = t.left;
            }else{
                tParent.right = t.right;
            }
            p.element = t.element;
            t.element = null;
            t.left = null;
            t.right = null;
        }
    }

    /**
     * 判断树中是否包含 t 元素
     * @param t
     * @return
     */
    public boolean contains(T t){
        return contains(t,this.root);
    }

    private boolean contains(T t,BinaryNode root){
        if(root == null)
            return false;

        T old = root.element;
        if(t.compareTo(old) == -1)
            return contains(t,root.left);
        else if (t.compareTo(old) == 1)
            return contains(t,root.right);
        else
            return true;
    }

    /**
     * 将树中的元素按以小到大的顺序收入数组中并返回
     * @return
     */
    public  T[] toArray(){
        if(root == null)
            return null;
        T[] array = initArray();
        array = traverse(this.root, array);
        this.index = 0;
        return array;
    }

    private T[] traverse(BinaryNode root,T[] array){
        if(root != null){
            array = traverse(root.left,array);
            array[this.index++] = root.element;
            array = traverse(root.right,array);
        }
        return array;
    }

    /**
     * 查询最小元素
     * @return
     */
    public T finMin(){
        return finMin(this.root);
    }

    private T finMin(BinaryNode root){
        if(root.left == null){
            return root.element;
        }else{
            return finMin(root.left);
        }
    }

    /**
     * 查询最大元素
     * @return
     */
    public T finMax(){
        return finMax(this.root);
    }

    private T finMax(BinaryNode root){
        if(root.right == null){
            return root.element;
        }else{
            return finMax(root.right);
        }
    }

    private T[] initArray(){
        BinaryNode root = this.root;
        if(root == null){
            throw new NullPointerException("root is null");
        }else {
            return (T[]) Array.newInstance(root.element.getClass(),this.length);
        }
    }

    private class BinaryNode{
        T element;
        BinaryNode left;
        BinaryNode right;

        BinaryNode(T element,BinaryNode left,BinaryNode right){
            this.element = element;
            this.left = left;
            this.right = right;
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

3wtczs93点抗母

钱癌晚期

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值