Java程序员面试笔试宝典之二叉树

本文详细介绍了二叉排序树的基本概念及其构建、遍历、删除等核心操作,并提供了完整的Java实现代码。此外,还探讨了如何通过前序和中序遍历来重建二叉树结构,以及如何计算二叉树中节点间的最大距离。

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

class TreeNode{
    int data;
    TreeNode left,right;
    public TreeNode(int data){
        this.data=data;
        left=null;
        right=null;
    }
}
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;


/**
 * 实现二叉排序树
 * 二叉排序树:它或者是一棵空树,或者是具有如下性质的一棵树:
 * ①如果左子树不为空,那么左子树上所有节点的值均小于等于它的根节点的值;
 * ②如果右子树不为空,那么右子树上所有节点的值均大于等于它的根节点的值;
 * ③左右子树分别也是二叉排序树。
 */
public class MyBinaryTree {

    private TreeNode root;
    public MyBinaryTree(){
        root=null;
    }

    //将数值输入构建二叉树
    public void buildTree(int [] data){
        for(int i=0;i<data.length;i++){
            insert(data[i]);
        }
    }
    //插入
    public void insert(int data){
        TreeNode newNode=new TreeNode(data);
        if(root==null){
            root=newNode;
        }else{
            TreeNode current=root;
            TreeNode parent;
            while(true){//寻找插入的位置
                parent=current;
                if(data<current.data){
                    current=current.left;
                    if(current==null){
                        parent.left=newNode;
                        return ;
                    }
                }else{
                    current=current.right;
                    if(current==null){
                        parent.right=newNode;
                        return ;
                    }
                }
            }
        }
    }
    //删除
    public void delete(int data){
        if(root==null){
            return ;
        }
        if(root.data==data){//删除根节点
            TreeNode newRoot=newRoot(root);
            newRoot.left=root.left;
            newRoot.right=root.right;
            root=newRoot;
            return ;
        }else {//删除非根节点
            TreeNode parent=root;
            TreeNode current=root;
            while(true){
                if(current.data>data){
                    parent=current;
                    current=current.left;
                    if(current==null){
                        return ;
                    }
                }else if(current.data<data){
                    parent=current;
                    current=current.right;
                    if(current==null){
                        return ;
                    }
                }else{
                    TreeNode left=current.left;
                    TreeNode right=current.right;
                    int flag=0;
                    if(parent.left==current){
                        flag=1;
                    }
                    TreeNode node=newRoot(current);
                    if(node!=left){//这句必须得加
                        node.left=left;                     
                    }
                    node.right=right;
                    if(flag==1){
                        parent.left=node;
                    }else{
                        parent.right=node;
                    }
                    return ;
                }
            }
        }

    }
    public TreeNode newRoot(TreeNode root){
        if(root.left==null){
             TreeNode node=root.right;
             root.right=null;
             return node;
        }else if(root.right==null){
            TreeNode node=root.left;
            root.left=null;
            return node;
        }else{
            TreeNode parent=root;
            TreeNode node=root.left;
            while(node.right!=null){
                parent=node;
                node=node.right;
            }
            if(node==parent.left){//这句必须得加
                return node;
            }else{
                parent.right=null;              
            }
            return node;
        }
    }

