递归改写成循环方式的实现例子-树的遍历

结果

构造的树为
          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;
    }
}

 

结语

晦涩难懂的程序逻辑,掌握了本质之后,便豁然开朗了! 不管是递归还是循环本质都是:反复调用同一段代码,遍历的条件和待遍历的数据需要考虑。递归采用栈存储记录了待遍历的数据,循环只能自己去想办法存储待遍历的数据,至于循环条件都一样,有则遍历,无则罢了!

posted @ 2021-05-29 16:46  追极  阅读(664)  评论(0编辑  收藏  举报