递归改写成循环方式的实现例子-树的遍历
结果
构造的树为 Tree001 / \ Tree002 Tree003 / Tree004 递归方式遍历一棵树 第1次要遍历的tree为:Tree{nodeId='001', nodeName='根结点'} 001:根结点 第2次要遍历的tree为:Tree{nodeId='002', nodeName='结点2'} 002:结点2 第3次要遍历的tree为:Tree{nodeId='004', nodeName='结点4'} 004:结点4 第4次要遍历的tree为:Tree{nodeId='003', nodeName='结点3'} 003:结点3 循环方式遍历一棵树 第1次要遍历的tree为:[Tree{nodeId='001', nodeName='根结点'}] 001:根结点 第2次要遍历的tree为:[Tree{nodeId='002', nodeName='结点2'}, Tree{nodeId='003', nodeName='结点3'}] 002:结点2 003:结点3 第3次要遍历的tree为:[Tree{nodeId='004', nodeName='结点4'}] 004:结点4
代码
树的数据结构
package com.hdwang.test; import java.util.List; /** * 树 */ public class Tree { /** * 树结点ID */ private String nodeId; /** * 树结点名称 */ private String nodeName; /** * 孩子结点 */ private List<Tree> children; public String getNodeId() { return nodeId; } public void setNodeId(String nodeId) { this.nodeId = nodeId; } public String getNodeName() { return nodeName; } public void setNodeName(String nodeName) { this.nodeName = nodeName; } public List<Tree> getChildren() { return children; } public void setChildren(List<Tree> children) { this.children = children; } @Override public String toString() { return "Tree{" + "nodeId='" + nodeId + '\'' + ", nodeName='" + nodeName + '\'' + '}'; } }
遍历程序
package com.hdwang.test; import org.apache.commons.collections4.CollectionUtils; import java.util.*; /** * 递归改成for循环方式的例子 */ public class RecursiveToForTest { /** * 记录遍历的次数 */ private static Long index = 0L; public static void main(String[] args) { //构造一颗树 Tree tree = buildTree(); //递归遍历 System.out.println("递归方式遍历一棵树"); recursivePrint(tree); //索引重置 index = 0L; //循环遍历 System.out.println("\n循环方式遍历一棵树"); forPrint(tree); } /** * 递归方式打印输出一棵树 * * @param tree 树 */ private static void recursivePrint(Tree tree) { System.out.println("第" + (++index) + "次要遍历的tree为:" + tree); System.out.println(tree.getNodeId() + ":" + tree.getNodeName()); if (CollectionUtils.isNotEmpty(tree.getChildren())) { for (Tree child : tree.getChildren()) { recursivePrint(child); } } } /** * for循环方式打印一颗树 * * @param tree 树 */ private static void forPrint(Tree tree) { //使用列表存储需要遍历的树结点 List<Tree> treeList = new LinkedList<>(); treeList.add(tree); //当需要遍历的树列表不为空时,一直遍历输出结点信息 while (CollectionUtils.isNotEmpty(treeList)) { System.out.println("第" + (++index) + "次要遍历的tree为:" + treeList); List<Tree> waitToPrintTreeList = new ArrayList<>(); for (Tree treeNode : treeList) { System.out.println(treeNode.getNodeId() + ":" + treeNode.getNodeName()); //将孩子结点添加到待遍历列表 if (CollectionUtils.isNotEmpty(treeNode.getChildren())) { waitToPrintTreeList.addAll(treeNode.getChildren()); } } //移除已经遍历过的树结点 treeList.clear(); //将待遍历树结点添加到列表中 treeList.addAll(waitToPrintTreeList); } } /** * 构造一颗树 * * @return 树 */ private static Tree buildTree() { Tree tree001 = new Tree(); tree001.setNodeId("001"); tree001.setNodeName("根结点"); List<Tree> childrenOf001 = new ArrayList<>(); Tree tree002 = new Tree(); tree002.setNodeId("002"); tree002.setNodeName("结点2"); childrenOf001.add(tree002); Tree tree003 = new Tree(); tree003.setNodeId("003"); tree003.setNodeName("结点3"); childrenOf001.add(tree003); tree001.setChildren(childrenOf001); List<Tree> childrenOf002 = new ArrayList<>(); Tree tree004 = new Tree(); tree004.setNodeId("004"); tree004.setNodeName("结点4"); childrenOf002.add(tree004); tree002.setChildren(childrenOf002); System.out.println("构造的树为"); System.out.println(" Tree001 \n" + "\t\t / \\ \n" + "\tTree002 Tree003\n" + " / \n" + " Tree004 "); System.out.println(); return tree001; } }
结语
晦涩难懂的程序逻辑,掌握了本质之后,便豁然开朗了! 不管是递归还是循环本质都是:反复调用同一段代码,遍历的条件和待遍历的数据需要考虑。递归采用栈存储记录了待遍历的数据,循环只能自己去想办法存储待遍历的数据,至于循环条件都一样,有则遍历,无则罢了!