Subato

Baumimplementierung

package name.panitz.util.tree;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.function.*;

public class Tree<E> {
  final E element;
  final List<Tree<E>> children;
  private Tree<E> parent=null;
  
  
  public Tree<E> getParent() {
    return parent;
  }

  public void setParent(Tree<E> p) {
    if (null!=parent)throw new RuntimeException("Multiple assignment to parent node.");
    this.parent = p;
  }

  @SafeVarargs
  public Tree(E element, Tree<E>... children) {
    this.element = element;
    this.children = List.of(children);
    this.children.parallelStream().forEach(child->child.setParent(this));
  }

  public int size() {
    return
      children.parallelStream().reduce(0, (r,c)->c.size()+r,(x,y)->x+y)+1;
  }

  @Override
  public String toString() {
    return element.toString()+children.toString();
  }
  
  String toLaTeX() {
    var result = new StringBuffer();
    result.append("\\begin{tikzpicture}[sibling distance=10em,"
        + "every node/.style = {shape=rectangle, rounded corners,"
        + "draw, align=center,top color=white, bottom color=blue!20}]]");

    result.append("\\");
    toLaTeXAux(result);
    
    result.append(";\n");
    result.append("\\end{tikzpicture}");
    return result.toString();
  }

  void toLaTeXAux(StringBuffer result) {
    result.append("node {"+element+"}");
    children.stream().forEach(child -> {
      result.append("\n  child {");
      child.toLaTeXAux(result);
      result.append("}");
    });
  }

  String toXML() {
    var result = new StringBuffer();
    result.append("<?xml version=\"1.0\"?>\n");
    toXMLAux(result);
    return result.toString();
  }
  
  void toXMLAux(StringBuffer result) {
    result.append("<node> <element>"+element+"</element>");
    children.stream().forEach(child -> {
      result.append("\n  <child>");
      child.toXMLAux(result);
      result.append("</child>");
    });
    result.append("</node>");
  }
  
  List<Tree<E>> auntsAndUncles(){
    var opa = parent.parent;
    return opa.children.parallelStream().filter(c->c!=parent).collect(Collectors.toList());
  }
  
  List<E> cousins(){
    List<E> result = new ArrayList<>();
    if (parent==null||parent.parent==null) return result;
    auntsAndUncles()
    .stream()
    .forEach(cs -> cs.children.stream().forEach(c->result.add(c.element)));
    return result;
  }
  
  boolean enthält(E e) {
    if (element.equals(e)) return true;
    for (var child : children) {
      if (child.enthält(e)) return true;
    }
    return false;
  }
  boolean enthält2(E e) {
    return element.equals(e)
        ||children.parallelStream().reduce(false, (r,c)->r||c.enthält2(e),(x,y)->x||y);
  }
  
  public void forEach(Consumer<E> con) {
    con.accept(element);
    children.parallelStream().forEach(child -> child.forEach(con));
  }


  public boolean contains(Predicate<? super E> pred) {
    if (pred.test(element))
      return true;
    for (Tree<E> child : children) {
      if (child.contains(pred))
        return true;
    }
    return false;
  }
  
  public List<E> fringe() {
    var result = new ArrayList<E>();
    fringe(result);
    return result;
  }    
  public void fringe(List<E> result) {
    if (children.isEmpty())
      result.add(element);
    for (Tree<E> child : children) {
      child.fringe(result);
    }
  }

  public List<E> ancestors(){
    var result = new ArrayList<E>();
    ancestors(result);
    return result;
  }    
  public void ancestors(List<E> result){
    if (parent!=null){
      result.add(parent.element);
      parent.ancestors(result);
    }
  }

  public List<E> siblings(){
    var result = new ArrayList<E>();
    siblings(result);
    return result;
  }    
  public void siblings(List<E> result){
    if (parent!=null){
      parent.children.stream().filter(x->x!=this).forEach(x->result.add(x.element));
    }
  }

  
  public List<E> pathTo(E elem) {
    var result = new ArrayList<E>();
    pathTo(elem,result);
    return result;
  }    

  public void pathTo(E elem, List<E> result) {
    if (element.equals(elem)) {
      result.add(element);
      return;
    }
    for (Tree<E> child : children) {
      child.pathTo(elem, result);
      if (!result.isEmpty()) {
        result.add(0, element);
        return;
      }
    }
  }

  public <R> Tree<R> map(Function<? super E, ? extends R> f) {
    return  new Tree<R>
      (f.apply(element)
      ,children
         .stream()
         .map(child->child.map(f))
         .toArray(size -> (Tree<R>[])new Tree[size]));
  }
    
}