玄星幻月001-树结构复制
玄星幻月001-树结构复制
前言:在实际开发中,可能会遇到一些通用的代码块,临时想比较费时耗力,如果做好记录就能很方便的拿来即用,省时省力。该系列将会记录本人项目或其他地方遇到比较好的例子来展开记录。玄星幻月:高中就开始喜欢这个词了,就以此作为系列名称!先定个小目标,数量突破三位数。(^_^)
背景:
树结构是在项目中比较常见的一种结构,向单项列表一样,每个节点属性都会存放着下一节点的id。有时候需要将一棵树复制并另存为另外的树,但是由于表主键的唯一性,如何保证复制后在每个节点主键变化的提前下又保证树的结构呢?
现在通过主键映射的方式来复制树结构,这样的好处是只需要按照原来的树结构映射替换它的主键,就可以保证树结构不变的又实现树的复制功能。
案例
节点信息
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class TreeNode {/*** 节点名称*/private String nodeName;/*** 节点Id*/private String nodeId;/*** 节点Id*/private String nodePid;/*** 为了方便测试,初始化一棵树* * @return List*/ public static List<TreeNode> createTreeA() {TreeNode ziyang = new TreeNode("ziyang", "a1", "-1");TreeNode ziyue = new TreeNode("ziyue", "a2", "a1");TreeNode zixing = new TreeNode("zixing", "a3", "a2");TreeNode zichen = new TreeNode("zichen", "a4", "a3");return new ArrayList<>(Arrays.asList(ziyang, ziyue, zixing, zichen));}
原树图示

此树结构有4层,跟节点是"ziyang",其父节点id为 -1 ,(父节点是 -1 表示根节点);下一节点是 “ziyue”,以此类推。
复制树示例【核心】
step1:生成Id映射Map
/*** 生成Id映射Map** @param treeA 原树节点集合* @return 原树和新树Id映射Map*/
private static Map<String, String> getOldNewMap(List<TreeNode> treeA) {// 所有节点id集合List<String> nodeIdList = treeA.stream().map(TreeNode::getNodeId).collect(Collectors.toList());// 获取原树的跟节点idString rootId = treeA.stream().filter(item -> item.getNodePid().equals("-1")).collect(Collectors.toList()).get(0).getNodeId();// 新树跟节点newId期前指定// 根据实际情况调整String newId = "b1";Map<String, String> idMap = new HashMap<>(treeA.size());for (String nodeId : nodeIdList) {// 先找到根节点,(根节点的nodePid都是 -1)if (nodeId.equals(rootId)) {idMap.put(rootId, newId);} else {// 用 UUID 生成 新树和旧树的id映射关系// 根据实际id策略生成,为了方便此处使用UUIDidMap.put(nodeId, UUID.randomUUID().toString());}}return idMap;
}
step2:生成复制后的树结构
/*** 生成复制后的树结构* * @param treeA 原树节点集合* @param idMap 原树和新树Id映射Map,由 step1 生成* @return 改变id的树节点集合*/
private static List<TreeNode> getTreeB(List<TreeNode> treeA, Map<String, String> idMap) {List<TreeNode> treeB = new ArrayList<>(treeA.size());for (TreeNode treeNode : treeA) {String id = idMap.get(treeNode.getNodeId());// 可不判空,适用于根节点标记不是 nodePidif (null != id) {treeNode.setNodeId(id);}String pid = idMap.get(treeNode.getNodePid());// 跟节点标记在父ID,即 nodePid = -1// 跟节点的标志 nodePid = -1 不在映射中时不用重新复制,在 idMap 中也取不到,不用处理if (null != pid) {treeNode.setNodePid(pid);}treeB.add(treeNode);}return treeB;
}
新树结构

测试用例
@Test
public void testCopyTest() {// 获取原树节点集合List<TreeNode> treeA = TreeNode.createTreeA();System.out.println("treeA : " + treeA);// 生成原树和新树Id映射MapMap<String, String> idMap = getOldNewMap(treeA);// 获取复制后的树节点List<TreeNode> treeB = getTreeB(treeA, idMap);System.out.println("treeB : " + treeB);
}
后记:玄星幻月的第一篇完全是自己想的,遇到这个场景的时候也在网上搜过,但是没有找到类型的例子,也许用到的场景不是很多,但是感觉比较独特,就记录下来,若有更好的树复制方式,欢迎讨论,当然有其他比较有趣的例子,也可以共同探讨。(^_^)
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
