Java直观打印一棵二叉树

引言

学习堆排的过程中,总是用数组的形式来保存树型结构,输出也不是很直观。网上找过一些帖子,大家都希望能直观的打印一棵树,想到的方式也很直接,就是节点和节点之间通过斜线连接。

			1
		  /   \
	     2	   3
	   /  \    / \
	  4    5  6   7

但这样有个问题,如果树达到一定高度,斜线就很难准确的指向对应的数字,除非把斜线的角度和长度随着改变,但这样就涉及到画图,比较麻烦。我们完全可以把斜线去掉。
通过二维数组展示树图中 * 代表每个节点,去掉斜线后,无论树有多高都不会出现变形,实现起来比较简单。

思路及实现

画一棵二叉树,我们习惯从上到下,但是如果想要通过以上方式打印一棵二叉树,我们需要从下到上,首先要确定它最底层占用了多少个格子。把输出的结果想象成一个二维数组,最底层占用的格子数决定了二维数组的X轴长度,层高决定了Y轴长度。

一棵满二叉树,所有节点按顺序存放在一维数组里,存在如下规律:

每层有多少个节点:2^(n-1)
每层最起始节点的下标:2^(n-1)-1

通过以上两个规律,我们可以计算出树的高度,顺便把节点分层保存下来,方法如下:

public static void showTree(int[] array){
    int hight = 1;//层数
    int len = array.length;
    int p = 0;//节点下标
    List<List<String>> list = new ArrayList<List<String>>();//所有节点分层保存
    List<String> temp = new ArrayList<String>();//当前层节点

    while ( p < len){
        int start = (int) Math.pow(2,hight-1) - 1;//当前层起始节点下标
        int end = start + (int) (Math.pow(2,hight-1)) - 1;//当前层结束节点下标
        temp.add(p + "");
        p++;
        if(p > end || p >= len){ //当前层循环结束 或者 所有节点循环结束
            list.add(temp);
            temp = new ArrayList<String>();
            if ( p < len){ //最后一个节点层数不用累加
                hight++; //换层
            }
        }
    }
}

得到树的高度,我们就能创建出效果图中的二维数组。

int lastNum = (int)Math.pow(2,hight-1);//满二叉树最后一层的节点数
int lastLen = lastNum + (lastNum - 1); //最后一层所占数组长度(每个节点之间间隔一个位置)
String[][] tree = new String[hight][lastLen];

上面Excel图中总结的规律:

每层起始节点下标:2^(hight-n)-1
每层节点下标间隔:2^(hight)

我们把之前分层保存下来的节点,按照对应下标存入二维数组即可。

for (int i = 0,size = list.size(); i < size ; i ++) {
    List<String> strs = list.get(i);//当前层所有节点
    int tempHight = hight - i;
    int start = (int) (Math.pow(2,tempHight-1) - 1);//当前层起始节点下标
    for (String str : strs) {
        tree[i][start] = str;//节点
        int gap = (int) Math.pow(2,tempHight);//当前层节点间的间隔
        start = start + gap;//下一个节点
    }
}

至此,我们就把一维数组中保存的二叉树,按照树形结构保存到二维数组,现在只需要输出即可。

//输出树
for (int i = 0 ; i < hight ; i ++){
    for(int j = 0 ; j < lastLen ; j ++){
        String str = tree[i][j];
        System.out.format("%-2.2s",StringUtils.isEmpty(str)?"██":str);
    }
    System.out.println();
}

实际效果图

实际效果图2

实际效果图3

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值