    //前序遍历
    public void preOrder(TreeNode localRoot){
        if(localRoot!=null){
            System.out.println(localRoot.data);
            preOrder(localRoot.left);
            preOrder(localRoot.right);
        }
    }
    public void preOrder(){
        this.preOrder(root);
    }
    //中序遍历
    public void inOrder(TreeNode localRoot){
        if(localRoot!=null){
            inOrder(localRoot.left);
            System.out.println(localRoot.data);
            inOrder(localRoot.right);
        }
    }
    public void inOrder(){
        this.inOrder(root);
    }
    //后序遍历
    public void postOrder(TreeNode localRoot){
        if(localRoot!=null){
            postOrder(localRoot.left);
            postOrder(localRoot.right);
            System.out.println(localRoot.data);
        }
    }
    public void postOrder(){
        this.postOrder(root);
    }
    //深度优先遍历
    public void dfs(TreeNode localRoot){
        if(localRoot==null){
            return ;
        }
        Stack<TreeNode> stack=new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node=stack.pop();
            System.out.println(node.data);
            if(node.right!=null){
                stack.push(node.right);
            }
            if(node.left!=null){
                stack.push(node.left);
            }
        }
    }
    public void dfs(){
        this.dfs(root);
    }
    //广度优先遍历
    public void bfs(TreeNode localRoot){
        if(localRoot==null){
            return ;
        }
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(localRoot);
        while(!queue.isEmpty()){
            TreeNode node=queue.poll();
            System.out.println(node.data);
            if(node.left!=null){
                queue.offer(node.left);
            }
            if(node.right!=null){
                queue.offer(node.right);
            }
        }
    }
    public void bfs(){
        this.bfs(root);
    }

    /**
     * 已知前序遍历和中序遍历,如何求后序遍历
     * 步骤:
     * 1.确定树的根节点。树根是当前树中所有元素在前序遍历中最先出现的元素,即先序遍历的第一个节点就是二叉树的根节点;
     * 2.求解树的子树。找到根在中序遍历的位置,位置在左边是根的左子树,位置在右边是根的右子树,如果根节点左边或右边为空,那么该方向子树为空;
     * 如果根节点左边和右边都为空,那么根节点已经为叶子节点;
     * 3.对二叉树的左右子树分别进行步骤1,2,直到求出二叉树结构为止。
     */
    public void initTree(int [] preOrder,int [] inOrder){//由前序遍历和中序遍历结果重新构造二叉排序树
        this.root=this.initTree(preOrder,0,preOrder.length-1,inOrder,0,inOrder.length-1);
        //构造出二叉树之后后序遍历二叉树
        this.postOrder();
    }
    public TreeNode initTree(int [] preOrder,int start1,int end1,int [] inOrder,int start2,int end2){
        if(start1>end1 || start2>end2){
            return null;
        }
        int rootData=preOrder[start1];
        TreeNode head=new TreeNode(rootData);
        //找到根节点在中序遍历中的位置
        int rootIndex=findIndexInArray(inOrder,rootData,start2,end2);
        head.left=initTree(preOrder,start1+1,start1+rootIndex-start2,inOrder,start2,rootIndex-1);
        head.right=initTree(preOrder,start1+rootIndex-start2+1,end1,inOrder,rootIndex+1,end2);
        return head;
    }
    public int findIndexInArray(int [] inOrder,int data,int start,int end){
        for(int i=start;i<=end;i++){
            if(inOrder[i]==data){
                return i;
            }
        }
        return -1;
    }

    /**
     * 求二叉树中节点的最大距离
     * 问题描述:节点的距离是指这两个节点之间边的个数。写一个程序求一棵二叉树中相聚最远的两个节点之间的距离。
     * 思路:距离最远的两个节点在二叉树的分布情况有三种:
     * ①相距最远的两个节点都在根节点的左子树上,则在根节点的左子树上进行求解;
     * ②相距最远的两个节点都在根节点的右子树上,则在根节点的右子树上进行求解;
     * ③相距最远的两个节点一个在根节点的左子树上,另一个在根节点的右子树上,则分别求出这两个点到根节点的距离再相加;
     */
    public int maxDistance(TreeNode localRoot){
        if(localRoot==null){
             return 0;
        }
        if(localRoot.left==null || localRoot.right==null){
            return 1;
        }
        int result=0;
        int leftMaxDistance=dfs_distance(localRoot.left);
        int rightMaxDistance=dfs_distance(localRoot.right);
        result=Math.max(maxDistance(localRoot.left), maxDistance(localRoot.right));
        result=Math.max(result, leftMaxDistance+rightMaxDistance);
        return result;
    }
    public int dfs_distance(TreeNode node){
        if(node==null){
            return 0;
        }
        if(node.left==null && node.right==null){
            return 1;
        }
        return Math.max(dfs_distance(node.left), dfs_distance(node.right))+1;
    }

    public static void main(String [] args){
        MyBinaryTree mbt=new MyBinaryTree();
        int [] array={20,10,21,5,15,3,8,12,17,2,4,7,9,11,16,18};
        mbt.buildTree(array);
        System.out.println(mbt.maxDistance(mbt.root));
        mbt.delete(5);
        mbt.bfs();
    }
}

本博客内容来自《Java程序员面试笔试宝典》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值