树
我们的数据结构包含一对一、一对多、多对多的存储关系。
我们常用的一对一的数据结构:数组以及链表;一对多的数据结构:树;多对多:图。
本文主要介绍树的常用结构 二叉树。
二叉树
二叉树基本特点
- 至多拥有一个根节点
- 每个结点最多只能拥有两个子节点
- 每个节点的任意两个左右子树分别为二叉树
二叉树又包含三种特殊形态:斜树、满二叉树、完全二叉树
斜树
- 当二叉树的所有的结点都只有左子树的二叉树叫做左斜树;
- 当二叉树的所有的结点都只有右子树的二叉树叫做右斜树;
满二叉树
- 假设一个二叉树的深度为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;
}