二叉树(全)
一、二叉树定义:
二叉树是树结构的一种,至于两者的定义看图即可:
1、树
2、二叉树
二、二叉树的创建
1、结点的实现
和表示链表一样,我们可以使用一个内部类类来表示二叉树的一个节点:
//定义树节点
public static class TreeNode{
int val;
TreeNode left,right;
TreeNode(int val){ this.val = val;}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
2、二叉树的构建
创建好二叉树的结点之后,便需要通过结点创建二叉树。那么该如何创建二叉树呢?最简单的方法便是先创建出所有的结点,然后依次将所有的结点进行链接,当然该方法比较麻烦。其实在刷题过程中便发现题目的测试用例都是通过数组给出的,因此在这里给出了一种通过数组创建二叉树的方法:
//定义二叉树
public static class BT{
TreeNode root; //给出二叉树的根结点
BT(Integer[] arr){ //二叉树的构造方法,使用Integer数组,可以使用null
int n = arr.length;
ArrayList<TreeNode> nodes = new ArrayList<>(); //将数组中的元素转化为结点并保存在集合中
for (int i = 0; i < n; i++) {
if (arr[i]==null) nodes.add(null);
else nodes.add(new TreeNode(arr[i],null,null));
}
LinkedList<TreeNode> queue = new LinkedList<>();
TreeNode temp = nodes.get(0);
boolean flag=true;
//遍历结点集合
for (int i = 1; i < n; i++) {
if (flag){ //挂左子结点
temp.left=nodes.get(i);
if (nodes.get(i)!=null) queue.offer(nodes.get(i));
flag=false;
}
else { //挂右子结点
temp.right=nodes.get(i);
if (nodes.get(i)!=null) queue.offer(nodes.get(i));
flag = true;
temp = queue.poll(); //改变悬挂点
}
}
this.root = nodes.get(0);
}
}
三、二叉树的遍历
1、遍历分类
(1)前序遍历:先访问根节点,再访问左子树,最后访问右子树(中左右)
(2)中序遍历:先访问左子树,再访问根节点,最后访问右子树(左中右)
(3)后序遍历:先访问左子树,再访问右子树,最后访问根节点(左右中)
(4)层序遍历:由上到下,由左到右进行遍历
(5)Z型遍历:由上到下,左右交替
【注意】在进行遍历的时候需要用到递归的思想,例如要访问左子树,当左子树仍是一个二叉树时,便需要将其当做新的二叉树进行遍历
2、代码实现
(1)顺序遍历
递归即可
//前、中、后序遍历
public static void preTra(TreeNode root){
if (root==null) return;
System.out.println(root.val);
preTra(root.left);
preTra(root.right);
}
(2)层序遍历
可分为分层和不分层两种:分层指的是将不同层的元素相互隔开,分开保存;不分层指的是依次输出遍历结果,不同层之间不进行区分
//层序遍历(不分层)
public static void layerTra(TreeNode root){
if (root==null) return;
LinkedList<TreeNode> Nodes = new LinkedList<>();
Nodes.offer(root);
while(!Nodes.isEmpty()){
TreeNode temp = Nodes.poll();
System.out.println(temp.val);
if (temp.left!=null) Nodes.offer(temp.left);
if (temp.right!=null) Nodes.offer(temp.right);
}
}
//层序遍历(分层)
public static List<List<Integer>> layerTra1(TreeNode root){
if (root==null) return null;
List<List<Integer>> result = new ArrayList<>(); //保存结果
LinkedList<TreeNode> Nodes = new LinkedList<>(); //创建队列保存每一层的节点
Nodes.offer(root);
while(!Nodes.isEmpty()){
List<Integer> res = new ArrayList<>();
int n = Nodes.size();
for (int i = 0; i < n; i++) {
TreeNode temp = Nodes.poll();
res.add(temp.val);
if (temp.left!=null) Nodes.offer(temp.left);
if (temp.right!=null) Nodes.offer(temp.right);
}
result.add(res);
}
return result;
}
(3)Z型遍历
在层序遍历的基础上加一个flag标志位,控制左右切换
//Z型遍历
public static void zTra(TreeNode root){
Queue<TreeNode> nodes = new LinkedList<>();
nodes.offer(root);
boolean flag =false;
while (!nodes.isEmpty()){
int n = nodes.size();
ArrayList<Integer> res = new ArrayList<>();
for (int i = 0; i < n; i++) {
TreeNode temp = nodes.poll();
res.add(temp.val);
if (temp.left!=null) nodes.offer(temp.left);
if (temp.right!=null) nodes.offer(temp.right);
}
if (flag) {
for (Integer x : res) {
System.out.println(x);
}
flag = !flag;
}
else {
for (int i = res.size()-1; i >=0; i--) {
System.out.println(res.get(i));
}
flag = !flag;
}
}
}
四、二叉树的其他操作
1、左右翻转
//左右翻转
public static TreeNode reverse(TreeNode root){
if (root==null) return null; //递归结束条件
TreeNode temp = root.left; //左右交换
root.left = root.right;
root.right = temp;
reverse(root.left); //递归调用
reverse(root.right);
return root;
}
2、最大深度
//最大深度
public static int maxDepth(TreeNode root){
if (root==null) return 0;
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return Math.max(left,right)+1;
}
3、最小深度
//最小深度
public static int minDepth(TreeNode root){
if (root==null) return 0;
int left = minDepth(root.left);
int right = minDepth(root.right);
if (left==0) return right+1;
else if (right==0) return left+1;
else return Math.min(left,right)+1;
}
五、下面给出整体的代码:
package binarytree;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
public class binarytree {
public static void main(String[] args) {
//测试函数
Integer[] a = {1,2,3,null,null,4,5,6};
Integer[] b = {3,9,20,null,null,15,7};
BT bt = new BT(a);
System.out.println(maxDepth(bt.root));
System.out.println(minDepth(bt.root));
// layerTra(bt.root);
// System.out.println("===");
/*
List<List<Integer>> lists = layerTra1(bt.root);
for (int i = 0; i < lists.size(); i++) {
for (int j = 0; j < lists.get(i).size(); j++) {
System.out.println(lists.get(i).get(j));
}
System.out.println("===");
}
*/
}
//前序遍历
public static void preTra(TreeNode root){
if (root==null) return;
System.out.println(root.val);
preTra(root.left);
preTra(root.right);
}
//层序遍历(不分层)
public static void layerTra(TreeNode root){
if (root==null) return;
LinkedList<TreeNode> Nodes = new LinkedList<>();
Nodes.offer(root);
while(!Nodes.isEmpty()){
TreeNode temp = Nodes.poll();
System.out.println(temp.val);
if (temp.left!=null) Nodes.offer(temp.left);
if (temp.right!=null) Nodes.offer(temp.right);
}
}
//层序遍历(分层)
public static List<List<Integer>> layerTra1(TreeNode root){
if (root==null) return null;
List<List<Integer>> result = new ArrayList<>(); //保存结果
LinkedList<TreeNode> Nodes = new LinkedList<>(); //创建队列保存每一层的节点
Nodes.offer(root);
while(!Nodes.isEmpty()){
List<Integer> res = new ArrayList<>();
int n = Nodes.size();
for (int i = 0; i < n; i++) {
TreeNode temp = Nodes.poll();
res.add(temp.val);
if (temp.left!=null) Nodes.offer(temp.left);
if (temp.right!=null) Nodes.offer(temp.right);
}
result.add(res);
}
return result;
}
//Z型遍历
public static void zTra(TreeNode root){
Queue<TreeNode> nodes = new LinkedList<>();
nodes.offer(root);
boolean flag =false;
while (!nodes.isEmpty()){
int n = nodes.size();
ArrayList<Integer> res = new ArrayList<>();
for (int i = 0; i < n; i++) {
TreeNode temp = nodes.poll();
res.add(temp.val);
if (temp.left!=null) nodes.offer(temp.left);
if (temp.right!=null) nodes.offer(temp.right);
}
if (flag) {
for (Integer x : res) {
System.out.println(x);
}
flag = !flag;
}
else {
for (int i = res.size()-1; i >=0; i--) {
System.out.println(res.get(i));
}
flag = !flag;
}
}
}
//左右翻转
public static TreeNode reverse(TreeNode root){
if (root==null) return null; //递归结束条件
TreeNode temp = root.left; //左右交换
root.left = root.right;
root.right = temp;
reverse(root.left); //递归调用
reverse(root.right);
return root;
}
//最大深度
public static int maxDepth(TreeNode root){
if (root==null) return 0;
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return Math.max(left,right)+1;
}
//最小深度
public static int minDepth(TreeNode root){
if (root==null) return 0;
int left = minDepth(root.left);
int right = minDepth(root.right);
if (left==0) return right+1;
else if (right==0) return left+1;
else return Math.min(left,right)+1;
}
//定义树节点
public static class TreeNode{
int val;
TreeNode left,right;
TreeNode(int val){ this.val = val;}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
//定义二叉树
public static class BT{
TreeNode root; //给出二叉树的根结点
BT(Integer[] arr){ //二叉树的构造方法,使用Integer数组,可以使用null
int n = arr.length;
ArrayList<TreeNode> nodes = new ArrayList<>(); //将数组中的元素转化为结点并保存在集合中
for (int i = 0; i < n; i++) {
if (arr[i]==null) nodes.add(null);
else nodes.add(new TreeNode(arr[i],null,null));
}
LinkedList<TreeNode> queue = new LinkedList<>();
TreeNode temp = nodes.get(0);
boolean flag=true;
//遍历结点集合
for (int i = 1; i < n; i++) {
if (flag){ //挂左子结点
temp.left=nodes.get(i);
if (nodes.get(i)!=null) queue.offer(nodes.get(i));
flag=false;
}
else { //挂右子结点
temp.right=nodes.get(i);
if (nodes.get(i)!=null) queue.offer(nodes.get(i));
flag = true;
temp = queue.poll(); //改变悬挂点
}
}
this.root = nodes.get(0);
}
}
}