(id,pid)格式数据转树和森林结构工具类设计与实现

Posted 小熊vip

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(id,pid)格式数据转树和森林结构工具类设计与实现相关的知识,希望对你有一定的参考价值。

树形结构很多地方都有应用,比如我们在构造网站后台的授权限树的时候,再比如我们在设计多级留言的时候、还有分类等等。

有些时候我们的树形结构并不需要过多设计,这是因为我们的很多时候对这棵树的要求不高(两层、三层就行了),这时候我们很容易的会按照层级划分树形结构,然后查询数据库的时候会一层一层的嵌套查询。如果层次比较浅这种做法是可取的(或者我们本来就不打算一次将树加载完全,而是在需要时再加载,那分层级的多次加载也许有用武之地)。但是考虑这种情况:我们的树比较深,而且要一次加载完全。要是按照一层一层的加载原则,那么光是访问数据库的查询语句就是指数形式的了。性能肯定不好。那么除了一层一层的查询好有更好的办法吗?肯定是有的,多查询一些资料会发现这种做法比较常见了:(id,pid),通俗说就是一个节点只需要记住自己的id和父亲的id(根节点没有pid可以设置一个特殊值)就可以拥有呈现这棵树的完整结构全部信息了,仔细想一想自己学过的数据结构,是不是这样的?好了这样一来我们在设计数据库的时候就可以很轻松的设计一棵树的树形结构了。那么有个问题,我们在展现出来的时候总不能直接显示一连串的(id,pid)集合吧。我们要的是树形结构。这时候我们其实非常想实现的是从(id,pid)到

(id,children【】)的转化。毕竟我们在展现树形结构的时候后一种格式更适合页面的呈现,而前一种比较适合数据的存储格式。

好了废话不多说了,下面是代码示例:

首先是自定义节点类:

/**
 * 节点类
 * @author bearsmall
 *
 */
public class TreeNode 
	private int id;//主键ID
	private int pid;//父节点ID
	private Object content;//节点内容
	private List<TreeNode> children = new ArrayList<TreeNode>();//子孙节点
	
	public TreeNode(int id, Object content) 
		this.id = id;
		this.content = content;
	
	public TreeNode(int id, int pid, Object content) 
		this.id = id;
		this.pid = pid;
		this.content = content;
	
	
	public int getId() 
		return id;
	
	public void setId(int id) 
		this.id = id;
	
	public int getPid() 
		return pid;
	
	public void setPid(int pid) 
		this.pid = pid;
	
	public Object getContent() 
		return content;
	
	public void setContent(Object content) 
		this.content = content;
	
	public List<TreeNode> getChildren() 
		return children;
	
	public void setChildren(List<TreeNode> children) 
		this.children = children;
	
	@Override
	public String toString() 
		return "TreeNode [id=" + id + ", pid=" + pid + ", content=" + content
				+ ", children=" + children + "]";
	


然后是树节点管理类:

/**
 * 树节点管理类
 * 
 * @author bearsmall
 *
 */
public class TreeNodeManager 
	private List<TreeNode> list;// 树的所有节点

	public TreeNodeManager(TreeNode[] items) 
		list = new ArrayList<TreeNode>();
		for (TreeNode treeNode : items) 
			list.add(treeNode);
		
	

	public TreeNodeManager(List<TreeNode> items) 
		list = items;
	

	/**
	 * 根据节点ID获取一个节点
	 * 
	 * @param id
	 *            节点ID
	 * @return 对应的节点对象
	 */
	public TreeNode getTreeNodeAT(int id) 
		for (TreeNode treeNode : list) 
			if (treeNode.getId() == id)
				return treeNode;
		
		return null;
	

	/**
	 * 获取树的根节点
	 * 
	 * @return 一棵树的根节点
	 */
	public TreeNode getRoot() 
		for (TreeNode treeNode : list) 
			if (treeNode.getPid() == 0)
				return treeNode;
		
		return null;
	


最后是树节点转化类:

/**
 * 节点归并类
 * @author bearsmall
 *
 */
