利用hashMap实现基于索引的多叉树

101 阅读2分钟

需求背景

公司要求实现利用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;
    }
}