树结构——层序遍历
层序遍历,是将每个结点按照深度归类进行遍历输出。
层序遍历优点:
- 能解决最短/最少结点问题,探索深度小。
- 每个结点只访问一次。
缺点:
- 内存消耗较大
思路
层序遍历的顺序是,分别遍历每个深度的结点。
示例:

结果:[[1],[3,2,4],[5,6]]
代码
前提:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class Node { public int val; public IList<Node> children;
public Node() {}
public Node(int _val) { val = _val; }
public Node(int _val, IList<Node> _children) { val = _val; children = _children; } }
public IList<IList<int>> LevelOrder(Node root) { IList<IList<int>> list = new List<IList<int>>(); if(root == null){ return list; }
InOrder(root,list); return list; }
|
迭代法
迭代方案来处理一般比递归要简单一点。
使用队列前进先出的特点,可以保证是层序的遍历顺序。不过难点在于输出要每个深度一个分组的结果,那么如何得知当前结点是什么深度就很重要。
如果提供的树结构没有depth
的字段,那么只能通过计数方式来获取。可以想象队列中的顺序就是层序顺序,所以只要知道第几个结点出队列时表示该深度遍历结束即可。
那么就需要两个参数来做记录。nodeCount
和 childCount
。
nodeCount
记录的是本深度的结点数量,每次出队列时该参数-1。当nodeCount == 0
时,表示该层的全部都出队列了,那么接下来该是下一深度的计数。而下一深度的结点数量刚好可以通过childCount
来获得。
childeCount
记录每次子节点的遍历数量,当childCount
被赋值给nodeCount
时,表示当前层结点遍历完毕,childCount
已经记录了下一层的所有结点数量。接着进行下一层之前赋值为0,就继续计数下下一层的节点数量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| private void InOrder(Node node,IList<IList<int>> list){
if(node == null){ return; }
Queue<Node> queue = new Queue<Node>(); queue.Enqueue(node); int nodeCount = 1; int childCount = 0; int depth = 1;
while(queue.Count > 0){ Node pNode = queue.Dequeue(); nodeCount --;
IList<int> cellList = null; if(depth > list.Count){ cellList = new List<int>(); list.Add(cellList); }else{ cellList = list[depth-1]; } cellList.Add(pNode.val);
if(pNode.children != null && pNode.children.Count > 0){ for(int i = 0; i < pNode.children.Count;i++){ queue.Enqueue(pNode.children[i]); }
childCount += pNode.children.Count; }
if(nodeCount == 0){ nodeCount = childCount; childCount = 0; depth++; }
} }
|
其中的depth
我用参数来记录,不过仅仅为了解决问题,其实可以直接使用list.Count
来代替depth
,其主要作用就是取出当前深度的结果数组,将结果加入到当前结果数组中。
递归法(不建议)
递归方案能看出来和深度搜索中前序遍历很像。
所以这个只是结果为层序,但遍历顺序并不是。
关键仅仅是传递了depth
,将结果提供给指定depth
的数列中。
!!层序遍历不要使用此方法,此方法仅仅是让结果正确而已。其实质依旧是前序遍历!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
private void InOrder(Node node,IList<IList<int>> list,int depth){ IList<int> res = null; if(depth > list.Count){ res = new List<int>(); list.Add(res); }else{ res = list[depth-1]; }
res.Add(node.val);
if(node.children != null && node.children.Count > 0){ for(int i = 0; i < node.children.Count;i++){ InOrder(node.children[i],list,depth + 1); } } }
|