[数据结构与算法]树的多种遍历方式

树的遍历

(一)树结构实现

  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 }
posted @ 2015-02-13 10:41  江正军  阅读(2391)  评论(0编辑  收藏  举报