结构图
构建原理:
每新增一个newNode,则查看newNode是否是node节点(根节点)下某个child节点(node节点的List中的节点)的父节点,如果是,则移除这个节点child,并把这个节点child作为newNode的子节点。遍历完整个node节点的子节点集合(list)之后,把newNode节点插入到node中,设置父节点结束(由于newNode节点类似于一种吞并的方式,所以最后插入的到list的时候可能是无序的)。子节点采用递归的方式,依次对node下的每一个节点比较,满足newNode是某个节点的子节点,那么从node中移除newNode,并把newNode设置为这个节点的子节点,由于每个节点只有唯一一个父节点,一旦设置成功则退出,设置完毕。详细逻辑看源码。
由于构建的过程中涉及到节点的移动、增加、删除,所以是同级节点是无序的,后面源码有介绍排序方法。
1.依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2.TreeNode
package com.example.datastucture.node.orgNode;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Setter
@Getter
@NoArgsConstructor
public class TreeNode<T> implements Serializable,Cloneable{
private static final long serialVersionUID = -8685446899650372456L;
private String id;
private String pid;
private String name;
private T t;
private ArrayList<TreeNode<T>> children = new ArrayList<>();
public TreeNode(String id, String pid, String name, T t) {
this.id = id;
this.pid = pid;
this.name = name;
this.t = t;
}
/**
* 这个clone方法只能拷贝当前对象和下一级children,children下面的TreeNode没法深拷贝,泛型也没法深拷贝。后续想办法
* @return
*/
@Override
public TreeNode<T> clone(){
TreeNode<T> treeNode = null;
try {
treeNode = (TreeNode<T>) super.clone();
treeNode.children = (ArrayList<TreeNode<T>>) children.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return treeNode;
}
}
3.TreeBuilder
可直接调用的方法为了防止出现多线程并发的问题,所以设计成线程安全的实现。
package com.example.datastucture.node.orgNode;
import org.springframework.beans.BeanUtils;
import javax.validation.constraints.NotNull;
import java.util.*;
/**
* 线程安全的构建节点树
*/
public class TreeBuilder<T> {
private TreeNode<T> node;
private transient TreeNode<T> temp;
public synchronized void add(@NotNull final TreeNode<T> newNode) {
if (node == null) {
node = new TreeNode<T>();
}
if (node.getChildren() == null) {
node.setChildren(new ArrayList<>());
}
final TreeNode<T> currentNode = node;
setNode(newNode, currentNode);
}
/**
* 设置子节点
* 这个依赖于父节点方法的设置,由父节点设置的原理,
* 可以得出:当前节点(newNode)如果在node下的所有节点中存在一个父节点,那么这个父节点有且仅有一个。
* 因此采用递归的方式设置子节