Общая реализация дерева в Java

Кто-нибудь знает о реализации общего дерева (узлы могут иметь несколько дочерних элементов) для Java? Он должен исходить из надежного источника и должен быть полностью протестирован.

Просто кажется неправильным реализовывать это самостоятельно. Почти напоминает мне мои университетские годы, когда мы должны были сами писать все наши сборники.

EDIT: найден этот проект на java.net, возможно, стоит изучить.


person Ivan Koblik    schedule 31.08.2009    source источник
comment
Как вы хотите использовать это дерево?   -  person pjp    schedule 31.08.2009
comment
т. е. вы сами определяете структуру (например, генеалогическое древо) или элементы сопоставимы, и вы хотите эффективно вставить их в дерево?   -  person pjp    schedule 31.08.2009
comment
Каждый узел должен иметь возможность вести список дочерних узлов в порядке вставки. Мне нужно сделать что-то вроде обхода postorder (en.wikipedia.org/wiki/ Tree_traversal), обход дочерних элементов узла в обратном направлении.   -  person Ivan Koblik    schedule 31.08.2009
comment
Для обхода дерева вы можете взглянуть на Guava TreeTraverser   -  person Vitalii Fedorenko    schedule 12.08.2013


Ответы (10)


Вот оно:

abstract class TreeNode implements Iterable<TreeNode> {

  private Set<TreeNode> children;

  public TreeNode() {
    children = new HashSet<TreeNode>();
  }

  public boolean addChild(TreeNode n) {
    return children.add(n);
  }

  public boolean removeChild(TreeNode n) {
    return children.remove(n);
  }

  public Iterator<TreeNode> iterator() {
    return children.iterator();
  }
}

Мне доверяют, но я не проверял реализацию.

person Zed    schedule 31.08.2009
comment
Просто убедитесь, что TreeNode правильно реализует equals и hashCode. - person pjp; 31.08.2009
comment
Спасибо, но мне нужно что-то хорошо протестированное, иначе мне пришлось бы потратить пару часов на написание юнит-тестов самому... - person Ivan Koblik; 31.08.2009
comment
Как вы точно получаете доступ к дочерним элементам TreeNode? :П - person Martin OConnor; 31.08.2009
comment
@Ivan Похоже, вам все равно придется писать модульные тесты, чтобы проверить правильность ваших предположений о хорошо протестированном коде, который вы ищете. - person Martin OConnor; 31.08.2009
comment
@Мартин, вот что делает его таким безопасным! - person Zed; 31.08.2009
comment
@Martin Наверняка будут клиентские тесты, но я не хочу писать тесты для коллекции (например, убедиться, что он выполняет нулевые проверки ...) - person Ivan Koblik; 31.08.2009
comment
equals и hashCode являются необязательными и основаны на том, как вы определяете равенство. Вы не должны переопределять их, если вам это не нужно. - person Steve Kuo; 31.08.2009
comment
+1 только за I am well trusted, but haven't tested the implementation. :) - person Vaishak Suresh; 20.11.2012
comment
отсутствует общая часть - person cdalxndr; 03.07.2021

В библиотеках коллекций нет класса Tree. Однако в Swing Frameworks он есть. DefaultTreeModel

Я использовал это в прошлом, и это работает хорошо. Он включает дополнительные классы в ваше приложение, хотя это может быть или не быть желательным.

Вы также можете смоделировать дерево, используя другую коллекцию и сохраняя в ней коллекции. Например. Список списков.

person Fortyrunner    schedule 31.08.2009
comment
Спасибо за идею, попробую. По крайней мере интерфейсы выглядят вполне юзабельно: javax.swing.tree.TreeNode. - person Ivan Koblik; 31.08.2009
comment
Я не могу понять, почему этого нет в API коллекций по умолчанию. - person Fortyrunner; 31.08.2009
comment
Я предполагаю, что его нет в API коллекций, потому что он не добавляет ничего лишнего к уже доступным реализациям коллекций. - person Zed; 31.08.2009

Используйте гуаву

Гуава 15.0 представлен удобный API для обхода дерева, поэтому вам не нужно в тысячу раз заново реализовывать его в кодовой базе.

А именно, TreeTraverser и некоторые специализированные реализации, такие как BinaryTreeTraverser.

Очень желательно дополнение, чтобы избежать повторной реализации чего-то такого простого и с дополнительным бонусом:

  • с душевным спокойствием (стабильность, поддерживаемая библиотека и т. д.),
  • хороший дизайн,
  • несколько встроенных режимов обхода.

Пока ты там...

Обратите внимание, что Guava теперь также предоставляет новые методы для своего вспомогательного класса Files, которые используют TreeTraverser, например. Files.fileTreeTraverser()< /a>, который дает вам TreeTraverser<File> для ваших нужд обхода файловой системы.

person haylem    schedule 23.09.2013

Довольно сложно сделать на Java настоящую реализацию универсального дерева, которая действительно отделяла бы операции и свойства дерева от базовых реализаций, т. е. заменяла RedBlackTreeNode и переопределяла пару методов, чтобы получить реализацию RedBlackTree, сохраняя при этом все общие операции, которые выполняет BinaryTree. интерфейс содержит.

Кроме того, идеальная абстракция могла бы заменить низкоуровневое представление дерева, например. неявная двоичная древовидная структура, хранящаяся в массиве для кучи или базового интерфейса узла с левыми и правыми дочерними указателями или несколькими дочерними указателями, или дополнение любого из вышеперечисленного родительскими указателями, или потоки конечных узлов и т. д. и т. д., и Т. Д.

