树的遍历
(一)树结构实现
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 }