All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.qudtlib.tools.contribute.support.tree.Node Maven / Gradle / Ivy

There is a newer version: 6.8.0
Show newest version
package io.github.qudtlib.tools.contribute.support.tree;

import java.util.*;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Node {
    private T data;
    private List> children = new ArrayList<>();

    public Node(T data) {
        this.data = data;
    }

    public Node addChild(T child) {
        Node newNode = new Node(child);
        this.children.add(newNode);
        return newNode;
    }

    public Node addChild(Node child) {
        this.children.add(child);
        return child;
    }

    public int size() {
        return this.children.stream().mapToInt(Node::size).sum() + 1;
    }

    @Override
    public String toString() {
        return "[" + data + "" + (children.isEmpty() ? "" : children) + "]";
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Node)) return false;
        Node node = (Node) o;
        return Objects.equals(getData(), node.getData())
                && Objects.equals(getChildren(), node.getChildren());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getData(), getChildren());
    }

    public T getData() {
        return data;
    }

    public List> getChildren() {
        return children;
    }

    public Optional> findFirst(Function predicate) {
        if (predicate.apply(this.data)) {
            return Optional.of(this);
        }
        for (Node child : this.children) {
            Optional> result = child.findFirst(predicate);
            if (result.isPresent()) {
                return result;
            }
        }
        return Optional.empty();
    }

    public boolean hasChildren() {
        return this.children != null && !this.children.isEmpty();
    }

    public static  Optional> insert(
            Node root, Node other, BiPredicate isParentOf) {
        if (isParentOf.test(other.getData(), root.getData())) {
            other.addChild(root);
            return Optional.of(other);
        } else if (isParentOf.test(root.getData(), other.getData())) {
            root.addChild(other);
            return Optional.of(root);
        }
        List> newChildren = new ArrayList<>();
        boolean insertDone = false;
        for (Node childNode : root.children) {
            if (!insertDone) {
                Optional> result = insert(childNode, other, isParentOf);
                if (result.isPresent()) {
                    insertDone = true;
                    newChildren.add(result.get());
                } else {
                    newChildren.add(childNode);
                }
            } else {
                newChildren.add(childNode);
            }
        }
        if (insertDone) {
            root.children = newChildren;
            return Optional.of(root);
        }
        return Optional.empty();
    }

    public static  List> forestOf(Collection items, BiPredicate isParentOf) {
        List> roots = items.stream().map(i -> new Node<>(i)).collect(Collectors.toList());
        int numRoots = Integer.MAX_VALUE;
        boolean finished = false;
        while (!finished) {
            finished = true;
            outer:
            for (int i = 0; i < roots.size() - 1; i++) {
                for (int j = i + 1; j < roots.size(); j++) {
                    Optional> combined =
                            Node.insert(roots.get(i), roots.get(j), isParentOf);
                    if (combined.isPresent()) {
                        roots.remove(j);
                        roots.remove(i);
                        roots.add(combined.get());
                        finished = false;
                        break outer;
                    }
                }
            }
        }
        return roots;
    }

    public static  Builder builder(T item) {
        return new Builder<>(item);
    }

    public int getChildrenCount() {
        return this.children == null ? 0 : this.children.size();
    }

    public static class Builder {
        private Node root;
        private ArrayDeque> pathToCurrent = new ArrayDeque<>();

        Builder(T root) {
            this.root = new Node(root);
            pathToCurrent.push(this.root);
        }

        public Builder leaf(T item) {
            this.pathToCurrent.peek().addChild(item);
            return this;
        }

        public Builder inner(T item) {
            Node inner = new Node<>(item);
            this.pathToCurrent.peek().addChild(inner);
            this.pathToCurrent.push(inner);
            return this;
        }

        public Builder up() {
            this.pathToCurrent.pop();
            return this;
        }

        public Node build() {
            return root;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy