需求背景
公司要求实现利用VIN码到车型库的映射即输入Vin码 查询出车辆的品牌车型车系,
树特点
1.同级内索引唯一.
2.子节点集基于hashMap 子节点集数据量大时查询效率高.
3.和所有树一样要在数据库维护层级关系 遍历插入效率低下.(叶子节点可用批量插入)
多叉树代码:
package com.dsj.api;
import com.alibaba.fastjson.annotation.JSONField;
import com.google.common.collect.Lists;
import java.util.*;
/**
*
*
* @author : Duanshaojie
* @ClassName: HashHashTreeNode
* @date 2022-09-13-10:20
* @description :
*/
public class HashTreeNode<T> {
/**
* 索引
*/
private String index;
/**
* 父级节点
* 去掉这个索引就不要使用toJsonString
* 此处采用双向指针 容易引起堆栈溢出
*/
@JSONField(serialize = false)
private HashTreeNode parentNode;
/**
* 节点数据
*/
private T data;
/**
* 子节点
*/
private HashMap<String, HashTreeNode<T>> sonNodes = new HashMap<>();
/**
* 获取索引
*
* @return java.lang.String
* @author duanshaojie
* @date 2022/09/13 10:29
*/
public String getIndex() {
return index;
}
/**
* 设置索引 这里需要将父节点子节点集复制变更
*
* @param index
* @return void
* @author duanshaojie
* @date 2022/09/13 10:29
*/
public void setIndex(String index) {
//为空且索引不变||不为空切索引不变 这种情况无需变更节点结构
if ((Objects.isNull(index) && this.index == index) || (Objects.nonNull(this.index) && this.index.equals(index))) {
return;
} else {
this.parentNode.sonNodes.put(index, this);
this.parentNode.sonNodes.remove(index);
}
this.index = index;
}
/**
* 获取父节点
*
* @return
*/
public HashTreeNode getParentNode() {
return parentNode;
}
/**
* 设置父级节点
*
* @param parentNode
* @return void
* @description 如果父级节点变更 删除原有父级节点子节点 指定父节点增加子节点
* @author duanshaojie
* @date 2022/09/13 10:40
*/
public void setParentNode(HashTreeNode parentNode) {
if (this.parentNode == parentNode) {
return;
} else {
this.parentNode.sonNodes.remove(this.index);
parentNode.putSon(this.index, this.data);
}
}
/**
* 获取当前节点根节点
*
* @return com.dsj.api.HashTreeNode
* @author duanshaojie
* @date 2022/09/13 10:46
*/
public HashTreeNode<T> getRootNode() {
return getRootNode(this);
}
/**
* 获取指定节点根节点
*
* @param hashTreeNode
* @return com.dsj.api.HashTreeNode
* @author duanshaojie
* @date 2022/09/13 10:46
*/
private HashTreeNode<T> getRootNode(HashTreeNode<T> hashTreeNode) {
if (Objects.isNull(hashTreeNode) || Objects.isNull(hashTreeNode.getParentNode())) {
return hashTreeNode;
} else {
return getRootNode(hashTreeNode.parentNode);
}
}
/**
* 判断当前节点是否根节点
*
* @return
*/
public boolean isRootNode() {
return Objects.isNull(parentNode);
}
/**
* 判断指定节点是否根节点
*
* @return
*/
public boolean isRootNode(HashTreeNode hashTreeNode) {
return Objects.nonNull(hashTreeNode) && Objects.isNull(hashTreeNode.getParentNode());
}
/**
* 根据索引获取当前节点子节点
*
* @param index
* @return
*/
public HashTreeNode<T> getSonByIndex(String index) {
return sonNodes.get(index);
}
/**
* 指定节点是否包含子节点
*
* @param index 索引
* @param hashTreeNode 节点
* @return boolean
* @author duanshaojie
* @date 2022/09/13 10:50
*/
public boolean containsSonByIndex(String index, HashTreeNode hashTreeNode) {
return Objects.nonNull(hashTreeNode) && hashTreeNode.sonNodes.containsKey(index);
}
/**
* 当前节点是否包含子节点
*
* @param index 索引
* @return boolean
* @author duanshaojie
* @date 2022/09/13 10:52
*/
public boolean containsSonByIndex(String index) {
return this.sonNodes.containsKey(index);
}
/**
* 当前节点放置子节点
*
* @param index 索引
* @param data 数据
* @return com.dsj.api.HashTreeNode
* @author duanshaojie
* @date 2022/09/13 10:52
*/
public HashTreeNode putSon(String index, T data) {
HashTreeNode sonNode = new HashTreeNode();
sonNode.setParentNode(this);
sonNode.setIndex(index);
sonNode.setData(data);
sonNodes.put(index, sonNode);
return sonNode;
}
/**
* 当前节点是否叶子节点
*
* @return boolean
* @author duanshaojie
* @date 2022/09/13 10:53
*/
public boolean isLeafNode() {
return sonNodes.size() == 0;
}
/**
* 获取子节点集合
*
* @return java.util.List<com.dsj.api.HashTreeNode < T>>
* @author duanshaojie
* @date 2022/09/13 10:53
*/
public List<HashTreeNode<T>> getSonNodeList() {
return Lists.newArrayList(this.sonNodes.values());
}
/**
* 获取所有子节点
*
* @return java.util.List<com.dsj.api.HashTreeNode < T>>
* @author duanshaojie
* @date 2022/09/13 11:06
*/
public List<HashTreeNode<T>> getALLSonNode() {
return getAllSonNode(this);
}
/**
* 获取所有指定节点的子节点(递归调用)
*
* @param hashTreeNode
* @return java.util.List<com.dsj.api.HashTreeNode < T>>
* @author duanshaojie
* @date 2022/09/13 11:06
*/
private List<HashTreeNode<T>> getAllSonNode(HashTreeNode hashTreeNode) {
if (Objects.isNull(hashTreeNode)) {
return Collections.emptyList();
}
List<HashTreeNode<T>> dataList = new ArrayList<>();
dataList.addAll(sonNodes.values());
for (HashTreeNode sonNode : sonNodes.values()) {
dataList.addAll(getAllSonNode(sonNode));
}
return dataList;
}
/**
* 获取当前节点数据
*
* @return T
* @author duanshaojie
* @date 2022/09/13 11:07
*/
public T getData() {
return this.data;
}
/**
* 设置当前节点数据
*
* @param data
* @return void
* @author duanshaojie
* @date 2022/09/13 11:07
*/
public void setData(T data) {
this.data = data;
}
}