您的位置:首页 > 其它

递归获取拉平存储的树每个节点到达的路径

2016-11-12 00:00 447 查看
最近公司的一个项目需要把存储在数据库中树结构拉出来,并且要计算到达每个节点的路径。下午想了一下实现,周一要交差,抽出关键代码:

/**
* 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<Node> nodes) {

for (Node node : nodes) {
List<String> path = newArrayList();
recurNode(nodes, node, node, path);
}
}

/**
* 递归查找父节点
*
* @param nodes
*            所有节点
* @param targetNode
*            目标节点
* @param currentNode
*            当前节点
* @param path
*            路径
*/
private static void recurNode(List<Node> nodes, Node targetNode,
Node currentNode, List<String> 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<Node> 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  递归