【Java】 剑指offer(31)从上往下打印二叉树

本文参考自《剑指offer》一书,代码采用Java语言。

更多:《剑指Offer》Java实现合集  

题目 

  (一)从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。

  (二)从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行。

  (三)请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

思路

  (一)不分行从上往下打印二叉树:该题即为对二叉树的层序遍历,结点满足先进先出的原则,采用队列。每从队列中取出头部结点并打印,若其有子结点,把子结点放入队列尾部,直到所有结点打印完毕。

	/*
	 * 不分行从上往下打印二叉树
	 */
	// 题目:从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。
	public void printTree1(TreeNode root) {
		if (root == null)
			return;
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		TreeNode node = null;
		while (queue.size()!=0) {
			node = queue.poll();
			System.out.print(node.val + " ");
			if (node.left != null)
				queue.offer(node.left);
			if (node.right != null)
				queue.offer(node.right);
		}
		System.out.println();
	}

  (二)分行从上到下打印二叉树:同样使用队列,但比第一题增加两个变量:当前层结点数目pCount,下一层结点数目nextCount。根据当前层结点数目来打印当前层结点,同时计算下一层结点数目,之后令pCount等于nextCount,重复循环,直到打印完毕。

	/*
	 * 分行从上到下打印二叉树
	 */
	// 题目:从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层
	// 打印到一行。
	public void printTree2(TreeNode root) {
		if (root == null)
			return;
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		TreeNode node = null;
		int pCount = 0;		 //当前层结点数目
		int nextCount = 1;   //下一层结点数目
		while (!queue.isEmpty()) {
			pCount = nextCount;
			nextCount = 0;
			//打印当前层数字,并计算下一层结点数目
			for (int i = 1; i <= pCount; i++) {
				node = queue.poll();
				System.out.print(node.val + " ");
				if (node.left != null) {
					queue.offer(node.left);
					nextCount++;
				}
				if (node.right != null) {
					queue.offer(node.right);
					nextCount++;
				}
			}
			System.out.println();
		}
	}

  (三)之字形打印二叉树:

    (1)自己开始想的方法:在(二)的基础上,多定义一个表示当前层数的变量level。每层结点不直接打印,放入一个数组中,根据此时的层数level的奇偶来决定正向还是反向打印数组。

	/*
	 * 之字形打印二叉树
	 */
	// 题目:请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺
	// 序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,
	// 其他行以此类推。
	/**
	 * 自己开始想的方法,采用数组存储每层的数字,根据当前层数确定正反向打印数组
	 */
	public void printTree3_1(TreeNode root) {
		if (root == null)
			return;
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		TreeNode node = null;
		int pCount = 0;		 //当前层结点数目
		int nextCount = 1;   //下一层结点数目
		int level=1;    //层数
		int[] pNums=null;    //用于存储当前层的数字
		while (!queue.isEmpty()) {
			pCount = nextCount;
			nextCount = 0;
			pNums=new int[pCount];
			//存储当前层数字,并计算下一层结点数目
			for (int i = 0; i < pCount; i++) {
				node = queue.poll();
				pNums[i]=node.val;
				if (node.left != null) {
					queue.offer(node.left);
					nextCount++;
				}
				if (node.right != null) {
					queue.offer(node.right);
					nextCount++;
				}
			}
			//根据当前层数确定正向或者反向打印数组
			if((level&1)!=0 ) {
				for(int i=0;i<pCount;i++) {
					System.out.print(pNums[i]+" ");
				}
			}else {
				for(int i=pCount-1;i>=0;i--) {
					System.out.print(pNums[i]+" ");
				}
			}
			level++;
			System.out.println();
		}
	}

    (2)书中提供的方法:采用两个栈,对于不同层的结点,一个栈用于正向存储,一个栈用于逆向存储,打印出来就正好是相反方向。

	/**
	 * 采用两个栈进行操作的方法
	 */
	public void printTree3_2(TreeNode root) {
		if (root == null)
			return;
		Stack<TreeNode> stack1 = new Stack<TreeNode>();
		Stack<TreeNode> stack2 = new Stack<TreeNode>();
		TreeNode node = null;
		stack1.push(root);
		while(!stack1.empty() || !stack2.empty()) {
			while(!stack1.empty()) {
				node=stack1.pop();
				System.out.print(node.val + " ");
				if (node.left != null)
					stack2.push(node.left);
				if (node.right != null)
					stack2.push(node.right);
			}
			System.out.println();
			while(!stack2.empty()) {
				node=stack2.pop();
				System.out.print(node.val + " ");
				if (node.right != null)
					stack1.push(node.right);
				if (node.left != null)
					stack1.push(node.left);
			}
			System.out.println();
		}
	}

  

