zoukankan      html  css  js  c++  java
  • [数据结构与算法]树的多种遍历方式

    树的遍历

    (一)树结构实现

      1 package tree.tree;
      2 
      3 import java.util.Iterator;
      4 import java.util.List;
      5 
      6 /**
      7  * 树节点抽象接口
      8  * 
      9  * @author jzj
     10  * @data 2009-12-17
     11  */
     12 public abstract class TreeNode implements Comparable {
     13 
     14     //父节点
     15     private TreeNode pNode;
     16 
     17     //数据域,节点编号,不能修改
     18     private int nodeId;
     19 
     20     //数据域,节点名字,能修改
     21     private String nodeName;
     22 
     23     //节点深度,根默认为0
     24     private int depth;
     25 
     26     public TreeNode getPMenuComponent() {
     27         return pNode;
     28     }
     29 
     30     public void setPMenuComponent(TreeNode menuComponent) {
     31         pNode = menuComponent;
     32     }
     33 
     34     public int getNodeId() {
     35         return nodeId;
     36     }
     37 
     38     public void setNodeId(int nodeId) {
     39         this.nodeId = nodeId;
     40     }
     41 
     42     public String getNodeName() {
     43         return nodeName;
     44     }
     45 
     46     public void setNodeName(String nodeName) {
     47         this.nodeName = nodeName;
     48     }
     49 
     50     public int getDepth() {
     51         return depth;
     52     }
     53 
     54     public void setDepth(int depth) {
     55         this.depth = depth;
     56     }
     57 
     58     //添加子节点 默认不支持,叶子节点不支持此功能
     59     public void addSubNode(TreeNode menuComponent) {
     60         throw new UnsupportedOperationException();
     61     }
     62 
     63     //删除子节点 默认不支持,叶子节点不支持此功能
     64     public void removeSubNode(TreeNode menuComponent) {
     65         throw new UnsupportedOperationException();
     66     }
     67 
     68     //修改节点信息
     69     public void modiNodeInfo(String nodeName) {
     70         this.setNodeName(nodeName);
     71     }
     72 
     73     //获取子节点 默认不支持,叶子节点不支持此功能
     74     public List getSubNodes() {
     75         throw new UnsupportedOperationException();
     76     }
     77 
     78     //打印节点信息
     79     public void print() {
     80         throw new UnsupportedOperationException();
     81     }
     82 
     83     //获取节点信息
     84     protected abstract StringBuffer getNodeInfo();
     85 
     86     //提供深度迭代器 默认不支持,叶子节点不支持此功能
     87     public Iterator createDepthOrderIterator() {
     88         throw new UnsupportedOperationException();
     89     }
     90 
     91     //提供广度优先迭代器 默认不支持,叶子节点不支持此功能
     92     public Iterator createLayerOrderIterator() {
     93         throw new UnsupportedOperationException();
     94     }
     95 
     96     /**
     97      * 根据树节点id,在当然节点与子节点中搜索指定的节点
     98      * @param treeId
     99      * @return TreeNode
    100      */
    101     public TreeNode getTreeNode(int treeId) {
    102         return getNode(this, treeId);
    103     }
    104 
    105     /**
    106      * 使用树的先序遍历递归方式查找指定的节点
    107      * 
    108      * @param treeNode 查找的起始节点
    109      * @param treeId 节点编号
    110      * @return
    111      */
    112     protected TreeNode getNode(TreeNode treeNode, int treeId) {
    113         throw new UnsupportedOperationException();
    114     }
    115 
    116     public int compareTo(Object o) {
    117 
    118         TreeNode temp = (TreeNode) o;
    119 
    120         return this.getNodeId() > temp.getNodeId() ? 1 : (this.getNodeId() < temp
    121                 .getNodeId() ? -1 : 0);
    122     }
    123 
    124     public boolean equals(Object menuComponent) {
    125 
    126         if (!(menuComponent instanceof TreeNode)) {
    127             return false;
    128         }
    129         TreeNode menu = (TreeNode) menuComponent;
    130 
    131         // 如果两个节点的nodeID相应则认为是同一节点
    132         return this.getNodeId() == menu.getNodeId();
    133     }
    134 }
      1 package tree.tree;
      2 
      3 import java.util.ArrayList;
      4 import java.util.Iterator;
      5 import java.util.List;
      6 
      7 /**
      8  * 树的分支节点
      9  *
     10  * @author jzj
     11  * @data 2009-12-17
     12  */
     13 public class TreeBranchNode extends TreeNode {
     14 
     15     //存储子节点
     16     List subNodesList = new ArrayList();
     17 
     18     public TreeBranchNode(int nodeId, String nodeName) {
     19         this.setNodeId(nodeId);
     20         this.setNodeName(nodeName);
     21     }
     22 
     23     //添加子节点
     24     public void addSubNode(TreeNode menuComponent) {
     25         // 设置父节点
     26         menuComponent.setPMenuComponent(this);
     27 
     28         // 设置节点的深度
     29         menuComponent.setDepth(this.getDepth() + 1);
     30         subNodesList.add(menuComponent);
     31     }
     32 
     33     //删除一个子节点
     34     public void removeSubNode(TreeNode menuComponent) {
     35         subNodesList.remove(menuComponent);
     36     }
     37 
     38     //获取子节点
     39     public List getSubNodes() {
     40         return subNodesList;
     41     }
     42 
     43     //打印节点信息,以树的形式展示,所以它包括了所有子节点信息
     44     public void print() {
     45         System.out.println(this.getNodeInfo());
     46     }
     47 
     48     //打印节点本身信息,不递归打印子节点信息
     49     public String toString() {
     50         return getSefNodeInfo().toString();
     51     }
     52 
     53     // 递归打印节点信息实现
     54     protected StringBuffer getNodeInfo() {
     55 
     56         StringBuffer sb = getSefNodeInfo();
     57         sb.append(System.getProperty("line.separator"));
     58         //如果有子节点
     59         for (Iterator iter = subNodesList.iterator(); iter.hasNext();) {
     60             TreeNode node = (TreeNode) iter.next();
     61             //递归打印子节点信息
     62             sb.append(node.getNodeInfo());
     63 
     64             if (iter.hasNext()) {
     65                 sb.append(System.getProperty("line.separator"));
     66             }
     67 
     68         }
     69         return sb;
     70     }
     71 
     72     //节点本身信息,不含子节点信息
     73     private StringBuffer getSefNodeInfo() {
     74         StringBuffer sb = new StringBuffer();
     75 
     76         // 打印缩进
     77         for (int i = 0; i < this.getDepth(); i++) {
     78             sb.append(' ');
     79         }
     80         sb.append("+--");
     81 
     82         sb.append("[nodeId=");
     83         sb.append(this.getNodeId());
     84         sb.append(" nodeName=");
     85 
     86         sb.append(this.getNodeName());
     87         sb.append(']');
     88         return sb;
     89     }
     90 
     91     //为外界提供遍历组合结构的迭代器
     92     public Iterator createDepthOrderIterator() {
     93         return new TreeOutOrder.DepthOrderIterator(this);
     94     }
     95 
     96     //为外界提供遍历组合结构的迭代器
     97     public Iterator createLayerOrderIterator() {
     98         return new TreeOutOrder.LevelOrderIterator(this);
     99     }
    100 
    101     /**
    102      * 使用树的先序遍历递归方式查找指定的节点
    103      * 
    104      * @param treeNode 查找的起始节点
    105      * @param treeId 节点编号
    106      * @return
    107      */
    108     protected TreeNode getNode(TreeNode treeNode, int treeId) {
    109 
    110         //如果找到,则停止后续搜索,并把查找到的节点返回给上层调用者
    111         if (treeNode.getNodeId() == treeId) {//1、先与父节点比对
    112             return treeNode;
    113         }
    114 
    115         TreeNode tmp = null;
    116 
    117         //如果为分支节点,则遍历子节点
    118         if (treeNode instanceof TreeBranchNode) {
    119 
    120             for (int i = 0; i < treeNode.getSubNodes().size(); i++) {//2、再与子节点比对
    121                 tmp = getNode((TreeNode) treeNode.getSubNodes().get(i), treeId);
    122                 if (tmp != null) {//如果查找到,则返回上层调用者
    123                     return tmp;
    124                 }
    125             }
    126         }
    127 
    128         //如果没有找到,返回上层调用者
    129         return null;
    130     }
    131 }
     1 package tree.tree;
     2 
     3 /**
     4  * 树的叶子节点
     5  *
     6  * @author jzj
     7  * @data 2009-12-17
     8  *
     9  */
    10 public class TreeLeafNode extends TreeNode {
    11     public TreeLeafNode(int nodeId, String nodeName) {
    12         this.setNodeId(nodeId);
    13         this.setNodeName(nodeName);
    14     }
    15 
    16     // 获取叶子节点信息
    17     protected StringBuffer getNodeInfo() {
    18         StringBuffer sb = new StringBuffer();
    19 
    20         // 打印缩进
    21         for (int i = 0; i < this.getDepth(); i++) {
    22             sb.append(' ');
    23         }
    24         sb.append("---");
    25 
    26         sb.append("[nodeId=");
    27         sb.append(this.getNodeId());
    28         sb.append(" nodeName=");
    29 
    30         sb.append(this.getNodeName());
    31         sb.append(']');
    32 
    33         return sb;
    34     }
    35 
    36     public String toString() {
    37         return getNodeInfo().toString();
    38     }
    39 }

    (二)利用树本身特点进行递归遍历(属内部遍历)

    树的内部遍历方式有两种:前序遍历、后序遍历,注,没有中序遍历。与二叉树的内部遍历方式一样也是采用递归方式实现的。

     1 package tree.tree;
     2 
     3 /**
     4  * 树的两种 内部 遍历方式:前序遍历、后序遍历
     5  * 
     6  * @author jzj
     7  * @data 2009-12-17
     8  */
     9 public class TreeInOrder {
    10 
    11     /**
    12      * 树的前序递归遍历 pre=prefix(前缀)
    13      * @param node 要遍历的节点
    14      */
    15     public static void preOrder(TreeNode node) {
    16         //如果传进来的节点不为空,则遍历,注,叶子节点的子节点为null
    17         if (node != null) {
    18             System.out.print(node.getNodeId() + " ");//先遍历父节点
    19 
    20             if (node instanceof TreeBranchNode) {
    21                 for (int i = 0; i < node.getSubNodes().size(); i++) {
    22                     preOrder((TreeNode) node.getSubNodes().get(i));//再遍历子节点
    23                 }
    24             }
    25 
    26         }
    27     }
    28 
    29     /**
    30      * 树的后序递归遍历 post=postfix(后缀)
    31      * @param node 要遍历的节点
    32      */
    33     public static void postOrder(TreeNode node) {
    34         //如果传进来的节点不为空,则遍历
    35         if (node != null) {
    36             //如果为分支节点,则遍历子节点
    37             if (node instanceof TreeBranchNode) {
    38 
    39                 for (int i = 0; i < node.getSubNodes().size(); i++) {
    40                     postOrder((TreeNode) node.getSubNodes().get(i));//先遍历子节点
    41                 }
    42             }
    43             System.out.print(node.getNodeId() + " ");//后遍历父节点
    44         }
    45     }
    46 }

    (三)利用栈与队列对树进行非递归遍历(属外部遍历)

    树的两种外部非递归遍历方式:深度优先(即先根)遍历、广度优先(即层次)遍历。它们需借助于栈与队列来实现。

      1 package tree.tree;
      2 
      3 import java.util.ArrayList;
      4 import java.util.Iterator;
      5 import java.util.Stack;
      6 
      7 import queue.LinkedQueue;
      8 
      9 public class TreeOutOrder {
     10     /**
     11      * 深度优先遍历迭代器
     12      * 
     13      * @author jzj
     14      * @data 2009-12-17
     15      */
     16     public static class DepthOrderIterator implements Iterator {
     17         //栈,用来深度遍历树节点,以便回溯
     18         Stack stack = new Stack();
     19 
     20         public DepthOrderIterator(TreeNode rootNode) {
     21             ArrayList list = new ArrayList();
     22             list.add(rootNode);
     23 
     24             // 将根节点迭代器入栈
     25             stack.push(list.iterator());
     26         }
     27 
     28         //是否有下一元素
     29         public boolean hasNext() {
     30             // 如果栈为空则返回,证明没有可遍历的元素
     31             if (stack.empty()) {
     32                 return false;
     33             } else {
     34                 // 如果栈不为空,则取出栈顶元素(迭代器)
     35                 Iterator iterator = (Iterator) stack.peek();
     36 
     37                 // 这里使用简单元素(即线性排列的元素,而不是树状结构的元素)的方式来遍历
     38                 if (!iterator.hasNext()) {
     39                     // 如果取出迭代器已经遍历完成,则弹出迭代器,以便回退到上一(父)迭代器继续开妈以深度优先方式遍历
     40                     stack.pop();
     41 
     42                     // 通过递归方式继续遍历父迭代器还未遍历到的节点元素
     43                     return hasNext();
     44                 } else {
     45                     // 如果找到了下一个元素,返回true
     46                     return true;
     47                 }
     48             }
     49         }
     50 
     51         // 取下一元素
     52         public Object next() {
     53             // 如果还有下一个元素,则先取到该元素所对应的迭代器引用,以便取得该节点元素
     54             if (hasNext()) {
     55                 Iterator iterator = (Iterator) stack.peek();
     56                 // 获取该节点元素
     57                 TreeNode component = (TreeNode) iterator.next();
     58 
     59                 //只有分支节点需进一步对子节点进行迭代
     60                 if (component instanceof TreeBranchNode) {
     61                     stack.push(component.getSubNodes().iterator());
     62                 }
     63 
     64                 // 返回遍历得到的节点
     65                 return component;
     66             } else {
     67                 // 如果栈为空
     68                 return null;
     69             }
     70         }
     71 
     72         public void remove() {
     73             throw new UnsupportedOperationException();
     74         }
     75     }
     76 
     77     /**
     78      * 层次遍历迭代器
     79      * 
     80      * @author jzj
     81      * @data 2009-12-17
     82      */
     83     public static class LevelOrderIterator implements Iterator {
     84         //队列,实现层次遍历,存入节点迭代器
     85         private LinkedQueue queue = new LinkedQueue();
     86 
     87         public LevelOrderIterator(TreeNode rootNode) {
     88             ArrayList list = new ArrayList();
     89             list.add(rootNode);
     90 
     91             // 将根节点迭代器入队
     92             queue.enqueue(list.iterator());
     93         }
     94 
     95         //是否有下一元素
     96         public boolean hasNext() {
     97             // 如果队列为空则返回
     98             if (queue.isEmpty()) {
     99                 return false;
    100             } else {
    101                 // 如果队列不为空,则取出队首元素(迭代器)
    102                 Iterator iterator = (Iterator) queue.front();
    103 
    104                 if (!iterator.hasNext()) {
    105                     // 如果取出迭代器已经遍历完成,则出队
    106                     queue.dequeue();
    107 
    108                     // 通过递归方式继续遍历父迭代器是否还有未遍历到的节点元素
    109                     return hasNext();
    110                 } else {
    111                     // 如果找到了下一个元素,返回true
    112                     return true;
    113                 }
    114             }
    115         }
    116 
    117         // 取下一元素
    118         public Object next() {
    119             // 如果还有下一个元素
    120             if (hasNext()) {
    121                 Iterator iterator = (Iterator) queue.front();
    122                 // 获取该节点元素
    123                 TreeNode component = (TreeNode) iterator.next();
    124 
    125                 //只有分支节点需进一步对子节点进行迭代
    126                 if (component instanceof TreeBranchNode) {
    127                     queue.enqueue(component.getSubNodes().iterator());
    128                 }
    129 
    130                 // 返回遍历得到的节点
    131                 return component;
    132             } else {
    133                 // 如果栈为空
    134                 return null;
    135             }
    136         }
    137 
    138         public void remove() {
    139             throw new UnsupportedOperationException();
    140         }
    141     }
    142 }

    (四)测试

      1 package tree.tree;
      2 
      3 import java.util.Iterator;
      4 
      5 /**
      6  * 测试
      7  * @author jzj
      8  * @data 2009-12-17
      9  */
     10 public class TestTreeOrder {
     11     public static void main(String[] args) {
     12         TreeNode root = new TreeBranchNode(1, "one");
     13         TreeNode n2 = new TreeBranchNode(2, "two");
     14         TreeNode n3 = new TreeBranchNode(3, "three");
     15         TreeNode n4 = new TreeBranchNode(4, "four");
     16         TreeNode n5 = new TreeBranchNode(5, "five");
     17         TreeNode n6 = new TreeLeafNode(6, "six");
     18         TreeNode n7 = new TreeLeafNode(7, "seven");
     19         TreeNode n8 = new TreeBranchNode(8, "eight");
     20         TreeNode n9 = new TreeLeafNode(9, "nine");
     21         TreeNode n10 = new TreeBranchNode(10, "ten");
     22         TreeNode n11 = new TreeLeafNode(11, "eleven");
     23         TreeNode n12 = new TreeLeafNode(12, "twelve");
     24         TreeNode n13 = new TreeLeafNode(13, "thirteen");
     25         TreeNode n14 = new TreeLeafNode(14, "fourteen");
     26         TreeNode n15 = new TreeLeafNode(15, "fifteen");
     27         TreeNode n16 = new TreeLeafNode(16, "sixteen");
     28         TreeNode n17 = new TreeLeafNode(17, "seventeen");
     29         TreeNode n18 = new TreeLeafNode(18, "eighteen");
     30         root.addSubNode(n2);
     31         root.addSubNode(n3);
     32         root.addSubNode(n4);
     33         n2.addSubNode(n5);
     34         n3.addSubNode(n6);
     35         n3.addSubNode(n7);
     36         n3.addSubNode(n8);
     37         n3.addSubNode(n9);
     38         n4.addSubNode(n10);
     39         n5.addSubNode(n11);
     40         n5.addSubNode(n12);
     41         n8.addSubNode(n13);
     42         n8.addSubNode(n14);
     43         n8.addSubNode(n15);
     44         n10.addSubNode(n16);
     45         n10.addSubNode(n17);
     46         n10.addSubNode(n18);
     47 
     48         root.print();
     49 
     50         Iterator itr = root.createDepthOrderIterator();
     51         System.out.print("深度(先根)遍历 - ");
     52         while (itr.hasNext()) {
     53             System.out.print(((TreeNode) itr.next()).getNodeId() + " ");
     54         }
     55         System.out.println();
     56         itr = root.createLayerOrderIterator();
     57         System.out.print("广度(层次)遍历 - ");
     58         while (itr.hasNext()) {
     59             System.out.print(((TreeNode) itr.next()).getNodeId() + " ");
     60         }
     61 
     62         System.out.println();
     63         System.out.print("先序遍历 - ");
     64         TreeInOrder.preOrder(root);
     65         System.out.println();
     66         System.out.print("后序遍历 - ");
     67         TreeInOrder.postOrder(root);
     68         System.out.println();
     69         for (int i = 1; i <= 18; i++) {
     70             System.out.print(root.getTreeNode(i).getNodeId() + " ");
     71         }
     72         /*
     73          * print:
     74          * 
     75          *+--[nodeId=1 nodeName=one]
     76          * +--[nodeId=2 nodeName=two]
     77          *  +--[nodeId=5 nodeName=five]
     78          *   ---[nodeId=11 nodeName=eleven]
     79          *   ---[nodeId=12 nodeName=twelve]
     80          * +--[nodeId=3 nodeName=three]
     81          *  ---[nodeId=6 nodeName=six]
     82          *  ---[nodeId=7 nodeName=seven]
     83          *  +--[nodeId=8 nodeName=eight]
     84          *   ---[nodeId=13 nodeName=thirteen]
     85          *   ---[nodeId=14 nodeName=fourteen]
     86          *   ---[nodeId=15 nodeName=fifteen]
     87          *  ---[nodeId=9 nodeName=nine]
     88          * +--[nodeId=4 nodeName=four]
     89          *  +--[nodeId=10 nodeName=ten]
     90          *   ---[nodeId=16 nodeName=sixteen]
     91          *   ---[nodeId=17 nodeName=seventeen]
     92          *   ---[nodeId=18 nodeName=eighteen]
     93          *   
     94          *   深度(先根)遍历 - 1 2 5 11 12 3 6 7 8 13 14 15 9 4 10 16 17 18 
     95          *   广度(层次)遍历 - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 
     96          *   先序遍历 - 1 2 5 11 12 3 6 7 8 13 14 15 9 4 10 16 17 18 
     97          *   后序遍历 - 11 12 5 2 6 7 13 14 15 8 9 3 16 17 18 10 4 1 
     98          *   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 
     99          */
    100     }
    101 }
  • 相关阅读:
    安装mysql
    工坊第十天
    工坊第九天
    友链qaq
    About me
    好耶
    [Ynoi2011]初始化
    [Ynoi2013]大学
    [Ynoi2015]盼君勿忘
    [Ynoi2019模拟赛]Yuno loves sqrt technology III
  • 原文地址:https://www.cnblogs.com/jiangzhengjun/p/4289824.html
Copyright © 2011-2022 走看看