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

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

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

/**
 * 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

 

转载于:https://my.oschina.net/phridem/blog/786768

你可能感兴趣的:(递归获取拉平存储的树每个节点到达的路径)