2019独角兽企业重金招聘Python工程师标准>>>
最近公司的一个项目需要把存储在数据库中树结构拉出来,并且要计算到达每个节点的路径。下午想了一下实现,周一要交差,抽出关键代码:
/**
* Copyright © 2016 my. All rights reserved.
*/
package cn.mycompay.mysystem;
import static java.text.MessageFormat.format;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.base.Joiner.on;
import static com.google.common.collect.Lists.reverse;
/**
* 获取到达树每个节点的路径
*
* @author James 2016年11月12日 下午4:14:58
*
*/
public class TreePath {
/**
* 根据平铺树计算路径
*
* @param nodes
*/
private static void genPath(List nodes) {
for (Node node : nodes) {
List path = newArrayList();
recurNode(nodes, node, node, path);
}
}
/**
* 递归查找父节点
*
* @param nodes
* 所有节点
* @param targetNode
* 目标节点
* @param currentNode
* 当前节点
* @param path
* 路径
*/
private static void recurNode(List nodes, Node targetNode,
Node currentNode, List path) {
if (StringUtils.equals(currentNode.getNodeNo(),
currentNode.getParentNodeNo())) {
throw new RuntimeException(format("非法的树结构,node:{0}",
currentNode.getNodeNo()));
}
path.add(checkNotNull(emptyToNull(currentNode.getNodeCode()),
format("节点编码为空,node:{0}", currentNode.getNodeNo())));
// 终止条件,这里约定null,""表示根节点
if (StringUtils.isBlank(currentNode.getParentNodeNo())) {
targetNode.setPath(on(".").join(reverse(path)));
return;
}
// 节点编号必须唯一,每次只能找到一个父节点
for (Node node : nodes) {
if (StringUtils.equals(currentNode.getParentNodeNo(),
node.getNodeNo())) {
recurNode(nodes, targetNode, node, path);
return;
}
}
// 既不是根节点又无法找到父节点
throw new RuntimeException(format("非法的树结构,node:{0}",
currentNode.getNodeNo()));
}
/**
* @param args
*/
public static void main(String[] args) {
List tree = newArrayList();
// 第一颗课树
tree.add(new Node("1", "A", ""));
tree.add(new Node("2", "B", "1"));
tree.add(new Node("3", "C", "2"));
tree.add(new Node("4", "D", "3"));
tree.add(new Node("5", "E", "1"));
tree.add(new Node("6", "F", "2"));
// 第二课树
tree.add(new Node("11", "AA", ""));
tree.add(new Node("22", "BB", "11"));
tree.add(new Node("33", "CC", "22"));
tree.add(new Node("44", "DD", "33"));
tree.add(new Node("55", "EE", "11"));
tree.add(new Node("66", "FF", "22"));
tree.add(new Node("77", "GG", "66"));
genPath(tree);
for (Node node : tree) {
System.out.println(node.getPath());
}
}
}
/**
* 平铺的树 对应数据库中一条记录
*
* @author James 2016年11月12日 下午4:15:26
*
*/
class Node {
public Node(String nodeNo, String nodeCode, String parentNodeNo) {
super();
this.nodeNo = nodeNo;
this.nodeCode = nodeCode;
this.parentNodeNo = parentNodeNo;
}
/**
* 节点唯一编号
*/
private String nodeNo;
/**
* 节点编码
*/
private String nodeCode;
/**
* 父节点编码
*/
private String parentNodeNo;
/**
* 根据元数据递归生成到达节点路径
*/
private String path;
/**
* @return the nodeNo
*/
public String getNodeNo() {
return nodeNo;
}
/**
* @param nodeNo
* the nodeNo to set
*/
public void setNodeNo(String nodeNo) {
this.nodeNo = nodeNo;
}
/**
* @return the nodeCode
*/
public String getNodeCode() {
return nodeCode;
}
/**
* @param nodeCode
* the nodeCode to set
*/
public void setNodeCode(String nodeCode) {
this.nodeCode = nodeCode;
}
/**
* @return the parentNodeNo
*/
public String getParentNodeNo() {
return parentNodeNo;
}
/**
* @param parentNodeNo
* the parentNodeNo to set
*/
public void setParentNodeNo(String parentNodeNo) {
this.parentNodeNo = parentNodeNo;
}
/**
* @return the path
*/
public String getPath() {
return path;
}
/**
* @param path
* the path to set
*/
public void setPath(String path) {
this.path = path;
}
}
输出结果:
A
A.B
A.B.C
A.B.C.D
A.E
A.B.F
AA
AA.BB
AA.BB.CC
AA.BB.CC.DD
AA.EE
AA.BB.FF
AA.BB.FF.GG