测试算例 

  1.功能测试(完全二叉树;左斜树;右斜树)

  2.特殊测试(null;一个结点)

完整Java代码

含测试代码:

import java.util.LinkedList;
import java.util.Stack;
/**
 *
 * @Description 面试题32:从上往下打印二叉树
 *
 * @author yongh
 */

public class PrintTreeFromTopToBottom {
	public class TreeNode {
		int val = 0;
		TreeNode left = null;
		TreeNode right = null;

		public TreeNode(int val) {
			this.val = val;
		}
	}

	/*
	 * 	不分行从上往下打印二叉树
	 */
	// 题目:从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。
	public void printTree1(TreeNode root) {
		if (root == null)
			return;
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		TreeNode node = null;
		while (queue.size()!=0) {
			node = queue.poll();
			System.out.print(node.val + " ");
			if (node.left != null)
				queue.offer(node.left);
			if (node.right != null)
				queue.offer(node.right);
		}
		System.out.println();
	}	

	/*
	 * 分行从上到下打印二叉树
	 */
	// 题目:从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层
	// 打印到一行。
	public void printTree2(TreeNode root) {
		if (root == null)
			return;
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		TreeNode node = null;
		int pCount = 0;		 //当前层结点数目
		int nextCount = 1;   //下一层结点数目
		while (!queue.isEmpty()) {
			pCount = nextCount;
			nextCount = 0;
			//打印当前层数字,并计算下一层结点数目
			for (int i = 1; i <= pCount; i++) {
				node = queue.poll();
				System.out.print(node.val + " ");
				if (node.left != null) {
					queue.offer(node.left);
					nextCount++;
				}
				if (node.right != null) {
					queue.offer(node.right);
					nextCount++;
				}
			}
			System.out.println();
		}
	}

	/*
	 * 之字形打印二叉树
	 */
	// 题目:请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺
	// 序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,
	// 其他行以此类推。
	/**
	 * 自己开始想的方法,采用数组存储每层的数字,根据当前层数确定正反向打印数组
	 */
	public void printTree3_1(TreeNode root) {
		if (root == null)
			return;
		LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
		queue.offer(root);
		TreeNode node = null;
		int pCount = 0;		 //当前层结点数目
		int nextCount = 1;   //下一层结点数目
		int level=1;    //层数
		int[] pNums=null;    //用于存储当前层的数字
		while (!queue.isEmpty()) {
			pCount = nextCount;
			nextCount = 0;
			pNums=new int[pCount];
			//存储当前层数字,并计算下一层结点数目
			for (int i = 0; i < pCount; i++) {
				node = queue.poll();
				pNums[i]=node.val;
				if (node.left != null) {
					queue.offer(node.left);
					nextCount++;
				}
				if (node.right != null) {
					queue.offer(node.right);
					nextCount++;
				}
			}
			//根据当前层数确定正向或者反向打印数组
			if((level&1)!=0 ) {
				for(int i=0;i<pCount;i++) {
					System.out.print(pNums[i]+" ");
				}
			}else {
				for(int i=pCount-1;i>=0;i--) {
					System.out.print(pNums[i]+" ");
				}
			}
			level++;
			System.out.println();
		}
	}