Я пытался решить эту проблему сам, но в итоге получил довольно сложный интерфейс, который по-прежнему обеспечивает безопасность типов. Вот основа идеи создания абстрактного класса BinaryTree с нетривиальной операцией (Euler Tour), которая будет работать, даже если базовый класс узла или класс дерева изменен. Вероятно, его можно было бы улучшить, представив идею курсоров для навигации и позиций в древовидной структуре:

public interface Tree<E, P extends Tree.Entry<E, P>> extends Collection<E>
{
   public P getRoot();
   public Collection<P> children(P v);
   public E getValue(P v);

   public static interface Entry<T, Q extends Entry<T, Q>> { }
}

public interface BinaryTree<E, P extends BinaryTree.Entry<E, P>> extends Tree<E, P>
{
   public P leftChild(P v);
   public P rightChild(P v);

   public static interface Entry<T, Q extends Entry<T, Q>> extends Tree.Entry<T, Q>
   {
      public Q getLeft();
      public Q getRight();
   }
}

public interface TreeTraversalVisitor<E, P extends BinaryTree.Entry<E, P>, R> 
{
   public R visitLeft( BinaryTree<E, P> tree, P v, R result );
   public R visitCenter( BinaryTree<E, P> tree, P v, R result );
   public R visitRight( BinaryTree<E, P> tree, P v, R result );
}

public abstract class AbstractBinaryTree<E, P extends BinaryTree.Entry<E, P>> extends AbstractCollection<E> implements BinaryTree<E, P>
{
   public Collection<P> children( P v )
   {
      Collection<P> c = new ArrayList<P>( 2 );

      if ( hasLeft( v ))
         c.add( v.getLeft());

      if ( hasRight( v ))
         c.add( v.getRight());

      return c;
   }

   /**
    * Performs an Euler Tour of the binary tree
    */
   public static <R, E, P extends BinaryTree.Entry<E, P>> 
   R eulerTour( BinaryTree<E, P> tree, P v, TreeTraversalVisitor<E, P, R> visitor, R result )
   {
      if ( v == null )
         return result;

      result = visitor.visitLeft( tree, v, result );

      if ( tree.hasLeft( v ))
         result = eulerTour( tree, tree.leftChild( v ), visitor, result );

      result = visitor.visitCenter( tree, v, result );

      if ( tree.hasRight( v ))
         result = eulerTour( tree, tree.rightChild( v ), visitor, result );

      result = visitor.visitRight( tree, v, result );

      return result;
   }    
}
person Lucas    schedule 01.06.2010

А, я собирался выложить беспардонный плагин к своему решению и увидел, что кто-то уже разместил ссылку на него. Да, у меня была та же проблема, и в итоге я написал свое собственное Generic Tree. У меня есть тесты для узла дерева и самого дерева.

Я реализовал узел как объект, имеющий поле данных и список узлов (которые являются дочерними элементами этого узла).

http://vivin.net/2010/01/30/generic-n-ary-tree-in-java/

person Vivin Paliath    schedule 31.01.2010

Я нашел реализацию Generic Tree (с тестами) здесь:

http://vivin.net/2010/01/30/generic-n-ary-tree-in-java/

Я думаю, это то, что вы ищете.

person OccludedInsight    schedule 31.01.2010

Я нашел совершенно фантастическую библиотеку http://jung.sourceforge.net, см. javadoc http://jung.sourceforge.net/doc/api/index.html . Это гораздо больше, чем просто реализация графа. С его помощью вы можете визуализировать и раскладывать графики; плюс, у него есть набор стандартных графических алгоритмов, которые вы можете использовать из коробки. Иди, посмотри! Хотя в итоге я реализовал свой собственный базовый граф (раньше я не знал о JUNG), я использую эту библиотеку для визуализации. Выглядит очень аккуратно!

person Ivan Koblik    schedule 01.02.2010


Когда мне нужно дерево, я обычно использую следующий интерфейс и реализую его соответствующим образом.

  /**
   * Generic node interface
   * 
   * @param <T> type of contained data
   * @param <N> self-referential type boundary that captures the implementing type
   */
  interface Node<T, N extends Node<T, N>>
  {

    public T getObject();

    public boolean addChild(N node);

    public List<N> getChildren();

  }

Реализация может быть

  class StringNode implements Node<String, StringNode>
  {

    private final String value;

    public StringNode(String value)
    {
      this.value = value;
    }

    @Override
    public String getObject()
    {
      return value;
    }

    @Override
    public boolean addChild(StringNode node)
    {
      // add child
      return false;
    }

    @Override
    public List<StringNode> getChildren()
    {
      // return children
      return Collections.emptyList();
    }

  }

Преимуществом здесь является гибкость, получаемая за счет реализации алгоритмов по отношению к интерфейсу. Достаточно простым примером может быть

  public <T, N extends Node<T, ? extends N>> N performAlgorithm(N node)
  {
    if (!node.getChildren().isEmpty())
      return node.getChildren().get(0);

    return node;
  }

Метод может использоваться с типом интерфейса или конкретными реализациями.

StringNode sn = new StringNode("0");
Node<String, StringNode> node = sn;

// perform computations on the interface type
Node<String, StringNode> result = performAlgorithm(node);

// or use a concrete implementation
StringNode result2 = performAlgorithm(sn);
person mike    schedule 12.06.2019

Если вам нужно дерево узлов корпоративного уровня, вы можете заглянуть в репозиторий содержимого Java (JCR) . Но это далеко не простые решения дерева узлов в памяти, предлагаемые здесь, и многопользовательская база данных XML с SQL и XPath.

person Erk    schedule 02.12.2020