import java.util.List;
/**
* 树形结构基础类
* @param
*/
public interface BaseTree<T> {
String getId();
void setId(String id);
String getPid();
void setPid(String pid);
List<T> getChildren();
void setChildren(List<T> children);
}
package com.zm.decorator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 树形结构工具类
* T 实现了BaseTree接口的实体对象,实体对象中默认有表示父子关系的id和pid
* N id和pid的类型
* 由于 实体对象中表示父子关系的属性名称不一定是id和pid,所以提供了getId和getPid方法进行拓展
*/
public abstract class TreeUtil<T extends BaseTree<T>, N> {
/**
* id的get方法
*
* @param t 对象
* @return id 的值
*/
protected abstract N getId(T t);
/**
* 父级id的get方法
*
* @param t 对象
* @return pid 的值
*/
protected abstract N getPid(T t);
/**
* 格式化成树形结构
* 要点:非基本类型的变量存储的是内存地址,对它的操作会影响到原始值。
*
* @param list 要操作的列表
* @return 树形结果列表
*/
public List<T> parseTree(List<T> list) {
if(list.isEmpty()){
return list;
}
List<T> resultList = new ArrayList<>();
// 知道有多少个元素,那么在创建的时候直接指定长度,避免因扩容而浪费时间
Map<N, T> tmpMap = new HashMap<>(list.size());
for (T t : list) {
tmpMap.put(this.getId(t), t);
}
for (T t : list) {
/*1、tmpMap存储的是以id为key的键值对。
2、如果以pid为key可以从tmpMap中取出对象,则说明该元素是子级元素。
3、如果以pid为key不能从tmpMap中取出对象,则说明该元素是最上层元素。
4、子级元素放在父级元素的children中。
5、最上层元素添加到结果中
*/
T tmap = tmpMap.get(this.getPid(t));
if (tmap != null) {
if (null == tmap.getChildren()) {
tmap.setChildren(new ArrayList<>());
}
tmap.getChildren().add(t);
} else {
resultList.add(t);
}
}
// 如果集合中存储了大量的元素,并且集合已经使用完毕,那么尽量调用clear方法来及时的释放空间。
// 如果集合不会重复使用,那么将集合也设置为null将内存一并释放。这样有助于gc能更快完成清除内存的工作。
list.clear();
list = null;
return resultList;
}
}
import java.util.List;
public class TestNode implements BaseTree<TestNode>{
private List<TestNode> children;
private String id;
private String pid;
private String name;
@Override
public List<TestNode> getChildren() {
return children;
}
@Override
public void setChildren(List<TestNode> children) {
this.children = children;
}
@Override
public String getId() {
return id;
}
@Override
public void setId(String id) {
this.id = id;
}
@Override
public String getPid() {
return pid;
}
@Override
public void setPid(String pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) {
ArrayList<TestNode> objects = getTestNodes();
test1(objects);
}
private static void test1(ArrayList<TestNode> objects) {
TreeUtil<TestNode, String> treeUtil = new TreeUtil<TestNode, String>() {
@Override
protected String getId(TestNode e) {
return e.getId();
}
@Override
protected String getPid(TestNode e) {
return e.getPid();
}
};
List<TestNode> testNodes = treeUtil.parseTree(objects);
System.out.println(testNodes);
}
private static ArrayList<TestNode> getTestNodes() {
TestNode testNode1 = new TestNode();
testNode1.setName("中国");
testNode1.setId("0");
TestNode testNode2 = new TestNode();
testNode2.setName("福建省");
testNode2.setId("1");
testNode2.setPid("0");
TestNode testNode3 = new TestNode();
testNode3.setName("浙江省");
testNode3.setId("2");
testNode3.setPid("0");
TestNode testNode4 = new TestNode();
testNode4.setName("福州市");
testNode4.setId("3");
testNode4.setPid("1");
TestNode testNode5 = new TestNode();
testNode5.setName("宁德市");
testNode5.setId("4");
testNode5.setPid("1");
ArrayList<TestNode> objects = new ArrayList<>();
objects.add(testNode1);
objects.add(testNode2);
objects.add(testNode3);
objects.add(testNode4);
objects.add(testNode5);
return objects;
}
import java.util.List;
/**
* 树形结构基础类
*
* @param
* @author zhou
*/
public interface BaseTree<T> {
/**
* 获取id
*
* @return
*/
String getId();
/**
* 获取父id
*
* @return
*/
String getPid();
/**
* 获取子集合
*
* @return
*/
List<T> getChildren();
/**
* 赋子集合
*
* @return
*/
void setChildren(List<T> children);
}
import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* 树形结构工具类
* T 实现了BaseTree接口的实体对象,实体对象中默认有表示父子关系的id和pid
* N id和pid的类型
* 由于 实体对象中表示父子关系的属性名称不一定是id和pid,所以提供了getId和getPid方法进行拓展
*
* @author zhou
*/
public class TreeUtil {
/**
* 格式化成树形结构 JDK1.8以下版本
* 要点:非基本类型的变量存储的是内存地址,对它的操作会影响到原始值。
*
* @param list 要操作的列表
* @return 树形结果列表
*/
public static <T extends BaseTree<T>> List<T> parseTree(List<T> list) {
if (list.isEmpty()) {
return list;
}
List<T> resultList = new ArrayList<>();
// 知道有多少个元素,那么在创建的时候直接指定长度,避免因扩容而浪费时间
Map<String, T> tmpMap = new HashMap<>(list.size());
for (T t : list) {
tmpMap.put(t.getId(), t);
}
for (T t : list) {
/*1、tmpMap存储的是以id为key的键值对。
2、如果以pid为key可以从tmpMap中取出对象,则说明该元素是子级元素。
3、如果以pid为key不能从tmpMap中取出对象,则说明该元素是最上层元素。
4、子级元素放在父级元素的children中。
5、最上层元素添加到结果中
*/
T tmap = tmpMap.get(t.getPid());
if (tmap != null) {
if (null == tmap.getChildren()) {
tmap.setChildren(new ArrayList<>());
}
tmap.getChildren().add(t);
} else {
resultList.add(t);
}
}
// 如果集合中存储了大量的元素,并且集合已经使用完毕,那么尽量调用clear方法来及时的释放空间。
// 如果集合不会重复使用,那么将集合也设置为null将内存一并释放。这样有助于gc能更快完成清除内存的工作。
list.clear();
list = null;
return resultList;
}
}
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class TestNode implements BaseTree<TestNode>{
private List<TestNode> children;
private String iid;
private String ipid;
private String name;
@Override
public String getId() {
return iid;
}
@Override
public String getPid() {
return ipid;
}
public static void main(String[] args) {
ArrayList<TestNode> objects = getTestNodes();
List<TestNode> testNodes = TreeUtil.parseTree(objects);
System.out.println(testNodes);
}
private static ArrayList<TestNode> getTestNodes() {
TestNode testNode1 = new TestNode();
testNode1.setName("中国");
testNode1.setIid("0");
TestNode testNode2 = new TestNode();
testNode2.setName("福建省");
testNode2.setIid("1");
testNode2.setIpid("0");
TestNode testNode3 = new TestNode();
testNode3.setName("浙江省");
testNode3.setIid("2");
testNode3.setIpid("0");
TestNode testNode4 = new TestNode();
testNode4.setName("福州市");
testNode4.setIid("3");
testNode4.setIpid("1");
TestNode testNode5 = new TestNode();
testNode5.setName("宁德市");
testNode5.setIid("4");
testNode5.setIpid("1");
ArrayList<TestNode> objects = new ArrayList<>();
objects.add(testNode1);
objects.add(testNode2);
objects.add(testNode3);
objects.add(testNode4);
objects.add(testNode5);
return objects;
}
}
静态工具类使用起来超级简单了