	/**
	 * 采用两个栈进行操作的方法
	 */
	public void printTree3_2(TreeNode root) {
		if (root == null)
			return;
		Stack<TreeNode> stack1 = new Stack<TreeNode>();
		Stack<TreeNode> stack2 = new Stack<TreeNode>();
		TreeNode node = null;
		stack1.push(root);
		while(!stack1.empty() || !stack2.empty()) {
			while(!stack1.empty()) {
				node=stack1.pop();
				System.out.print(node.val + " ");
				if (node.left != null)
					stack2.push(node.left);
				if (node.right != null)
					stack2.push(node.right);
			}
			System.out.println();
			while(!stack2.empty()) {
				node=stack2.pop();
				System.out.print(node.val + " ");
				if (node.right != null)
					stack1.push(node.right);
				if (node.left != null)
					stack1.push(node.left);
			}
			System.out.println();
		}
	}

	//============测试代码==============
	private void test(int testNum,TreeNode root) {
		System.out.println("=========test"+testNum+"===========");
		System.out.println("method1:");
		printTree1(root);
		System.out.println("method2:");
		printTree2(root);
		System.out.println("method3_1:");
		printTree3_1(root);
		System.out.println("method3_2:");
		printTree3_2(root);
	}

	//null
	private void test1() {
		TreeNode node=null;
		test(1, node);
	}

	//单个结点
	private void test2() {
		TreeNode node=new TreeNode(1);
		test(2, node);
	}

	//左斜
	private void test3() {
		TreeNode node1=new TreeNode(1);
		TreeNode node2=new TreeNode(2);
		TreeNode node3=new TreeNode(3);
		node1.left=node2;
		node2.left=node3;
		test(3, node1);
	}

	//右斜
	private void test4() {
		TreeNode node1=new TreeNode(1);
		TreeNode node2=new TreeNode(2);
		TreeNode node3=new TreeNode(3);
		node1.right=node2;
		node2.right=node3;
		test(4, node1);
	}

	//完全二叉树
	private void test5() {
		TreeNode[] nodes = new TreeNode[15];
		for(int i=0;i<15;i++) {
			nodes[i]= new TreeNode(i+1);
		}
		for(int i=0;i<7;i++) {
			nodes[i].left=nodes[2*i+1];
			nodes[i].right=nodes[2*i+2];
		}
		test(5, nodes[0]);
	}

	public static void main(String[] args) {
		PrintTreeFromTopToBottom demo= new PrintTreeFromTopToBottom();
		demo.test1();
		demo.test2();
		demo.test3();
		demo.test4();
		demo.test5();
	}
}

  

=========test1===========
method1:
method2:
method3_1:
method3_2:
=========test2===========
method1:
1
method2:
1
method3_1:
1
method3_2:
1 

=========test3===========
method1:
1 2 3
method2:
1
2
3
method3_1:
1
2
3
method3_2:
1
2
3 

=========test4===========
method1:
1 2 3
method2:
1
2
3
method3_1:
1
2
3
method3_2:
1
2
3 

=========test5===========
method1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
method2:
1
2 3
4 5 6 7
8 9 10 11 12 13 14 15
method3_1:
1
3 2
4 5 6 7
15 14 13 12 11 10 9 8
method3_2:
1
3 2
4 5 6 7
15 14 13 12 11 10 9 8 

PrintTreeFromTopToBottom

收获

  1.层序遍历时,一般都要用到队列,可以用LinkedList类(方法:poll() 和 offer(Obj) )。

  2.在分行打印时,定义的两个int有明显实际意义(当前层结点数目,下一层结点数目)。自己编程时,一开始只知道要设置两个变量,但没有去想这两个变量的实际意义。当明白变量意义时,自己的思路会更清晰,而且代码可读性也更好。

  

更多:《剑指Offer》Java实现合集  

  

原文地址:https://www.cnblogs.com/yongh/p/9812691.html

时间: 2024-10-11 11:33:13

【Java】 剑指offer(31)从上往下打印二叉树的相关文章

