力扣上刷二叉树相关的题目时,在本地测试总是很麻烦,所以写了个工具。具体功能:
所有代码都是跑过的,拿着就能用。这里主要是记录一下,省的以后用的时候又要重写。代码都有注释,如果能够帮助到大家更好。
public class TreeNode {
public Integer val;
public TreeNode left;
public TreeNode right;
public TreeNode() {
}
public TreeNode(Integer val) {
this.val = val;
}
public TreeNode(Integer val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.LinkedList;
public class TreeProcession {
/**
* 通过一个数组建立二叉树
* @param arr 一个整型数组,按照完全二叉树的规则存储,空节点用null
* @return
*/
public TreeNode buildBTbyArray(Integer[]arr){
if(!isValidBTArray(arr)) {
System.out.println("Invalid Binary Tree Array!!!");
return null;
}
TreeNode [] tree = new TreeNode[arr.length];
for(int i=0; i<arr.length; i++){
if(arr[i]==null){
tree[i] = null;
}else {
tree[i] = new TreeNode(arr[i]);
}
}
for(int i=0; i<tree.length;i++){
if(tree[i]==null) continue;
if(2*i+1 < tree.length && tree[2*i+1]!=null){
tree[i].left = tree[2*i+1];
}
if(2*i+2 < tree.length && tree[2*i+2]!=null){
tree[i].right = tree[2*i+2];
}
}
return tree[0];
}
/**
* 判断输入的数组是否是二叉树的合法表达
* 判断规则:当一个节点为null,而其子节点不为null,则认为是非法的
* 还有末尾跟很多无意义null的情况应该也是非法,但是自己用,就不管那么多了
* @param arr
* @return
*/
public boolean isValidBTArray(Integer[]arr){
for(int i=0; i<arr.length; i++){
if(arr[i]==null){
if(2*i+1<arr.length && arr[2*i+1]!=null)
return false;
if(2*i+2<arr.length && arr[2*i+2]!=null)
return false;
}
}
return true;
}
/**
* 将一棵二叉树用null填充为满二叉树,并返回其对应存储数组
* 难点在于判断是否到达最后一层,因为对于非最后一层的null节点,同样要存入null,如果是最后一层,则不再继续存
* @param root
* @return
*/
public ArrayList<Integer> binaryTree2Array(TreeNode root){
ArrayList<ArrayList<Integer>> arr = _binaryTree2ArrayHelper(root);
ArrayList<Integer> res = new ArrayList<>();
for(ArrayList<Integer> levelArr:arr){
res.addAll(levelArr);
}
int j=res.size()-1;
while (res.get(j)==null){
res.remove(j);
j--;
}
return res;
}
/**
* 将二叉树补全为完全二叉树并将每层结果存储返回
* @param root
* @return 返回二叉树的层序遍历,每层节点单独存放
*/
private ArrayList<ArrayList<Integer>> _binaryTree2ArrayHelper(TreeNode root){
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
LinkedList<TreeNode> queue = new LinkedList<>();
int h = height(root);
int level = 1;
queue.add(root);
//通过level来发现是不是到达了最后一层
while (!queue.isEmpty() && level<h){
int length = queue.size();
ArrayList<Integer> levelArray = new ArrayList<>();
for(int i=0; i<length;i++){
TreeNode temp = queue.removeFirst();
if(temp==null){
levelArray.add(null);
queue.add(new TreeNode());
queue.add(new TreeNode());
}else {
levelArray.add(temp.val);
if(temp.left!=null){
queue.add(temp.left);
}else {
queue.add(new TreeNode());
}
if(temp.right!=null){
queue.add(temp.right);
}else {
queue.add(new TreeNode());
}
}
}
res.add(levelArray);
level++;
}
//单独处理最后一层
int length = queue.size();
ArrayList<Integer> levelArray = new ArrayList<>();
for(int i=0; i<length;i++){
TreeNode temp = queue.removeFirst();
if(temp==null){
levelArray.add(null);
}else {
levelArray.add(temp.val);
}
}
res.add(levelArray);
return res;
}
/**
* 获得一个二叉树的高度
* @param root
* @return
*/
public int height(TreeNode root){
if(root == null) return 0;
return Math.max(height(root.left),height(root.right))+1;
}
/**
* 打印图形化二叉树
* @param root 二叉树根节点
*/
public void printGraphBT(TreeNode root){
String nullC = " ^ ";
String space = " "; //打印的树中的每个节点占3个位置,当数字大于三位数时,显示会移位
ArrayList<ArrayList<Integer>> arr = _binaryTree2ArrayHelper(root);
ArrayList<StringBuilder> res = new ArrayList<>();
int h = arr.size(); //根据当前层的高度确定当前层两个节点之间的间距
for(int j=0; j<arr.size(); j++){
StringBuilder s = new StringBuilder();
ArrayList<Integer> levelArr = arr.get(j);
//将当前层的数字之间加上一定数量的空格
for(int i=0; i<levelArr.size(); i++){
if(levelArr.get(i)==null){
s.append(nullC);
}else {
//打印的树中的每个节点占3个位置,当数字大于三位数时,显示会移位
//对于负数,负号占一个位置,要用不同的格式
DecimalFormat dfP = new DecimalFormat("000");
DecimalFormat dfN = new DecimalFormat("00");
if(levelArr.get(i)>=0){
s.append(dfP.format(levelArr.get(i)));
}else {
s.append(dfN.format(levelArr.get(i)));
}
}
//本层两个节点之间的空格数 = 以本层节点为根的满二叉树节点数量
if(j>0 && i<levelArr.size()-1){
int n = (int)Math.pow(2,h)-1;
StringBuilder inserS = new StringBuilder();
for(int k=0;k<n;k++){
inserS.append(space);
}
s.append(inserS);
}
}
res.add(s);
h--;
}
//在树的某一层左右两边加空格
//空格数(左/右) = (最底层字符数-当前层字符数)/2
int len = res.get(res.size()-1).length();
for(int i=0; i<arr.size()-1;i++){
StringBuilder temp = new StringBuilder();
for(int j=0; j<(len-res.get(i).length())/2;j++){
// System.out.println(arr.get(i).size());
temp.append(' ');
}
res.get(i).insert(0,temp.toString());
res.get(i).append(temp.toString());
}
//在左右两侧加上 level 和 节点数
for(int i=0; i<arr.size();i++){
res.get(i).insert(0,"level-"+i+": ");
res.get(i).append(" nodes=").append((int)Math.pow(2, i));
}
System.out.println("【The Binary Tree is】:");
for(StringBuilder levelArr: res){
System.out.println(levelArr.toString());
}
}
/**
* 根据数组中节点打印一个图形化的二叉树
* @param arr 一个整型数组,按照完全二叉树的规则存储,空节点用null
*/
public void printGraphBT(Integer [] arr){
TreeNode root = buildBTbyArray(arr);
printGraphBT(root);
}
}
这里直接测试从数组打印二叉树 printGraphBT (Integer [] arr) 函数以及打印二叉树节点数组函数binaryTree2Array(TreeNode root),基本就测完了这里面的所有功能。
public class TestTreeUtil {
public static void main(String[]args){
Integer[] arr = {10,5,-3,3,2,null,11,3,-2,null,1};
TreeProcession process = new TreeProcession();
System.out.println(process.binaryTree2Array(process.buildBTbyArray(arr)));
process.printGraphBT(arr);
}
}