一般我们存储树形数据,如菜单等等存在子父级关系的,会使用每条数据都存储父节点id的方法。
最近接触到一个更好的方法,一般数据的每条唯一主键较长,且只存储父节点id,要找到祖父节点等更高的节点,会需要重复遍历,找起来相对麻烦。
我们可以对每条数据都加几个字段,一个为层级,从1开始,每下一个节点递增1,一个为行次,每个层级均从1开始,同层级每一条数据递增1,再一个为长编码(longNumber),为层级和行次的组合,"|"连接,去掉父节点id字段。
就例如:
11
|—11|21
|—11|22
|——11|22|31
12
|—12|21
|——12|21|31
|—12|22
这个结构其中一个优点就是,可直接用Map作为存储容器,key为长编码,value为节点对象,而非原来的那种节点对象的无限自身引用(套娃)。
对这种树形数据的一些方法:
/**
* 遍历树节点
*
* @param treeMap 树节点map集
* @author ***
* @createDate 2021/05/14
*/
public static void traverTree(Map<String, TestPO> treeMap) {
// 按长编码顺序依次遍历数据
int partLevel = 0; // 初始化层级,层级入库从0开始,但是展示从1开始
String longNumber = partLevel + 1 + "" + 1; // 初始化长编码
do {
for (; ; ) {
TestPO po = treeMap.get(longNumber);
if (po != null) {
{
// 拿到节点,doSomething()
}
// 不为空,继续往下层级,层级+1
longNumber = longNumber + '|' + (++partLevel + 1) + 1;
} else {
// 为空,则往回退,退到上一级后上一级的节点行次+1,但是注意,层级为1时不能再退,直接结束当前循环
if (longNumber.contains("|")) {
partLevel--;
longNumber = longNumber.substrin