剑指OFFER之从上往下打印二叉树(九度OJ1523)

题目描述: 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行一个整数n(1<=n<=1000, :n代表将要输入的二叉树元素的个数(节点从1开始编号).接下来一行有n个数字,代表第i个二叉树节点的元素的值.接下来有n行,每行有一个字母Ci.Ci='d'表示第i个节点有两子孩子,紧接着是左孩子编号和右孩子编号.Ci='l'表示第i个节点有一个左孩子,紧接着是左孩子的编号.Ci='r'表示第i个节点有一个右孩

剑指offer:从上往下打印二叉树

题目描述: 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 解题思路: 实际就是二叉树的中序遍历问题.之前在leetcode刷过类似题目. 利用队列完成即可. 代码: /* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: v

剑指offer:从上到下打印二叉树

题目描述从上往下打印出二叉树的每个节点,同层节点从左至右打印. class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None class Solution: """ 由于需要逐层打印,那么我们在遍历整棵树的时候就需要维护一个队列. 队列中存储的是下一层从左到右的节点. 具体来说在打印第k层的节点的时候,将该节点的左右子节点按顺序入队即可.递归出口就是队列为空 &qu

剑指offer——32从上到下打印二叉树

题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 题解: 就是简单的层序遍历 1 class Solution { 2 public: 3 vector<int> PrintFromTopToBottom(TreeNode* root) { 4 vector<int>res; 5 BFS(root, res); 6 return res; 7 } 8 void BFS(TreeNode *root, vector<int>&res) 9 { 10

[剑指Offer] 22.从上往下打印二叉树

[思路]广度优先遍历,队列实现 1 class Solution 2 { 3 public: 4 vector<int> PrintFromTopToBottom(TreeNode* root) 5 { 6 queue<TreeNode*> Queue; 7 vector<int> res; 8 if(root == NULL) 9 return res; 10 Queue.push(root); 11 while(!Queue.empty()) 12 { 13 res

剑指offer22:从上往下打印出二叉树的每个节点,同层节点从左至右打印。

1 题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 2 思路和方法 使用一个队列存放节点.先将根节点加入到队列中,然后循环遍历队列中的元素,遍历过程中,访问该节点的左右子节点,再将左右子节点加入到队列中. 例子:1 2 3 4 5 6 7 8 ? 对于第一层,只有根节点 1,第二层有节点2和3.先将根节点1加入到队列中,接下来要打印节点为1的两个子节点,应该在遍历到该根节点时把值为2和3的两个子节点保存到队列.按照从左向右打印的要求,取出2,保存其子节点4:随后取出3,保存其子

剑指offer:按之字形顺序打印二叉树

题目描述请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推. class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None class Solution: """ 由于需要打印Z字型,那么我们在遍历整棵树的时候就需要维护一个栈. 栈中存储的是下一层的节点的逆序,则在访问的时候

剑指Offer面试题23(Java版):从上往下打印二叉树

题目:从上往下打印二叉树的每个结点,同一层的结点按照从左到右的顺序打印.例如输入下图的二叉树,则一次打印出8,6,10,5,7,9,11. 这道题实质上考察的就是树的遍历算法,只是这种遍历不是我们熟悉的前序.中序或者后序遍历.由于我们不太熟悉这种按层遍历的方法,可能已下载也想不清楚遍历的过程. 因为按层打印的顺序决定应该先打印的根节点,所以我们从树的根节点开始分析.为了接下来能够打印8的结点的两个子节点,我们应该在遍历到该结点时把值为6和10的两个结点保存到一个容器中,现在容器内就有两个结点了.

剑指Offer对答如流系列 - 从上往下打印二叉树

面试题32:从上往下打印二叉树 题目描述 树的结构定义如下: public class Node{ int e; Node left; Node right; Node(int x) { e = x; } } (一)不分行从上到下打印二叉树 从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印. 比如下面二叉树,输出顺序为 8 6 10 5 7 9 11 (二)分行从上到下打印二叉树 从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行. 比如下面二叉树,输出