Java 树容器
开发过程中遇到了一些问题
- 业务对象关系为多叉树结构,经常要求查询子节点信息,进行子节点遍历,子节点条件过滤等等
- 要求快速统计子节点数量
开发过程中图快,以冗余查询数据库的方式应付了过去,但终究不美
于是业余时间编写了一个简单的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;
}
}
}
}