Java 树容器

文章介绍了一个用于处理业务对象的多叉树结构的Java树容器实现,该容器支持快速查询子节点、遍历、过滤等功能。为了提高性能,作者使用了读写锁确保线程安全,并提供了插入、删除、更新节点的方法,以及统计子节点数量和获取子树的能力。代码设计为非平衡树,强调了泛型类的hash不可变性的重要性。
摘要由CSDN通过智能技术生成

Java 树容器

开发过程中遇到了一些问题

  1. 业务对象关系为多叉树结构,经常要求查询子节点信息,进行子节点遍历,子节点条件过滤等等
  2. 要求快速统计子节点数量

开发过程中图快,以冗余查询数据库的方式应付了过去,但终究不美
于是业余时间编写了一个简单的Java树容器
敢不敢用不知道,图一乐绝对是够了
现在放上代码的test版


import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * @author xiaoxiu liu
 * @Description: 树
 * @date 2023/1/18
 */
public interface Tree<V> {

    //******************************************************************************************************

    /**
     * 是否为空,root不算,子树root算
     * @return
     */
    boolean isEmpty();

    /**
     * 是否存在该节点
     * @param node
     * @return
     */
    boolean has(V node);

    /**
     * 统计元素的数量
     * @return
     */
    long size();

    /**
     * 统计该元素为子树的元素数量
     * @return
     */
    long size(V node);

    /**
     * 获得子树
     * @param node
     * @return
     */
    Tree<V> getSubtree(V node);
    /**
     * 获得树中之前存入的相等的元素
     * @param node
     * @return
     */
    V get(V node);

    /**
     * 获得父节点
     * @param node
     * @return
     */
    V parent(V node);

    /**
     * 获得某个节点的儿子节点列表,如果想获得所有子节点用filter方法
     * @param node
     * @return
     */
    List<V> children(V node);

    /**
     * 返回该节点在子树中的高度
     * @return
     */
    int height(V node);

    //******************************************************************************************************
    //插入类的方法
    /**
     * 在根节点下添加元素列表
     * @param node
     */
    void add(List<V> node);
    /**
     * 在根节点下添加元素
     * @param node
     */
    void add(V node);

    /**
     * 在指定节点下插入一个元素
     * @param parent
     * @param node
     */
    void add(V parent,V node);

    /**
     * 在指定节点下插入一个元素列表
     * @param parent
     * @param node
     */
    void add(V parent, List<V> node);


    /**
     * 清空树,仅保留root节点
     */
    void clear();

    /**
     * 替换某个元素。不影响它和其他节点的关系
     * @param node
     * @return
     */
    V update(V node);

    /**
     * 转移子树,将一个节点转为其他节点的子节点
     * @param parent
     * @param node
     * @return 原本的parent下
     */
    void update(V parent,V node);

    /**
     * 删除该节点(包括子节点)
     * @param node
     * @return
     */
    void delete(V node);

    List<V> filter(Predicate<V> filter);


    void foreach(Consumer<V> consumer);
}



import java.util.*;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @Description: 业务树,节点之间关系靠自身业务维护,使用请重写bean的hashcode和equals方法
 * 请注意,因为采用可变对象作为hash的key,所以可能导致数据丢失,请自行保证泛型类的hash不可变性!
 * 线程安全的
 * 读写锁的
 * 非平衡树
 * 空间复杂度为2n
 * 时间复杂度不定,理想情况为常量级
 * @author xiaoxiu liu
 * @date 2023/1/18
 * @version jdk1.8
 */
public class BusinessHashTree<V> implements Tree<V>{


    private Node<V> root;
    private Map<V,Node<V>> map;
    private ReadWriteLock lock;

    public BusinessHashTree(){
        this.root=new Node<V>();
        this.map=new HashMap<V,Node<V>>();
        this.lock=new ReentrantReadWriteLock();
    }
    private BusinessHashTree(Node<V> root, Map<V,Node<V>> map, ReadWriteLock lock){
        this.root=root;
        this.map=new HashMap<V,Node<V>>();
        this.lock=new ReentrantReadWriteLock();
    }
    @Override
    public boolean isEmpty() {
        lock.readLock().lock();
        try {
            return root.count==0;
        }finally {
            lock.readLock().unlock();
        }
    }


