【每日一篇】二叉树的深度与广度优先遍历及二叉树的图形化控制台输出
2018-03-08 20:26
274 查看
前文提到树与二叉树,二叉树及其子类作为常用的数据结构还是要多提一提。树的遍历方式主要分为深度优先及广度优先。而深度优先又分为中序遍历、后序遍历和前序遍历,加上广度优先也就是层次遍历,这里手写一下这四种遍历的实现。然后作为实习进行一次二叉树的图形化控制台输出好了。
1.深度优先遍历
1.1前序遍历:
public void preOrder(Node node)
{
System.out.println(node.val); //先将根节点存入list
//如果左子树不为空继续往左找,在递归调用方法的时候一直会将子树的根存入list,这就做到了先遍历根节点
if(node.leftChild != null)
{
preOrder(node.leftChild);
}
//无论走到哪一层,只要当前节点左子树为空,那么就可以在右子树上遍历,保证了根左右的遍历顺序
if(node.rightChild != null)
{
preOrder(node.rightChild);
}
}2.中序遍历 private void lterator(Node node){
if (node.leftChild!=null) {
lterator(node.leftChild);
}
System.out.println(node.val);
if (node.rightChild!=null) {
lterator(node.rightChild);
}
}3.后序遍历: public void afterOrder(Node node)
{
//如果左子树不为空继续往左找,在递归调用方法的时候一直会将子树的根存入list,这就做到了先遍历根节点
if(node.leftChild != null)
{
preOrder(node.leftChild);
}
//无论走到哪一层,只要当前节点左子树为空,那么就可以在右子树上遍历,保证了根左右的遍历顺序
if(node.rightChild != null)
{
preOrder(node.rightChild);
}
System.out.println(node.val); //将根节点输出
} ???,看起来这三种深度遍历的方法都差不多嘛,区别无非是查找后序节点与获取节点值之间的顺序区别?虽然我也是这么想的,但是并不完全如此。至少在二叉查找树(任一节点的左节点始终小于右节点)的情况下,中序遍历根据遍历的方向可以获取从小到大或从大到小的元素集,而且时间复杂度仅为O(log(n))。而后序遍历也有他的优点,因为在处理节点之前已经缺点处理过了该节点的左右两子节点,所以后序遍历适用于删除所有节点这一类的操作。
2,广度优先遍历:
public ArrayDeque<Node> levelOrderTraversal() {
if (root == null) {
System.out.println("empty tree");
return null;
}
ArrayDeque<Node> queue = new ArrayDeque<>();
ArrayDeque<Node> result = new ArrayDeque<>();
queue.add(root);
while (queue.isEmpty() == false) {
Node node = queue.remove();
result.push(node);
if (node.leftChild != null) {
queue.add(node.leftChild);
}
if (node.rightChild != null) {
queue.add(node.rightChild);
}
}
return result;
} 如上所示,广度优先情况下,会先遍历该层所有的左右节点,将其放入队列中,然后进行循环,在处理掉队列中所有元素(也就是该层所有的子节点)之后,才会遍历下一层。
那么我们可以使用这个广度优先遍历的方法遍历树并图形化输出到控制台,emmm想要显示的好看意外的难,反正意思是这个意思,等我看其他几种树的时候回优化一下:@Override
public String toString() {
ArrayDeque<Node> elements=levelOrderTraversal();
if (elements==null){
return null;
}
int height=elements.getFirst().height;
String[] lines=new String[height+1];
int[] rightCounts=new int[height+1];
// StringBuilder sb=new StringBuilder();
while (!elements.isEmpty()){
Node temp=elements.pollLast();
if (lines[temp.height]==null){
lines[temp.height]=getInterval(height+temp.right)+ temp.val;
rightCounts[temp.height]=temp.right;
}
else {
lines[temp.height]=lines[temp.height]+getInterval(temp.right-rightCounts[temp.height])+ temp.val;
}
}
String result="";
for (String string:lines){
result+=string+"\r\n";
}
return result;
}
String getInterval(int number){
if (number<=0){
return "";
}else {
StringBuilder sb=new StringBuilder();
for (int i=1;i<=number;i++){
sb.append(" ");
}
return sb.toString();
}
}
1.深度优先遍历
1.1前序遍历:
public void preOrder(Node node)
{
System.out.println(node.val); //先将根节点存入list
//如果左子树不为空继续往左找,在递归调用方法的时候一直会将子树的根存入list,这就做到了先遍历根节点
if(node.leftChild != null)
{
preOrder(node.leftChild);
}
//无论走到哪一层,只要当前节点左子树为空,那么就可以在右子树上遍历,保证了根左右的遍历顺序
if(node.rightChild != null)
{
preOrder(node.rightChild);
}
}2.中序遍历 private void lterator(Node node){
if (node.leftChild!=null) {
lterator(node.leftChild);
}
System.out.println(node.val);
if (node.rightChild!=null) {
lterator(node.rightChild);
}
}3.后序遍历: public void afterOrder(Node node)
{
//如果左子树不为空继续往左找,在递归调用方法的时候一直会将子树的根存入list,这就做到了先遍历根节点
if(node.leftChild != null)
{
preOrder(node.leftChild);
}
//无论走到哪一层,只要当前节点左子树为空,那么就可以在右子树上遍历,保证了根左右的遍历顺序
if(node.rightChild != null)
{
preOrder(node.rightChild);
}
System.out.println(node.val); //将根节点输出
} ???,看起来这三种深度遍历的方法都差不多嘛,区别无非是查找后序节点与获取节点值之间的顺序区别?虽然我也是这么想的,但是并不完全如此。至少在二叉查找树(任一节点的左节点始终小于右节点)的情况下,中序遍历根据遍历的方向可以获取从小到大或从大到小的元素集,而且时间复杂度仅为O(log(n))。而后序遍历也有他的优点,因为在处理节点之前已经缺点处理过了该节点的左右两子节点,所以后序遍历适用于删除所有节点这一类的操作。
2,广度优先遍历:
public ArrayDeque<Node> levelOrderTraversal() {
if (root == null) {
System.out.println("empty tree");
return null;
}
ArrayDeque<Node> queue = new ArrayDeque<>();
ArrayDeque<Node> result = new ArrayDeque<>();
queue.add(root);
while (queue.isEmpty() == false) {
Node node = queue.remove();
result.push(node);
if (node.leftChild != null) {
queue.add(node.leftChild);
}
if (node.rightChild != null) {
queue.add(node.rightChild);
}
}
return result;
} 如上所示,广度优先情况下,会先遍历该层所有的左右节点,将其放入队列中,然后进行循环,在处理掉队列中所有元素(也就是该层所有的子节点)之后,才会遍历下一层。
那么我们可以使用这个广度优先遍历的方法遍历树并图形化输出到控制台,emmm想要显示的好看意外的难,反正意思是这个意思,等我看其他几种树的时候回优化一下:@Override
public String toString() {
ArrayDeque<Node> elements=levelOrderTraversal();
if (elements==null){
return null;
}
int height=elements.getFirst().height;
String[] lines=new String[height+1];
int[] rightCounts=new int[height+1];
// StringBuilder sb=new StringBuilder();
while (!elements.isEmpty()){
Node temp=elements.pollLast();
if (lines[temp.height]==null){
lines[temp.height]=getInterval(height+temp.right)+ temp.val;
rightCounts[temp.height]=temp.right;
}
else {
lines[temp.height]=lines[temp.height]+getInterval(temp.right-rightCounts[temp.height])+ temp.val;
}
}
String result="";
for (String string:lines){
result+=string+"\r\n";
}
return result;
}
String getInterval(int number){
if (number<=0){
return "";
}else {
StringBuilder sb=new StringBuilder();
for (int i=1;i<=number;i++){
sb.append(" ");
}
return sb.toString();
}
}
相关文章推荐
- 二叉树的序列化和反序列化,二叉树深度、广度优先遍历
- 二叉树的深度优先和广度优先遍历
- 二叉树,递归、非递归遍历,求深度,输出叶子节点
- 判断任一二叉树,是否为满二叉树.(输出二叉树,节点总数,二叉树深度)
- 二叉树结构字符串转为数组控制台输出二叉树
- 二叉树——已知二叉树先序,建树,并输出中序、后序,并求树叶数和深度
- 每日一题--二叉树的深度
- 打印如下图案:要求,通过输入不同的参数(比如1、2、3、4...N)该图案可以90°*N的倍数进行顺时针旋转。不需要图形化界面,在控制台中输出即可。注意:图中的“I”为占位符,真实的图形不应该有此符号
- 每日一练(39) - 二叉树的深度
- 打印如下图案:要求,通过输入不同的参数(比如1、2、3、4...N)该图案可以90°*N的倍数进行顺时针旋转。不需要图形化界面,在控制台中输出即可。注意:图中的“I”为占位符,真实的图形不应该有此符号
- 判断任一二叉树,是否为满二叉树.(输出二叉树,节点总数,二叉树深度)
- 二叉树的深度优先和广度优先遍历
- 【每日一篇】数据结构---树与二叉树与二叉查找树
- 二叉树创建、销毁、按照分层在控制台显示、计算二叉树深度等等
- 剑指offer_二叉树---二叉树的深度
- C语言版 彩色俄罗斯方块 控制台输出
- VC++窗口应用程序中使用控制台输出
- 剑指offer-面试题39 : 二叉树的深度
- 九度笔记之 1350:二叉树的深度
- Eclipse CDT 调用printf/cout 控制台(console)无输出