public class TreeNodeMerger 

	/**
	 * 将节点数组归并为一棵树(填充节点的children域)
	 * 时间复杂度为O(n^2)
	 * @param items 节点域
	 * @return
	 */
	public static TreeNode merge(TreeNode[] items)
		TreeNodeManager treeNodeManager = new TreeNodeManager(items);
		for (TreeNode treeNode : items) 
			if(treeNode.getPid()!=0)
				TreeNode t = treeNodeManager.getTreeNodeAT(treeNode.getPid());
				t.getChildren().add(treeNode);
			
		
		return treeNodeManager.getRoot();
	
	
	/**
	 * 将节点数组归并为一棵树(填充节点的children域)
	 *  时间复杂度为O(n^2)
	 * @param items 节点域
	 * @return
	 */
	public static TreeNode merge(List<TreeNode> items)
		TreeNodeManager treeNodeManager = new TreeNodeManager(items);
		for (TreeNode treeNode : items) 
			if(treeNode.getPid()!=0)
				TreeNode t = treeNodeManager.getTreeNodeAT(treeNode.getPid());
				t.getChildren().add(treeNode);
			
		
		return treeNodeManager.getRoot();
	


简单测试一下:

public class Main 
	public static void main(String[] args) 
		TreeNode[] treeNodes = new TreeNode[10];
		treeNodes[0] = new TreeNode(1, 0, "");
		treeNodes[1] = new TreeNode(2, 1, "");
		treeNodes[2] = new TreeNode(3, 1, "");
		treeNodes[3] = new TreeNode(4, 2, "");
		treeNodes[4] = new TreeNode(5, 3, "");
		treeNodes[5] = new TreeNode(6, 4, "");
		treeNodes[6] = new TreeNode(7, 3, "");
		treeNodes[7] = new TreeNode(8, 5, "");
		treeNodes[8] = new TreeNode(9, 6, "");
		treeNodes[9] = new TreeNode(10, 9, "");
		TreeNode treeNode = TreeNodeMerger.merge(treeNodes);
		JSONArray jsonArray = JSONArray.fromObject(treeNode);
		System.out.println(jsonArray);
	


输出结果:

[
		"children" : [
				"children" : [
						"children" : [
								"children" : [
										"children" : [
												"children" : [],
												"pid" : 9,
												"id" : 10,
												"content" : ""
											
										],
										"pid" : 6,
										"id" : 9,
										"content" : ""
									
								],
								"pid" : 4,
								"id" : 6,
								"content" : ""
							
						],
						"pid" : 2,
						"id" : 4,
						"content" : ""
					
				],
				"pid" : 1,
				"id" : 2,
				"content" : ""
			, 
				"children" : [
						"children" : [
								"children" : [],
								"pid" : 5,
								"id" : 8,
								"content" : ""
							
						],
						"pid" : 3,
						"id" : 5,
						"content" : ""
					, 
						"children" : [],
						"pid" : 3,
						"id" : 7,
						"content" : ""
					
				],
				"pid" : 1,
				"id" : 3,
				"content" : ""
			
		],
		"pid" : 0,
		"id" : 1,
		"content" : ""
	
]

这种格式是不是更清晰呢?

plus----------------------------------------------------------------------------森林的实现-----------------------------------------------------------------------------

森林管理类:

/**
 * 森林节点管理类
 * 
 * @author bearsmall
 *
 */
public class ForestNodeManager 
	private List<TreeNode> list;// 森林的所有节点

	public ForestNodeManager(TreeNode[] items) 
		list = new ArrayList<TreeNode>();
		for (TreeNode treeNode : items) 
			list.add(treeNode);
		
	

	public ForestNodeManager(List<TreeNode> items) 
		list = items;
	

	/**
	 * 根据节点ID获取一个节点
	 * 
	 * @param id
	 *            节点ID
	 * @return 对应的节点对象
	 */
	public TreeNode getTreeNodeAT(int id) 
		for (TreeNode treeNode : list) 
			if (treeNode.getId() == id)
				return treeNode;
		
		return null;
	

	/**
	 * 获取树的根节点【一个森林对应多颗树】
	 * 
	 * @return 树的根节点集合
	 */
	public List<TreeNode> getRoot() 
		List<TreeNode> roots = new ArrayList<TreeNode>();
		for (TreeNode treeNode : list) 
			if (treeNode.getPid() == 0)
				roots.add(treeNode);
		
		return roots;
	


