今晚Jack来说一说Dart语言实现树的遍历。先用源码演示一下树的 前序遍历,中序遍历 和 后序遍历;再谈一谈树的层序遍历的两种方法(广度优先比遍历 和 按层打印);最后演示一下已知前序遍历和中序遍历,如何确定树的后序遍历。
今天的演示全都以下图这棵树为例:

1.前序遍历:先打印当前节点值,再打印左儿子的值,最后打印右儿子的值;
中序遍历:先打印当前节点左儿子的值,再打印当前节点值,最后打印右儿子的值;
后序遍历:先打印当前节点左儿子的值,再打印右儿子的值,最后打印当前节点的值。
下面上代码,代码评论是遍历的结果:
class TreeNode{
int val;
TreeNode leftChild;
TreeNode rightChild;
TreeNode(this.val){
leftChild=null;
rightChild=null;
}
}
List<int> preList=List<int>();
List<int> inList=List<int>();
List<int> postList=List<int>();
void preTraversal(TreeNode rt){
if(rt==null)return;
preList.add(rt.val);
preTraversal(rt.leftChild);
preTraversal(rt.rightChild);
}
void inTraversal(TreeNode rt){
if(rt==null)return;
inTraversal(rt.leftChild);
inList.add(rt.val);
inTraversal(rt.rightChild);
}
void postTraversal(TreeNode rt){
if(rt==null)return;
postTraversal(rt.leftChild);
postTraversal(rt.rightChild);
postList.add(rt.val);
}
void main(){
TreeNode root=TreeNode(5);
root
..leftChild=TreeNode(3)
..rightChild=TreeNode(10)
..leftChild.leftChild=TreeNode(43)
..leftChild.rightChild=TreeNode(21)
..leftChild.leftChild.leftChild=TreeNode(12)
..rightChild.leftChild=TreeNode(76)
..rightChild.rightChild=TreeNode(9)
..rightChild.leftChild.leftChild=TreeNode(45)
..rightChild.leftChild.rightChild=TreeNode(8);
preTraversal(root);
print('The preorder list is $preList');
inTraversal(root);
print('The inorder list is $inList');
postTraversal(root);
print('The postorder list is $postList');
}
/*
Result of three traversals:
The preorder list is [5, 3, 43, 12, 21, 10, 76, 45, 8, 9]
The inorder list is [12, 43, 3, 21, 5, 45, 76, 8, 10, 9]
The postorder list is [12, 43, 21, 3, 45, 8, 76, 9, 10, 5]
*/
2.层序遍历:就是根据节点深度从小到大,从左到右打印一棵树的所有节点值。
先给一下 广度优先遍历(breadth first traversal)的代码,用queue来实现:
import 'dart:collection';
class TreeNode{
int val;
TreeNode leftChild;
TreeNode rightChild;
TreeNode(this.val){
leftChild=null;
rightChild=null;
}
}
List<int> levelOrder=List<int>();
void bfs(TreeNode rt){
if(rt==null)return;
Queue<TreeNode> qt=Queue<TreeNode>();
qt.add(rt);
while(qt.isNotEmpty){
TreeNode temp=qt.removeFirst();
levelOrder.add(temp.val);
if(temp.leftChild!=null)qt.add(temp.leftChild);
if(temp.rightChild!=null)qt.add(temp.rightChild);
}
print('The result of level order traversal is $levelOrder');
}
void main(){
TreeNode root=TreeNode(5);
root
..leftChild=TreeNode(3)
..rightChild=TreeNode(10)
..leftChild.leftChild=TreeNode(43)
..leftChild.rightChild=TreeNode(21)
..leftChild.leftChild.leftChild=TreeNode(12)
..rightChild.leftChild=TreeNode(76)
..rightChild.rightChild=TreeNode(9)
..rightChild.leftChild.leftChild=TreeNode(45)
..rightChild.leftChild.rightChild=TreeNode(8);
bfs(root);
}
/*
Result of breadth first traversal:
The result of level order traversal is [5, 3, 10, 43, 21, 76, 9, 12, 45, 8]
*/
再给一下按层打印的源码,这里主要是用到了递归思想,无论是取树高度还是打印指定层的所有节点:
import 'dart:math';
class TreeNode{
int val;
TreeNode leftChild;
TreeNode rightChild;
TreeNode(this.val){
leftChild=null;
rightChild=null;
}
}
List<int> levelOrder=List<int>();
int getHeight(TreeNode root){
if(root==null)return 0;
return max(getHeight(root.leftChild), getHeight(root.rightChild))+1;
}
void printGivenLevel(TreeNode root, int level){
if(root==null)return;
if(level>1){
printGivenLevel(root.leftChild, level-1);
printGivenLevel(root.rightChild, level-1);
}else levelOrder.add(root.val);
}
void printAllLevels(TreeNode root){
int treeHeight=getHeight(root);
for(int i=1;i<=treeHeight;i++)
printGivenLevel(root, i);
print('The result of level order traversal is $levelOrder');
}
void main(){
TreeNode root=TreeNode(5);
root
..leftChild=TreeNode(3)
..rightChild=TreeNode(10)
..leftChild.leftChild=TreeNode(43)
..leftChild.rightChild=TreeNode(21)
..leftChild.leftChild.leftChild=TreeNode(12)
..rightChild.leftChild=TreeNode(76)
..rightChild.rightChild=TreeNode(9)
..rightChild.leftChild.leftChild=TreeNode(45)
..rightChild.leftChild.rightChild=TreeNode(8);
printAllLevels(root);
}
/*
Result of printAllLevels method:
The result of level order traversal is [5, 3, 10, 43, 21, 76, 9, 12, 45, 8]
*/
3.最后解一道题,已知前序遍历和中序遍历,求一棵树的后序遍历。
其实也可以是 已知中序遍历和后序遍历,求一棵树的中序遍历。
但是 已知前序遍历和后序遍历,却不能唯一确定一棵树,那么也就不能唯一确定它的中序遍历。原因见下图,大家体会一下:

最后贴一下 前序遍历和中序遍历确定后序遍历的Dart源码,代码评论是结果:
class TreeNode{
int val;
TreeNode leftChild;
TreeNode rightChild;
TreeNode(this.val){
leftChild=null;
rightChild=null;
}
}
List<int> preorder=[5, 3, 43, 12, 21, 10, 76, 45, 8, 9];
List<int> inorder=[12, 43, 3, 21, 5, 45, 76, 8, 10, 9];
List<int> postList=List<int>();
TreeNode getRoot(int prel,int prer,int inl,int inr){
int prell,prelr,prerl,prerr,inll,inlr,inrl,inrr;
TreeNode root=TreeNode(preorder[prel]);
int rtPos=inorder.indexOf(preorder[prel]);
if(rtPos!=inl){
prell=prel+1;
inll=inl;
inlr=rtPos-1;
prelr=prell+inlr-inll;
root.leftChild=getRoot(prell, prelr, inll, inlr);
}
if(rtPos!=inr){
prerr=prer;
inrl=rtPos+1;
inrr=inr;
prerl=prer-(inrr-inrl);
root.rightChild=getRoot(prerl,prerr,inrl,inrr);
}
return root;
}
void postTraversal(TreeNode rt){
if(rt==null)return;
postTraversal(rt.leftChild);
postTraversal(rt.rightChild);
postList.add(rt.val);
}
void main(){
TreeNode root=getRoot(0, 9, 0, 9);
postTraversal(root);
print('The result of postorder traversal is $postList');
}
/*
The result of postorder traversal is [12, 43, 21, 3, 45, 8, 76, 9, 10, 5]
*/