Java数据结构之二叉树及其源码实现

我们的数据结构包含一对一、一对多、多对多的存储关系。
我们常用的一对一的数据结构:数组以及链表;一对多的数据结构:树;多对多:图。
本文主要介绍树的常用结构 二叉树。

二叉树

二叉树基本特点

  • 至多拥有一个根节点
  • 每个结点最多只能拥有两个子节点
  • 每个节点的任意两个左右子树分别为二叉树

二叉树又包含三种特殊形态:斜树、满二叉树、完全二叉树

斜树

  • 当二叉树的所有的结点都只有左子树的二叉树叫做左斜树
  • 当二叉树的所有的结点都只有右子树的二叉树叫做右斜树

满二叉树

  • 假设一个二叉树的深度为N,在这N层中,每一层的结点都达到最大值,即为满二叉树
  • 满二叉树的结点个数满足2^n-1;

完全二叉树

  • 假设一个二叉树的深度为N,在N-1层中,每层的结点都达到了最大值,且第N层中,所有的结点都位于最左侧且连续,则称为完全二叉树

代码实现

//二叉树

class JZ26TreeNode{
    
    

    int val;//本结点存储数据
    JZ26TreeNode left;//存储左子树地址
    JZ26TreeNode right;//存储右子树地址

    //构造方法 传入结点值
    public JZ26TreeNode(int x){
    
    
        this.val = x;
    }

}

生成二叉树

public class JZ26 {
    
    
    public static void main(String[] args) {
    
    
        //二叉树 根节点
        JZ26TreeNode root = new JZ26TreeNode(3);
        //根节点左子树
        JZ26TreeNode left01 = new JZ26TreeNode(9);
        //根结点右子树
        JZ26TreeNode right01 = new JZ26TreeNode(20);
        //将根节点左右子树分别与根节点相关联
        root.left = left01;
        root.right = right01;
        
        //根节点右子树的左子树
        JZ26TreeNode right01Left  = new JZ26TreeNode(15);
        //根节点右子树的右子树
        JZ26TreeNode right01Right =  new JZ26TreeNode(7);
   
        //给根节点右子树分别关联
        right01.left = right01Left;
        right01.right = right01Right;
    }
}

大家应该脑补出上图的二叉树了 ,这里我给大家画了一下

在这里插入图片描述

打印二叉树(广度优先遍历)

查看了网上的多种打印方式 ,都是要借助容器来实现的,先存储后打印,采取队列应该是最方便一种方式 ,队列先进先出

//借助queue打印二叉树
    public static void main(String[] args) {
    
    
        //二叉树 根节点
        JZ26TreeNode root = new JZ26TreeNode(3);
        //根节点左子树
        JZ26TreeNode left01 = new JZ26TreeNode(9);
        //根结点右子树
        JZ26TreeNode right01 = new JZ26TreeNode(20);
        //将根节点左右子树分别与根节点相关联
        root.left = left01;
        root.right = right01;

        //根节点右子树的左子树
        JZ26TreeNode right01Left  = new JZ26TreeNode(15);
        //根节点右子树的右子树
        JZ26TreeNode right01Right =  new JZ26TreeNode(7);

        //给根节点右子树分别赋值
        right01.left = right01Left;
        right01.right = right01Right;

        binaryTree(root);

    }

//打印二叉树 广度优先遍历
    public static void binaryTree(JZ26TreeNode root){
    
    
        //生成队列 将根节点存储至队列
        Queue<JZ26TreeNode> queue = new LinkedList();
        queue.add(root);
        //queue为空 跳出循环
        while (!queue.isEmpty()){
    
    
            JZ26TreeNode poll = queue.poll();
            //队列头部元素取出 打印
            System.out.println("二叉树元素为 :"+poll.val);
            //将头部元素的左右结点分别添加至队列 (非空情况)
            if(poll.left!=null) queue.add(poll.left);
            if(poll.right!=null) queue.add(poll.right);
        }
    }

打印结果为:

在这里插入图片描述

算法题

基本二叉树生成了 这里我们来做一道二叉树的算法题 ; (leetcode 剑指offer 第32题)

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回:

[3,9,20,15,7]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

聪明的同学已经发现了 这道题的二叉树就是上面我们已经实现的。 下面我们开始编码。

/*
先说一下思路 题目要求每层从上至下 从左到右顺序存储元素。
根据二叉树的存储规则 我们只能从根节点开始,每次拿到结点的左右结点(非空情况)
但是拿到的左右结点也有可能分别有子左右结点。故采取队列协助打印。
题目要求返回int[]  
上面我们已经学会打印了 那么这道题把打印变成存储int[] 即可。

*/  
    public static void main(String[] args) {
    
    
        //二叉树 根节点
        JZ26TreeNode root = new JZ26TreeNode(3);
        //根节点左子树
        JZ26TreeNode left01 = new JZ26TreeNode(9);
        //根结点右子树
        JZ26TreeNode right01 = new JZ26TreeNode(20);
        //将根节点左右子树分别与根节点相关联
        root.left = left01;
        root.right = right01;

        //根节点右子树的左子树
        JZ26TreeNode right01Left  = new JZ26TreeNode(15);
        //根节点右子树的右子树
        JZ26TreeNode right01Right =  new JZ26TreeNode(7);

        //给根节点右子树分别赋值
        right01.left = right01Left;
        right01.right = right01Right;

        int[] ints = binaryTree(root);
        for(int i: ints){
    
    
            System.out.println("数组元素为:"+i);
        }

    }

    public static int[] binaryTree(JZ26TreeNode root){
    
    
        //生成队列 将根节点存储至队列
        Queue<JZ26TreeNode> queue = new LinkedList();
        queue.add(root);
        List<Integer> res = new ArrayList<>();
        //queue为空 跳出循环
        while (!queue.isEmpty()){
    
    
            JZ26TreeNode poll = queue.poll();
            //取出头元素添加至list
            res.add(poll.val);

            //将头部元素的左右结点分别添加至队列 (非空情况)
            if(poll.left!=null) queue.add(poll.left);
            if(poll.right!=null) queue.add(poll.right);
        }
        int[] tar = new int[res.size()];
        //循环列表添加至数组
        for (int i = 0; i < res.size(); i++) {
    
    
            tar[i] = res.get(i);
        }
        return tar;
    }



猜你喜欢

转载自blog.csdn.net/pgcdnameming/article/details/124481715