    public boolean has(V node) {
        if (node==null)return false;
        lock.readLock().lock();
        try {
            return map.containsKey(node);
        }finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public long size() {
        lock.readLock().lock();
        try {
            return root.count;
        }finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public long size(V node) {
        lock.readLock().lock();
        try {
            if (has(node)){
                return map.get(node).count;
            }else {
                return -1;
            }
        }finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public Tree<V> getSubtree(V node) {
        lock.readLock().lock();
        try {
            if (node==null||!has(node))throw new IllegalArgumentException("该值为空或不存在");
            Node<V> tNode = map.get(node);
            Tree<V> businessTree = new BusinessHashTree(tNode,this.map,this.lock);
            return businessTree;
        }catch (Exception e){
            throw e;
        }finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public V get(V node) {
        lock.readLock().lock();
        try {
            if (has(node)){
                return map.get(node).data;
            }
            return null;
        }finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public V parent(V node){
        lock.readLock().lock();
        try {
            if (has(node)) {
                Node<V> n = map.get(node);
                return n.parent.data;
            }
            return null;
        }finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public List<V> children(V node) {
        lock.readLock().lock();
        try {
            if (node==null){
                if (root.children!=null){
                    return root.children.stream().map(Node::getData).collect(Collectors.toList());
                }
            }
            if (has(node)) {
                Node<V> n=map.get(node);
                if (n.children!=null){
                    return n.children.stream().map(Node::getData).collect(Collectors.toList());
                }
            }
            return null;
        }finally {
            lock.readLock().unlock();
        }
    }


    @Override
    public int height(V v) {
        lock.readLock().lock();
        try {
            if (has(v)){
                Node<V> node = map.get(v);
                int count=0;
                while (node!=root&&node!=null){
                    node=node.parent;
                    count++;
                }
                return count;
            }
            return -1;
        }finally {
            lock.readLock().unlock();
        }

    }


    @Override
    public void clear() {
        lock.writeLock().lock();
        try {
            if (root.children!=null){
                foreach(e->map.remove(e));
                Iterator<Node<V>> iterator = root.children.iterator();
                while (iterator.hasNext()){
                    Node<V> next = iterator.next();
                    next.parent=null;
                }
                root.children=null;
                if (root.parent!=null){
                    long count = root.count-1;
                    root.count-=count;
                    if (count!=0)
                    parentForeach(root,e->e.offset(-count));
                }else {
                    root.count=0;
                }

            }
        }finally {
            lock.writeLock().unlock();
        }
    }

    @Override
    public List<V> filter(Predicate<V> filter) {
        List<V> res=new ArrayList<>();
        lock.readLock().lock();
        Stack<Iterator<Node<V>>> stack=new Stack<>();
        try {
            if (root.parent!=null&&filter.test(root.data)){
                res.add(root.data);
            }
            if (root.children!=null){
                stack.push(root.children.iterator());
                while (stack.size()!=0){
                    Iterator<Node<V>> pop = stack.pop();
                    if (pop.hasNext()){
                        stack.push(pop);
                        Node<V> next = pop.next();
                        if (filter.test(next.data))res.add(next.data);
                        if (next.children!=null)stack.push(next.children.iterator());
                    }
                }
            }
            return res;
        }finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public void foreach(Consumer<V> consumer) {
        lock.readLock().lock();
        Stack<Iterator<Node<V>>> stack=new Stack<>();
        try {
            if (root.parent!=null&&root.data!=null){
                consumer.accept(root.data);
            }
            if (root.children!=null){
                stack.push(root.children.iterator());
                while (stack.size()!=0){
                    Iterator<Node<V>> pop = stack.pop();
                    if (pop.hasNext()){
                        stack.push(pop);
                        Node<V> next = pop.next();
                        consumer.accept(next.data);
                        if (next.children!=null)stack.push(next.children.iterator());
                    }
                }
            }
        }finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public void delete(V node) {
        lock.writeLock().lock();
        try {
            if (has(node)){
                Node<V> n = map.get(node);
                parentForeach(n,e->e.offset(-n.count));
                if (n.parent!=null)n.parent.deleteChild(n);
                map.remove(node);
            }
        }finally {
            lock.writeLock().unlock();
        }
    }

    @Override
    public V update(V node) {
        lock.writeLock().lock();
        try {
            if (has(node)){
                Node<V> n = map.get(node);
                V data = n.data;
                n.data=node;
                return data;
            }
            return null;
        }finally {
            lock.writeLock().unlock();
        }
    }

    @Override
    public void update(V parent, V node) {
        lock.writeLock().lock();
        try {
            if (updateCheck(parent,node)){
                Node<V> pn = map.get(parent);
                Tree<V> tree = new BusinessHashTree<V>(pn,map,lock);
                tree.clear();
                if (has(node)){
                    Node<V> n = map.get(node);
                    parentForeach(n,e->e.offset(-n.count));
                    pn.children.add(n);
                    n.parent=pn;
                    parentForeach(n,e->e.offset(n.count));
                }else {
                    add(parent,node);
                }
            }else {
                throw new IllegalArgumentException("未通过修改检查!");
            }
        }finally {
            lock.writeLock().unlock();
        }
    }


    protected void parentForeach(Node<V> node,Consumer<Node<V>> consumer){
        while (node!=null){
            node=node.parent;
            if (node!=null){
                consumer.accept(node);
            }
        }
    }
    @Override
    public void add(V node) {
        lock.writeLock().lock();
        try {
            if (insertCheck(node)){
                Node<V> n = root.addChild(node);
                map.put(node,n);
                parentForeach(n,e->e.offset(1));
            }
        }finally {
            lock.writeLock().unlock();
        }
    }

    @Override
    public void add(V parent, V node) {
        if (parent==null||node==null)throw new IllegalArgumentException("参数不能为空");
        lock.writeLock().lock();
        try {
            if (!has(parent))throw new IllegalArgumentException("父节点不存在!");
            if (insertCheck(node)){
                Node<V> n = map.get(parent);
                Node<V> child = n.addChild(node);
                map.put(node,child);
                parentForeach(child,e->e.offset(1));
            }
        }finally {
            lock.writeLock().unlock();
        }
    }

    @Override
    public void add(V parent, List<V> node) {
        lock.writeLock().lock();
        try {
            if (node!=null&&node.size()!=0){
                node.stream().filter(Objects::nonNull).forEach(e->add(parent,e));
            }
        }finally {
            lock.writeLock().unlock();
        }
    }

    @Override
    public void add(List<V> node) {
        lock.writeLock().lock();
        try {
            if (node!=null&&node.size()!=0){
                node.stream().filter(Objects::nonNull).forEach(this::add);
            }
        }finally {
            lock.writeLock().unlock();
        }
    }



    protected boolean insertCheck(V node){
        if(node==null)return false;
        if (has(node))throw new IllegalArgumentException("未通过检查,请检查该节点是否已存在树中!");
        return true;
    }

    protected boolean updateCheck(V parent, V node){
        if (node==null||parent==null)return false;
        if (!has(parent))return false;
        Node<V> parentNode = map.get(parent);
        Node<V> n = map.get(node);
        if (has(node)){
            while (parentNode!=null||parentNode.equals(n)){
                parentNode=parentNode.parent;
            }
            if (parentNode!=null){
                return false;
            }
        }
        return true;
    }


    protected class Node<V>{
        private Node<V> parent;
        private V data;
        private List<Node<V>> children;
        private long count;

        protected Node(){}
        protected Node(V data){this.data=data;}
        protected Node(V data,long count){this.data=data;this.count=count;}

        public void offset(long count){
            this.count+=count;
        }

        public Node<V> addChild(V node){
            if (node==null)return null;
            if (children==null){
                children=new ArrayList<>();
            }
            Node<V> n = new Node<>(node,1);
            n.parent=this;
            children.add(n);
            return n;
        }

        public void deleteChild(V node){
            if (node==null||this.children==null)return;
            for (int i = 0; i < children.size(); i++) {
                Node<V> n = children.get(i);
                if (n.data.equals(node)){
                    this.children.remove(i);
                    n.parent=null;
                }
            }
        }

        public V getData() {
            return data;
        }

        public void setData(V data) {
            this.data = data;
        }

        public void deleteChild(Node<V> node){
            if (node==null||this.children==null)return;
            if (this.children.contains(node)){
                this.children.remove(node);
                node.parent=null;
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值