从上往下打印二叉树(Java)

题目:

从上往下打印二叉树的每个结点,同一层的结点按照从左到右的顺序打印。例如下图中的二叉树,则依次打印出8、 6、 10、 5、 7、 9、 11。


二叉树结点的定义如下:

struct BinaryTreeNode{
	int m_nValue;
	BinaryTreeNode* m_pLeft;
	BinaryTreeNode* m_pRight;
}

思路:

这道题实质是在考查树的遍历算法。只是这种遍历不是我们熟悉的前序(根左右)、中序(左根右)、后序(左右根)遍历。故就需要从树及打印列表分析。分析上图二叉树的层次打印顺序:


通过上图的具体例子的分析,我们可以找到从上到下打印二叉树的规律:每一次打印一个结点的时候,如果该结点有子结点,则把该结点的子结点放到队列的末尾。接下来到队列的头部取出最早进入队列的结点,重复前面的打印操作,直至队列中所有的结点都被打印出来为止。

代码实现:

public class BinaryTreeNode {

	public int data; 
	
	public BinaryTreeNode left;
	
	public BinaryTreeNode right;

	public BinaryTreeNode(int data) {
		this.data = data;
	}

	@Override
	public String toString() {
		return "BinaryTreeNode [data=" + data + ", left=" + left + ", right=" + right
				+ "]";
	}
}
public ArrayList<Integer> printFromTopToBottom(BinaryTreeNode pTreeRoot){ //非递归版本
	ArrayList<Integer> list = new ArrayList<Integer>();
	if(pTreeRoot == null){
		return null;
	}
	Queue<BinaryTreeNode> queue = new LinkedList<BinaryTreeNode>(); 
	queue.offer(pTreeRoot);
	while(!queue.isEmpty()){
		BinaryTreeNode treeNode = queue.poll();
		if(treeNode.left!=null){
			queue.offer(treeNode.left);
		}
		if(treeNode.right!=null){
			queue.offer(treeNode.right);
		}
		list.add(treeNode.data);
	}
	return list;
}
//层序遍历二叉树递归实现
private int depth(BinaryTreeNode pTreeRoot){
	if(pTreeRoot==null){
		return 0;
	}
	int l = depth(pTreeRoot.left);
	int r = depth(pTreeRoot.right);
	if(l > r){
		return l + 1;
	}else{
		return r + 1;
	}
}
	
private void levelOrder(BinaryTreeNode pTreeNode, int level) {
	if(pTreeNode == null || level < 1){
		return ;
	}
	if(level == 1){
		System.out.print(pTreeNode.data+ " ");
		return ;
	}
	//左子树
	levelOrder(pTreeNode.left, level-1);
	//右子树
	levelOrder(pTreeNode.right, level-1);
}
	
public void printFromTopToBottom(BinaryTreeNode pTreeRoot){
	if(pTreeRoot==null){
		return ;
	}
	int depth = depth(pTreeRoot);
	for (int i = 1; i <= depth; ++i) {
		levelOrder(pTreeRoot, i);
	}
}

小结:

本题考查思维能力。首先需要明白按层从上到下遍历二叉树这个概念。并会用具体例子来分析。以及充分理解队列是先进先出,栈是先进后出。

扩展:

如何广度优先遍历一个有向图?这同样也可以基于队列实现。树是图的一种特殊退化形式,从上到下按层遍历二叉树,从本质上来说就是广度优先遍历二叉树。

举一反三:

不管是广度优先遍历一个有向图还是一颗树,都要用到队列。第一步我们把起始结点(对树而言是根结点)放入到队列中。接下来每一次从队列的头部取出一个结点,遍历这个结点之后把从它能达到的结点(对于树而言是子结点)都依次放入队列。我们重复这个遍历过程,直到队列中的结点全部被遍历为止。

小思:

我们知道这是一个对二叉树的广度优先遍历的考察,那我们能否实现对二叉树的深度优先遍历呢?

概念:

树的深度优先遍历:对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次。如果你还不能理解的话,其实我们常用的二叉树先序遍历(根左右)、中序遍历(左根右)、后序遍历(左右根)就是深度遍历。因二叉树比较特殊,故它的深度遍历就前面三种。

二叉树的深度遍历代码实现递归版:

//前序遍历二叉树
ArrayList<Integer> list = new ArrayList<Integer>();
public ArrayList<Integer> preOrderBinaryTree(BinaryTreeNode pTreeRoot){
	if(pTreeRoot!=null){
		list.add(pTreeRoot.data); //先根结点
		preOrderBinaryTree(pTreeRoot.left); //再左边
		preOrderBinaryTree(pTreeRoot.right); //再右边
	}else{
		return null;
	}
	return list;
}
//中序遍历二叉树
public ArrayList<Integer> inOrderBinaryTree(BinaryTreeNode pTreeRoot){
	if(pTreeRoot!=null){
		inOrderBinaryTree(pTreeRoot.left); //先左边
		list.add(pTreeRoot.data); //再中间
		inOrderBinaryTree(pTreeRoot.right); //再右边
	}else{
		return null;
	}
	return list;
}
//后序遍历二叉树
public ArrayList<Integer> postOrderBinaryTree(BinaryTreeNode pTreeNode){
	if(pTreeNode!=null){
		postOrderBinaryTree(pTreeNode.left); //先左边
		postOrderBinaryTree(pTreeNode.right); //再右边
		list.add(pTreeNode.data); //再中间
	}else{
		return null;
	}
	return list;
}
二叉树的深度优先遍历非递归版本:
public void preOrderBinaryTree(BinaryTreeNode pTreeNode) {    //前序
	Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
	while(pTreeNode!=null || !stack.isEmpty()){
		while(pTreeNode!=null){
			System.out.print(pTreeNode.data + " ");
			stack.push(pTreeNode);
			pTreeNode = pTreeNode.left;
		}
		if(!stack.isEmpty()){
			pTreeNode = stack.pop();
			pTreeNode = pTreeNode.right;
		}
	}
}

public void inOrderBinaryTree(BinaryTreeNode pTreeNode){    //中序
	Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
	while(pTreeNode!=null || !stack.isEmpty()){
		while(pTreeNode!=null){
			stack.push(pTreeNode);
			pTreeNode = pTreeNode.left;
		}
		if(!stack.isEmpty()){
			pTreeNode = stack.pop();
			System.out.print(pTreeNode.data + " ");
			pTreeNode = pTreeNode.right;
		}
	}
}


已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页