森林节点归并类:

/**
 * 节点归并类
 * @author bearsmall
 *
 */
public class ForestNodeMerger 

	/**
	 * 将节点数组归并为一个森林(多棵树)(填充节点的children域)
	 * 时间复杂度为O(n^2)
	 * @param items 节点域
	 * @return 多棵树的根节点集合
	 */
	public static List<TreeNode> merge(TreeNode[] items)
		ForestNodeManager forestNodeManager = new ForestNodeManager(items);
		for (TreeNode treeNode : items) 
			if(treeNode.getPid()!=0)
				TreeNode t = forestNodeManager.getTreeNodeAT(treeNode.getPid());
				t.getChildren().add(treeNode);
			
		
		return forestNodeManager.getRoot();
	
	
	/**
	 * 将节点数组归并为一个森林(多棵树)(填充节点的children域)
	 * 时间复杂度为O(n^2)
	 * @param items 节点域
	 * @return 多棵树的根节点集合
	 */
	public static List<TreeNode> merge(List<TreeNode> items)
		ForestNodeManager forestNodeManager = new ForestNodeManager(items);
		for (TreeNode treeNode : items) 
			if(treeNode.getPid()!=0)
				TreeNode t = forestNodeManager.getTreeNodeAT(treeNode.getPid());
				t.getChildren().add(treeNode);
			
		
		return forestNodeManager.getRoot();
	


测一下:

public class Main2 
	public static void main(String[] args) 
		TreeNode[] treeNodes = new TreeNode[10];
		treeNodes[0] = new TreeNode(1, 0, "");
		treeNodes[1] = new TreeNode(2, 0, "");
		treeNodes[2] = new TreeNode(3, 1, "");
		treeNodes[3] = new TreeNode(4, 2, "");
		treeNodes[4] = new TreeNode(5, 3, "");
		treeNodes[5] = new TreeNode(6, 4, "");
		treeNodes[6] = new TreeNode(7, 3, "");
		treeNodes[7] = new TreeNode(8, 5, "");
		treeNodes[8] = new TreeNode(9, 6, "");
		treeNodes[9] = new TreeNode(10, 9, "");
		List<TreeNode> tns = ForestNodeMerger.merge(treeNodes);
		JSONArray jsonArray = JSONArray.fromObject(tns);
		System.out.println(jsonArray);
	


打印输出:

[
		"children" : [
				"children" : [
						"children" : [
								"children" : [],
								"pid" : 5,
								"id" : 8,
								"content" : ""
							
						],
						"pid" : 3,
						"id" : 5,
						"content" : ""
					, 
						"children" : [],
						"pid" : 3,
						"id" : 7,
						"content" : ""
					
				],
				"pid" : 1,
				"id" : 3,
				"content" : ""
			
		],
		"pid" : 0,
		"id" : 1,
		"content" : ""
	, 
		"children" : [
				"children" : [
						"children" : [
								"children" : [
										"children" : [],
										"pid" : 9,
										"id" : 10,
										"content" : ""
									
								],
								"pid" : 6,
								"id" : 9,
								"content" : ""
							
						],
						"pid" : 4,
						"id" : 6,
						"content" : ""
					
				],
				"pid" : 2,
				"id" : 4,
				"content" : ""
			
		],
		"pid" : 0,
		"id" : 2,
		"content" : ""
	
]
ok!

以上是关于(id,pid)格式数据转树和森林结构工具类设计与实现的主要内容,如果未能解决你的问题,请参考以下文章

二维表转树结构

树的存储结构;树与二叉树的转换;树和森林的遍历算法

数据结构——第二章树和森林:04哈夫曼树与哈夫曼编码

决策树与随机森林

数据结构——第三章树和二叉树:03树和森林

集合转树json