问题一:从上到下打印二叉树
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
看到这个问题,第一脑海里就浮现出了数据结构期间学到的树的广度遍历,那么按照当时的思路,就是建立一个队列(因为队列有先进先出的性质),从第一个根节点开始,把根节点储存进队列中,然后判断队列是否为空,不为空则打印该节点,然后判断该节点的左右子树是否为空,不为空,把它的左右子树添加进队列中,以此类推,直到最后把所有不为空的节点全部输出,结束循环。
思路出来之后,那么我们可以假设树的结构如下:
题外话:作为一名灵魂画手,时不时的就得展露自己的高超手艺来吸引浏览量(我不会坦言是我网速差到打不开制图软件才用画板画的[手动捂脸])。
那么对于从上到下打印可有以下过程:
知道解决方法之后,那么就通过代码实现并测试吧!
有两个测试:
1、二叉树不为空,输出正确的顺序
2、二叉树为空,返回一个空集合
以下为参考代码:
using System;
using System.Collections.Generic;
using System.Linq;
namespace 从上到下打印二叉树
{
public class TreeNode
{
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int x)
{
val = x;
}
}
class Program
{
static void Main(string[] args)
{
TreeNode tree = CreateTree(null);
Solution s = new Solution();
List<int> list = s.PrintFromTopToBottom(tree);
s.PrintList(list);
list = s.PrintFromTopToBottom(null);
s.PrintList(list);
}
private static TreeNode CreateTree(TreeNode root)
{
if (root == null)
{
TreeNode tree = new TreeNode(1)
{
left = new TreeNode(2),
right = new TreeNode(3)
};
tree.left.left = new TreeNode(4);
tree.left.right = new TreeNode(5);
tree.right.left = new TreeNode(6);
tree.right.right = new TreeNode(7);
return tree;
}
else
return root;
}
}
class Solution
{
public List<int> PrintFromTopToBottom(TreeNode root)
{
List<int> list = new List<int>();
Queue<TreeNode> queue = new Queue<TreeNode>();
if (root == null)
return list;
queue.Enqueue(root);
while (queue.Count() != 0)
{
TreeNode pNode = queue.Dequeue();
list.Add(pNode.val);
if (pNode.left != null)
queue.Enqueue(pNode.left);
if (pNode.right != null)
queue.Enqueue(pNode.right);
}
return list;
}
public void PrintList(List<int> list)
{
if(list==null||list.Count<=0)
{
Console.WriteLine("null");
return;
}
foreach (int item in list)
Console.Write(item + "\t");
Console.WriteLine();
}
}
}
题目二:怎样分行从上到下打印二叉树
从上到下分层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印一行。例如打印如下二叉树
得出的结果应该是:
8
7 6
3 2 1 4
此题和上述题目一类似,也可以用一个队列来保存,但是为了保证把每一行单独的打印到一行里,需要设置两个变量,一个变量表示当前层中是否还有节点数没有被打印,另一个变量是下一层的节点数目。
以下为打印方法的参考代码:
public void PrintFromTopToBottomByLayer(TreeNode root)
{
Queue<TreeNode> queue = new Queue<TreeNode>();
if (root == null)
return;
//nextLayer 表示下一层需要打印的元素个数,toBePrint表示当前层需要打印的元素个数
int nextLayer = 0, toBePrint = 1;
queue.Enqueue(root);
while (queue.Count > 0)
{
TreeNode pNode = queue.Dequeue();
if(pNode.left!=null)
{
nextLayer++;
queue.Enqueue(pNode.left);
}
if (pNode.right != null)
{
nextLayer++;
queue.Enqueue(pNode.right);
}
Console.Write(pNode.val + "\t");
toBePrint--;
if (toBePrint == 0)
{
toBePrint = nextLayer;
nextLayer = 0;
Console.WriteLine();
}
}
}
问题三:之字形打印二叉树
问题描述
请实现一个函数按照之字形顺序打印二叉树,及第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,以此类推。
例如,按照之字形顺序打印下图二叉树
结果应该为:
1
3 2
4 5 6 7
15 14 13 12 11 10 9 8
我们以上面的二叉树为例来分析过程:
当根节点1打印之后,它的左子节点和右子节点先后保存到了一个数据容器中。打印第二层时,先打印3,再打印2。可以发现这个节点的打印是先进后出的,因此数据容器可以用栈来实现。
接着打印第二层你的两个节点。根据之字形顺序,先打印3节点,再打印2节点,并把它们的子节点保存到一个数据容器里。打印第三层时,会先打印节点2的两个子节点,再打印节点3的两个子节点。这意味着我们需要再定义一个栈来保存节点2和节点3的子节点。
分析到这里,可以得出的规律有:按之字形顺序打印二叉树需要两个栈,打印某一层时,把下一层的节点保存到相应的栈里。如果当前是奇数层(第一层,第三层),那么先保存左子节点再保存右子节点到第一个栈里;如果当前是偶数层(第二层),则先保存右子节点再保存左子节点到第二个栈里。
为什么要用两个栈?我们可以看看第二层到第三层的打印,如果打印节点时,先后把节点2和节点3压入栈里。接下来打印节点3,打印节点3时需要把它的左右子节点压入栈里,此时由于它的右子节点为7,就会导致下一个打印的节点为7,而不是节点2。所以为了避免这个问题,我们需要定义两个栈。
按之字形顺序打印二叉树,以下为打印过程:
以下为上述功能的方法实现代码:
public void PrintFromTopToBottomByLayerOfZ(TreeNode root)
{
if (root == null)
{
Console.WriteLine("null");
return;
}
//定义两个栈,一个储存当前层的元素,另一个储存下一层的元素
Stack<TreeNode>[] level = { new Stack<TreeNode>(), new Stack<TreeNode>() };
//表示当前层的栈下标和下一层的栈下标
int current = 0;
int next = 1;
//首先把根节点压入当前层的栈中
level[current].Push(root);
//如果当前层的栈和下一层的栈有一个栈不为空,则打印
while (level[current].Count > 0 || level[next].Count > 0)
{
//取出栈顶元素
TreeNode pNode = level[current].Pop();
//打印
Console.Write(pNode.val + "\t");
//如果当前层是奇数层,则从左到右压入子树数据
if (current == 0)
{
if (pNode.left != null)
level[next].Push(pNode.left);
if (pNode.right != null)
level[next].Push(pNode.right);
}
//如果当前层是偶数层,则从右到左压入子树数据
else
{
if (pNode.right != null)
level[next].Push(pNode.right);
if (pNode.left != null)
level[next].Push(pNode.left);
}
//如果当前层的所有数据全部弹出,则换一行进行下一层的打印
if (level[current].Count == 0)
{
Console.WriteLine();
current = 1 - current;
next = 1 - next;
}
}
}