一、示例:
樹的結構:

示例中自己構建了圖片中的這棵樹:
樹節點模型:
public class TreeNode { String value; List<TreeNode> children; public TreeNode() { children = new ArrayList<>(); } public TreeNode(String value) { this.value = value; children = new ArrayList<>(); } @Override public String toString() { // TODO Auto-generated method stub return value; } }
構建樹:
// 創建一棵樹 TreeNode root = new TreeNode("A"); // 第二層 root.children.add(new TreeNode("B")); root.children.add(new TreeNode("C")); // 第三層 root.children.get(0).children.add(new TreeNode("D")); root.children.get(0).children.add(new TreeNode("E")); root.children.get(1).children.add(new TreeNode("F")); root.children.get(1).children.add(new TreeNode("H")); root.children.get(1).children.add(new TreeNode("G")); // 第四層 root.children.get(0).children.get(1).children.add(new TreeNode("I"));
二、遍歷方式
提供三種方式進行遍歷:
① 遞歸形式的深度優先遍歷:
/** * 深度優先遍歷(遞歸方式) --- 樹(Tree) */ public void recurTree(TreeNode root) { List<List<String>> result = new ArrayList<>(); List<String> path = new ArrayList<>(); path.add(root.value); findPath(result, root, path); System.out.println(result); } private void findPath(List<List<String>> result, TreeNode node, List<String> path) { if (node.children == null || node.children.size() <= 0) { result.add(path); return; } for (int i = 0; i < node.children.size(); i++) { TreeNode child = node.children.get(i); List<String> cPath = new ArrayList<>(); cPath.addAll(path); cPath.add(child.value); findPath(result, child, cPath, target); } }
② 非遞歸的深度優先遍歷
/** * 深度優先遍歷(非遞歸方式) ----- 查找樹的所有葉子路徑 * * @param root * 根節點 * @return 葉子路徑的集合 */ public List<List<TreeNode>> dfsTree(TreeNode root) { Stack<TreeNode> nodeStack = new Stack<>(); Stack<List<TreeNode>> pathStack = new Stack<>(); List<List<TreeNode>> result = new ArrayList<>(); nodeStack.push(root); ArrayList<TreeNode> arrayList = new ArrayList<>(); arrayList.add(root); pathStack.push(arrayList); while (!nodeStack.isEmpty()) { TreeNode curNode = nodeStack.pop(); List<TreeNode> curPath = pathStack.pop(); if (curNode.children == null || curNode.children.size() <= 0) { result.add(curPath); } else { int childSize = curNode.children.size(); for (int i = childSize - 1; i >= 0; i--) { TreeNode node = curNode.children.get(i); nodeStack.push(node); List<TreeNode> list = new ArrayList<>(curPath); list.add(node); pathStack.push(list); } } } return result; }
3. 廣度優先遍歷,遍歷所有葉子路徑
/** * 廣度優先遍歷 ---- 查找樹的所有葉子路徑 * * @param root * 根節點 * @return 葉子路徑的集合 */ public List<List<TreeNode>> bfsTree(TreeNode root) { Queue<TreeNode> nodeQueue = new LinkedList<>(); Queue<List<TreeNode>> qstr = new LinkedList<>(); List<List<TreeNode>> result = new ArrayList<>(); nodeQueue.add(root); ArrayList<TreeNode> arrayList = new ArrayList<>(); qstr.add(arrayList); while (!nodeQueue.isEmpty()) { TreeNode curNode = nodeQueue.remove(); List<TreeNode> curList = qstr.remove(); if (curNode.children == null || curNode.children.size() <= 0) { curList.add(curNode); result.add(curList); } else { for (int i = 0; i < curNode.children.size(); i++) { TreeNode treeNode = curNode.children.get(i); nodeQueue.add(treeNode); List<TreeNode> list = new ArrayList<>(curList); list.add(curNode); qstr.add(list); } } } return result; }
三種方式的輸出:
深度優先遍歷(遞歸):[[A, B, D], [A, B, E, I], [A, C, F], [A, C, H], [A, C, G]]
廣度優先遍歷:[[A, B, D], [A, C, F], [A, C, H], [A, C, G], [A, B, E, I]]
深度優先遍歷(非遞歸):[[A, B, D], [A, B, E, I], [A, C, F], [A, C, H], [A, C, G]]
三、總結
示例是查找樹的所有葉子節點,舉一反三,如果我們是查找樹中滿足某個條件的路徑,也是非常容易了。比如下面中查找 “ E ” 的分支:
public void recurTree(TreeNode root) { List<List<String>> result = new ArrayList<>(); List<String> path = new ArrayList<>(); path.add(root.value); findPath(result, root, path, "E"); System.out.println(result); } private void findPath(List<List<String>> result, TreeNode node, List<String> path, String target) { if (target.equals(node.value)) { result.add(path); return; } if (node.children == null || node.children.size() <= 0) { return; } for (int i = 0; i < node.children.size(); i++) { TreeNode child = node.children.get(i); List<String> cPath = new ArrayList<>(); cPath.addAll(path); cPath.add(child.value); if (result.size() > 0) break; findPath(result, child, cPath, target); } }
輸出:
[[A, B, E]]
