2010-08-19 2 views
404

Есть ли хорошая доступная (стандартная Java) структура данных для представления дерева в Java?Структура данных дерева Java?

Конкретно мне нужно представить следующее:

  • Дерево в любом узле может иметь произвольное число детей
  • Каждый узел (после того, как корень) просто String (чьи дети также Струны)
  • мне нужно, чтобы быть в состоянии получить все дети (какой-то список или массив строк) заданной входной строкой, представляющей данный узел

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

+1

Если вы используете Java 8 и хотите пересечь ваши узлы потоками, фильтрацией и т. Д .; то вы можете взглянуть на Durian https://github.com/diffplug/durian/ –

ответ

253

здесь:

public class Tree<T> { 
    private Node<T> root; 

    public Tree(T rootData) { 
     root = new Node<T>(); 
     root.data = rootData; 
     root.children = new ArrayList<Node<T>>(); 
    } 

    public static class Node<T> { 
     private T data; 
     private Node<T> parent; 
     private List<Node<T>> children; 
    } 
} 

То есть базовая структура дерева, которая может быть использована для String или любого другого объекта. Довольно просто реализовать простые деревья, чтобы делать то, что вам нужно.

Все, что вам нужно добавить, это методы для добавления, удаления, перемещения и конструкторов. Node является основным строительным блоком Tree.

+6

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

+1

Правда, если вы хотите подняться по дереву, вам понадобится родительский реф. – jjnguy

+262

Строго говоря, класс «Дерево» не нужен, потому что каждый «узел» сам по себе может рассматриваться как дерево. –

92

На самом деле в JDK реализована довольно хорошая древовидная структура.

Взгляните на javax.swing.tree, TreeModel и TreeNode. Они предназначены для использования с JTreePanel, но на самом деле это довольно хорошая реализация дерева, и нет ничего, что помешало бы вам использовать ее без интерфейса swing.

Обратите внимание, что с Java 9 вы можете не использовать эти классы, поскольку они не будут присутствовать в 'Compact profiles'.

+4

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

+3

Хороший способ справиться с этим - создать пару статических методов newModel() и newNode(), а затем статически импортировать их. –

+118

Я бы не использовал библиотеки Swing для функций, не связанных с Swing. Это ** неправильная практика кодирования **. Вы никогда не знаете, как Swing реализует свои деревья, каковы их зависимости и как это может измениться в будущем. Swing - это не библиотека утилиты, а библиотека пользовательского интерфейса. – jasop

15
public class Tree { 
    private List<Tree> leaves = new LinkedList<Tree>(); 
    private Tree parent = null; 
    private String data; 

    public Tree(String data, Tree parent) { 
     this.data = data; 
     this.parent = parent; 
    } 
} 

Очевидно, вы можете добавить утилиту для добавления/удаления детей.

6

Наряду с ответом Гарета, проверьте DefaultMutableTreeNode. Это не общее, но, похоже, похоже на счет. Несмотря на то, что он находится в пакете javax.swing, он не зависит от каких-либо классов AWT или Swing. Фактически, исходный код на самом деле имеет комментарий // ISSUE: this class depends on nothing in AWT -- move to java.util?

38

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

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.HashMap; 

/** 
    * @author [email protected] (Yohann Coppel) 
    * 
    * @param <T> 
    *   Object's type in the tree. 
*/ 
public class Tree<T> { 

    private T head; 

    private ArrayList<Tree<T>> leafs = new ArrayList<Tree<T>>(); 

    private Tree<T> parent = null; 

    private HashMap<T, Tree<T>> locate = new HashMap<T, Tree<T>>(); 

    public Tree(T head) { 
    this.head = head; 
    locate.put(head, this); 
    } 

    public void addLeaf(T root, T leaf) { 
    if (locate.containsKey(root)) { 
     locate.get(root).addLeaf(leaf); 
    } else { 
     addLeaf(root).addLeaf(leaf); 
    } 
    } 

    public Tree<T> addLeaf(T leaf) { 
    Tree<T> t = new Tree<T>(leaf); 
    leafs.add(t); 
    t.parent = this; 
    t.locate = this.locate; 
    locate.put(leaf, t); 
    return t; 
    } 

    public Tree<T> setAsParent(T parentRoot) { 
    Tree<T> t = new Tree<T>(parentRoot); 
    t.leafs.add(this); 
    this.parent = t; 
    t.locate = this.locate; 
    t.locate.put(head, this); 
    t.locate.put(parentRoot, t); 
    return t; 
    } 

    public T getHead() { 
    return head; 
    } 

    public Tree<T> getTree(T element) { 
    return locate.get(element); 
    } 

    public Tree<T> getParent() { 
    return parent; 
    } 

    public Collection<T> getSuccessors(T root) { 
    Collection<T> successors = new ArrayList<T>(); 
    Tree<T> tree = getTree(root); 
    if (null != tree) { 
     for (Tree<T> leaf : tree.leafs) { 
     successors.add(leaf.head); 
     } 
    } 
    return successors; 
    } 

    public Collection<Tree<T>> getSubTrees() { 
    return leafs; 
    } 

    public static <T> Collection<T> getSuccessors(T of, Collection<Tree<T>> in) { 
    for (Tree<T> tree : in) { 
     if (tree.locate.containsKey(of)) { 
     return tree.getSuccessors(of); 
     } 
    } 
    return new ArrayList<T>(); 
    } 

    @Override 
    public String toString() { 
    return printTree(0); 
    } 

    private static final int indent = 2; 

    private String printTree(int increment) { 
    String s = ""; 
    String inc = ""; 
    for (int i = 0; i < increment; ++i) { 
     inc = inc + " "; 
    } 
    s = inc + head; 
    for (Tree<T> child : leafs) { 
     s += "\n" + child.printTree(increment + indent); 
    } 
    return s; 
    } 
} 
+3

Как бы реализовать DFS на дереве, созданном с использованием этого объекта класса? –

+2

Как можно было бы удалить лист с помощью этого класса? – ghedas

+1

Для чего будет использоваться поле головы? – Acour83

21

Я wrote немного библиотека, которая обрабатывает общие деревья. Это намного легче, чем качели. У меня также есть maven project.

+3

Я использую его сейчас, работает блестяще. Пришлось существенно изменить исходный код для моих собственных настроек, но это была отличная отправная точка. Спасибо Vivin! – jasop

1

Вы можете использовать класс HashTree, входящий в состав Apache JMeter, который является частью проекта Jakarta.

Класс HashTree включен в пакет org.apache.jorphan.collections.Хотя этот пакет не выпущен за пределами проекта JMeter, вы можете легко его получить:

1) Скачайте JMeter sources.

2) Создайте новый пакет.

3) Копия на нем/src/jorphan/org/apache/jorphan/collections /. Все файлы, кроме Data.java

4) Скопировать также /src/jorphan/org/apache/jorphan/util/JOrphanUtils.java

5) HashTree готов к использованию.

7

Вы можете использовать любой XML API из Java в качестве документа и Node..as XML представляет собой древовидную структуру со строками

+3

отличная идея. Мы могли бы использовать в XML-схеме памяти, используя dom4j + jaxen xpath для поиска узлов. –

7

ответа не упоминает более упрощенно, но рабочий код, так вот она:

public class TreeNodeArray<T> { 
    public T value; 
    public final java.util.List<TreeNodeArray<T>> kids = new java.util.ArrayList<TreeNodeArray<T>>(); 
} 
4

Поскольку вопрос запрашивает доступную структуру данных, дерево может быть построен из списков или массивов:

Object[] tree = new Object[2]; 
tree[0] = "Hello"; 
{ 
    Object[] subtree = new Object[2]; 
    subtree[0] = "Goodbye"; 
    subtree[1] = ""; 
    tree[1] = subtree; 
} 

instanceof может быть использован, чтобы определить, является ли элементом я s поддерево или терминальный узел.

+1

Довольно безобразно. И не работает, если ваши объекты данных могут быть массивами соответственно списков. – user686249

+0

Я согласен, что это уродливо. «Объект» будет либо листовыми объектами (например, «String's»), либо ветвями (представленными массивами). И он работает: этот код будет компилироваться, и он создает небольшое дерево 'String'. – Olathe

94

Еще одна структура дерева: использование

public class TreeNode<T> implements Iterable<TreeNode<T>> { 

    T data; 
    TreeNode<T> parent; 
    List<TreeNode<T>> children; 

    public TreeNode(T data) { 
     this.data = data; 
     this.children = new LinkedList<TreeNode<T>>(); 
    } 

    public TreeNode<T> addChild(T child) { 
     TreeNode<T> childNode = new TreeNode<T>(child); 
     childNode.parent = this; 
     this.children.add(childNode); 
     return childNode; 
    } 

    // other features ... 

} 

Примера:

TreeNode<String> root = new TreeNode<String>("root"); 
{ 
    TreeNode<String> node0 = root.addChild("node0"); 
    TreeNode<String> node1 = root.addChild("node1"); 
    TreeNode<String> node2 = root.addChild("node2"); 
    { 
     TreeNode<String> node20 = node2.addChild(null); 
     TreeNode<String> node21 = node2.addChild("node21"); 
     { 
      TreeNode<String> node210 = node20.addChild("node210"); 
     } 
    } 
} 

БОНУСА
См полномасштабного дерева:

  • итератор
  • поиск
  • Java/C#

https://github.com/gt4dev/yet-another-tree-structure

+1

Просто нашла вашу библиотеку чрезвычайно полезной. Спасибо. Но я хотел бы знать, как реализовать динамическое заполнение древовидной структуры на основе эталонной связи между родительским и дочерним. Приведенный пример: у меня есть один член1 спонсор другого участника2, а член-член 3-го члена - 2 и так и так. У меня уже есть отношение записей в таблице, но я не уверен, что могу заполнить их в виде дерева, используя вашу библиотеку. – d4v1dv00

+0

с 2016 года, ссылка не содержит исходных файлов или загрузок –

+0

На мой взгляд, этот ответ через три года после вышеупомянутого более высокого ответа, является более чистым. Однако я бы заменил LinkedList на ArrayList для this.children. – HopeKing

12

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

Нет необходимости создавать объекты узлов, которые содержат значения, на самом деле я рассматриваю это как главный недостаток дизайна и накладные расходы в большинстве реализаций дерева. Если вы посмотрите на Swing, TreeModel свободен от классов узлов (только DefaultTreeModel использует TreeNode), так как они действительно не нужны.

public interface Tree <N extends Serializable> extends Serializable { 
    public List<N> getRoots(); 
    public N getParent (N node); 
    public List<N> getChildren (N node); 
} 

public interface MutableTree <N extends Serializable> extends Tree<N> { 
    public boolean add (N parent, N node); 
    public boolean remove (N node, boolean cascade); 
} 

Учитывая эти интерфейсы, код, который использует деревья, не должен заботиться о том, как дерево реализовано. Это позволяет использовать общие реализации, а также специализированных тех, где вы реализуете дерево, делегируя функции другому API.
Пример: структура дерева файлов.

public class MappedTreeStructure<N extends Serializable> implements MutableTree<N> { 

    public static void main(String[] args) { 

     MutableTree<String> tree = new MappedTreeStructure<String>(); 
     tree.add("A", "B"); 
     tree.add("A", "C"); 
     tree.add("C", "D"); 
     tree.add("E", "A"); 
     System.out.println(tree); 
    } 

    private final Map<N, N> nodeParent = new HashMap<N, N>(); 
    private final LinkedHashSet<N> nodeList = new LinkedHashSet<N>(); 

    private void checkNotNull(N node, String parameterName) { 
     if (node == null) 
      throw new IllegalArgumentException(parameterName + " must not be null"); 
    } 

    @Override 
    public boolean add(N parent, N node) { 
     checkNotNull(parent, "parent"); 
     checkNotNull(node, "node"); 

     // check for cycles 
     N current = parent; 
     do { 
      if (node.equals(current)) { 
       throw new IllegalArgumentException(" node must not be the same or an ancestor of the parent"); 
      } 
     } while ((current = getParent(current)) != null); 

     boolean added = nodeList.add(node); 
     nodeList.add(parent); 
     nodeParent.put(node, parent); 
     return added; 
    } 

    @Override 
    public boolean remove(N node, boolean cascade) { 
     checkNotNull(node, "node"); 

     if (!nodeList.contains(node)) { 
      return false; 
     } 
     if (cascade) { 
      for (N child : getChildren(node)) { 
       remove(child, true); 
      } 
     } else { 
      for (N child : getChildren(node)) { 
       nodeParent.remove(child); 
      } 
     } 
     nodeList.remove(node); 
     return true; 
    } 

    @Override 
    public List<N> getRoots() { 
     return getChildren(null); 
    } 

    @Override 
    public N getParent(N node) { 
     checkNotNull(node, "node"); 
     return nodeParent.get(node); 
    } 

    @Override 
    public List<N> getChildren(N node) { 
     List<N> children = new LinkedList<N>(); 
     for (N n : nodeList) { 
      N parent = nodeParent.get(n); 
      if (node == null && parent == null) { 
       children.add(n); 
      } else if (node != null && parent != null && parent.equals(node)) { 
       children.add(n); 
      } 
     } 
     return children; 
    } 

    @Override 
    public String toString() { 
     StringBuilder builder = new StringBuilder(); 
     dumpNodeStructure(builder, null, "- "); 
     return builder.toString(); 
    } 

    private void dumpNodeStructure(StringBuilder builder, N node, String prefix) { 
     if (node != null) { 
      builder.append(prefix); 
      builder.append(node.toString()); 
      builder.append('\n'); 
      prefix = " " + prefix; 
     } 
     for (N child : getChildren(node)) { 
      dumpNodeStructure(builder, child, prefix); 
     } 
    } 
} 
+0

Я столкнулся с проблемой, когда я следую этой структуре, когда я делаю tree.add («A», «B»); tree.add ("A", "C"); tree.add ("C", "D"); tree.add ("E", "A"); E является родителем A Как мы это сделаем? – saNiks

+0

Привет, saNicks, в коде выше была ошибка, из-за которой последнее отношение не добавлялось. Теперь он исправлен, и я также добавил ненулевые проверки и (что более важно): циклические проверки, которые предотвращают нарушение древовидной структуры (добавление кода или одного из его предков в качестве дочернего для себя). Спасибо за подсказку! –

+0

Я исправил ошибку, если кто-то ищет исправление для этой ошибки, что вам нужно сделать, - это увидеть, возвращает ли метод add false, а если он ложный, просто создайте новый новый LinkedHashSet и клонируйте нольделист дерева в него, тогда вы сможете очистить дерево, добавьте родительский узел, который не был добавлен на предыдущем шаге, а затем добавьте все tempNode обратно в родительское дерево ... Спасибо за структуру, хотя! – saNiks

1

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

package com.datastructure.tree; 

public class BinaryTreeWithoutRecursion <T> { 

    private TreeNode<T> root; 


    public BinaryTreeWithoutRecursion(){ 
     root = null; 
    } 


    public void insert(T data){ 
     root =insert(root, data); 

    } 

    public TreeNode<T> insert(TreeNode<T> node, T data){ 

     TreeNode<T> newNode = new TreeNode<>(); 
     newNode.data = data; 
     newNode.right = newNode.left = null; 

     if(node==null){ 
      node = newNode; 
      return node; 
     } 
     Queue<TreeNode<T>> queue = new Queue<TreeNode<T>>(); 
     queue.enque(node); 
     while(!queue.isEmpty()){ 

      TreeNode<T> temp= queue.deque(); 
      if(temp.left!=null){ 
       queue.enque(temp.left); 
      }else 
      { 
       temp.left = newNode; 

       queue =null; 
       return node; 
      } 
      if(temp.right!=null){ 
       queue.enque(temp.right); 
      }else 
      { 
       temp.right = newNode; 
       queue =null; 
       return node; 
      } 
     } 
     queue=null; 
     return node; 


    } 

    public void inOrderPrint(TreeNode<T> root){ 
     if(root!=null){ 

      inOrderPrint(root.left); 
      System.out.println(root.data); 
      inOrderPrint(root.right); 
     } 

    } 

    public void postOrderPrint(TreeNode<T> root){ 
     if(root!=null){ 

      postOrderPrint(root.left); 

      postOrderPrint(root.right); 
      System.out.println(root.data); 
     } 

    } 

    public void preOrderPrint(){ 
     preOrderPrint(root); 
    } 


    public void inOrderPrint(){ 
     inOrderPrint(root); 
    } 

    public void postOrderPrint(){ 
     inOrderPrint(root); 
    } 


    public void preOrderPrint(TreeNode<T> root){ 
     if(root!=null){ 
      System.out.println(root.data); 
      preOrderPrint(root.left); 
      preOrderPrint(root.right); 
     } 

    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     // TODO Auto-generated method stub 
     BinaryTreeWithoutRecursion <Integer> ls= new BinaryTreeWithoutRecursion <>(); 
     ls.insert(1); 
     ls.insert(2); 
     ls.insert(3); 
     ls.insert(4); 
     ls.insert(5); 
     ls.insert(6); 
     ls.insert(7); 
     //ls.preOrderPrint(); 
     ls.inOrderPrint(); 
     //ls.postOrderPrint(); 

    } 

} 
+0

«Без использования классов Collection_» А? Итак, откуда взялся класс Queue? И, как было сказано выше, это двоичное дерево, не отвечающее первому требованию (любое количество дочерних узлов). – PhiLho

6

Есть несколько древовидных структур данных в Java, таких как DefaultMutableTreeNode в JDK Swing, Дерево в Стэнфорде пакете синтаксического анализа и других игрушечных кодов. Но ни один из них не достаточно мал для общего назначения.

Java-tree Проект пытается предоставить еще одну структуру данных древовидных данных общего назначения в Java. Разница между этим и другими составляет

  • Полностью бесплатно. Вы можете использовать его в любом месте (кроме вашей домашней работы: P)
  • Небольшой, но достаточно общий. Я помещал всю структуру данных в один файл класса, поэтому было бы легко скопировать/вставить.
  • Не только игрушки. Мне известны десятки кодов дерева Java, которые могут обрабатывать только двоичные деревья или ограниченные операции. Этот TreeNode намного больше. Он предоставляет различные способы посещения узлов, такие как предварительный заказ, постобработка, ширина, листья, путь к корню и т. Д. Кроме того, итераторы предоставляются для достаточности.
  • Дополнительные утилиты будут добавлены. Я готов добавить дополнительные операции, чтобы сделать этот проект всеобъемлющим, особенно если вы отправляете запрос через github.
2

Например:

import java.util.ArrayList; 
import java.util.List; 



/** 
* 
* @author X2 
* 
* @param <T> 
*/ 
public class HisTree<T> 
{ 
    private Node<T> root; 

    public HisTree(T rootData) 
    { 
     root = new Node<T>(); 
     root.setData(rootData); 
     root.setChildren(new ArrayList<Node<T>>()); 
    } 

} 

class Node<T> 
{ 

    private T data; 
    private Node<T> parent; 
    private List<Node<T>> children; 

    public T getData() { 
     return data; 
    } 
    public void setData(T data) { 
     this.data = data; 
    } 
    public Node<T> getParent() { 
     return parent; 
    } 
    public void setParent(Node<T> parent) { 
     this.parent = parent; 
    } 
    public List<Node<T>> getChildren() { 
     return children; 
    } 
    public void setChildren(List<Node<T>> children) { 
     this.children = children; 
    } 
} 
1

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

class Node 
{ 
int data; 
Node left; 
Node right; 

public Node(int ddata, Node left, Node right) 
{ 
    this.data = ddata; 
    this.left = null; 
    this.right =null;  
} 

public void displayNode(Node n) 
{ 
    System.out.print(n.data +" "); 
} 
} 

class BinaryTree 
{ 
Node root; 
public BinaryTree() 
{ 
    this.root = null; 
} 
public void insertLeft(int parent,int leftvalue) 
{ 
    Node n = find(root,parent); 
    Node leftchild = new Node(leftvalue, null, null); 
    n.left = leftchild; 
} 

public void insertRight(int parent, int rightvalue) 
{ 
    Node n = find(root,parent); 
    Node rightchild = new Node(rightvalue, null, null); 
    n.right = rightchild; 
} 

public void insertRoot(int data) 
{ 
    root = new Node(data, null, null); 
} 

public Node getRoot() 
{ 
    return root; 
} 

public Node find(Node n,int key) 
{  
    Node result = null; 
    if (n == null) 
     return null; 
    if (n.data ==key) 
     return n; 
    if (n.left != null) 
     result = find(n.left,key); 
    if (result == null) 
     result = find(n.right,key); 
    return result; 
} 

public int getheight(Node root) 
{ 
    if(root == null) 
     return 0;  
    return Math.max(getheight(root.left),getheight(root.right))+1; 
} 

public void printTree(Node n) 
{  
    if(n == null) 
     return; 
    printTree(n.left); 
    n.displayNode(n); 
    printTree(n.right);    
} 
} 
+3

Это двоичное дерево, оно не срабатывает при первом требовании OP ... – PhiLho

1

В Java нет конкретной структуры данных, которая соответствует вашим требованиям. Ваши требования весьма специфичны, и для этого вам необходимо создать собственную структуру данных. Рассматривая ваши требования, каждый может сказать, что вам нужно какое-то n-арное дерево с определенной функциональностью. Вы можете создать структуру данных в следующим образом:

  1. Структура узла дерева будет как содержание в узле и список детей, как: класс Node {строкового значения; Перечислите детей;}
  2. Вам необходимо получить детей заданной строки, поэтому у вас может быть 2 метода 1: Node searchNode (String str), вернет узел, который имеет то же значение, что и заданный ввод (используйте BFS для поиска) 2: Список getChildren (String str): этот метод будет внутренне вызывать searchNode, чтобы получить узел с той же строкой, а затем он создаст список всех строковых значений дочерних элементов и возвращает.
  3. Вам также потребуется вставить строку в дерево. Вам нужно будет написать один метод: void insert (String parent, String value): это снова приведет к поиску узла со значением, равным родительскому, а затем вы можете создать узел с заданным значением и добавить к списку дочерних элементов найденному родительскому элементу ,

Я предлагаю вам написать структуру узла в одном классе, таком как Class Node {String value; Список children;} и все другие методы, такие как search, insert и getChildren в другом классе NodeUtils, чтобы вы могли также передать корень дерева для выполнения операции по определенному дереву: класс NodeUtils {public static Node search (Node root, String value) {// выполнить BFS и вернуть узел}

1

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

import com.fasterxml.jackson.annotation.JsonValue; 
import com.fasterxml.jackson.databind.ObjectMapper; 

import java.util.HashMap; 
import java.util.Map; 
import java.util.TreeMap; 

/** 
* Created by kic on 16.07.15. 
*/ 
public class NestedMap<K, V> { 
    private final Map root = new HashMap<>(); 

    public NestedMap<K, V> put(K key) { 
     Object nested = root.get(key); 

     if (nested == null || !(nested instanceof NestedMap)) root.put(key, nested = new NestedMap<>()); 
     return (NestedMap<K, V>) nested; 
    } 

    public Map.Entry<K,V > put(K key, V value) { 
     root.put(key, value); 

     return (Map.Entry<K, V>) root.entrySet().stream().filter(e -> ((Map.Entry) e).getKey().equals(key)).findFirst().get(); 
    } 

    public NestedMap<K, V> get(K key) { 
     return (NestedMap<K, V>) root.get(key); 
    } 

    public V getValue(K key) { 
     return (V) root.get(key); 
    } 

    @JsonValue 
    public Map getRoot() { 
     return root; 
    } 

    public static void main(String[] args) throws Exception { 
     NestedMap<String, Integer> test = new NestedMap<>(); 
     test.put("a").put("b").put("c", 12); 
     Map.Entry<String, Integer> foo = test.put("a").put("b").put("d", 12); 
     test.put("b", 14); 
     ObjectMapper mapper = new ObjectMapper(); 
     System.out.println(mapper.writeValueAsString(test)); 

     foo.setValue(99); 
     System.out.println(mapper.writeValueAsString(test)); 

     System.out.println(test.get("a").get("b").getValue("d")); 
    } 
} 
1
// TestTree.java 
// A simple test to see how we can build a tree and populate it 
// 
import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.tree.*; 

public class TestTree extends JFrame { 

    JTree tree; 
    DefaultTreeModel treeModel; 

    public TestTree() { 
    super("Tree Test Example"); 
    setSize(400, 300); 
    setDefaultCloseOperation(EXIT_ON_CLOSE); 
    } 

    public void init() { 
    // Build up a bunch of TreeNodes. We use DefaultMutableTreeNode because the 
    // DefaultTreeModel can use it to build a complete tree. 
    DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root"); 
    DefaultMutableTreeNode subroot = new DefaultMutableTreeNode("SubRoot"); 
    DefaultMutableTreeNode leaf1 = new DefaultMutableTreeNode("Leaf 1"); 
    DefaultMutableTreeNode leaf2 = new DefaultMutableTreeNode("Leaf 2"); 

    // Build our tree model starting at the root node, and then make a JTree out 
    // of it. 
    treeModel = new DefaultTreeModel(root); 
    tree = new JTree(treeModel); 

    // Build the tree up from the nodes we created. 
    treeModel.insertNodeInto(subroot, root, 0); 
    // Or, more succinctly: 
    subroot.add(leaf1); 
    root.add(leaf2); 

    // Display it. 
    getContentPane().add(tree, BorderLayout.CENTER); 
    } 

    public static void main(String args[]) { 
    TestTree tt = new TestTree(); 
    tt.init(); 
    tt.setVisible(true); 
    } 
} 
+2

Пожалуйста, не просто сбрасывайте код - объясните, что он делает, и тем более почему он отличается (лучше), чем все остальные ответы. –

3
public abstract class Node { 
    List<Node> children; 

    public List<Node> getChidren() { 
    if (children == null) { 
     children = new ArrayList<>(); 
    } 
    return chidren; 
    } 
} 

Как просто, как он получает, и очень проста в использовании. Чтобы использовать его, увеличьте его:

public class MenuItem extends Node { 
    String label; 
    String href; 
    ... 
} 
1

Я написал библиотеку деревьев, которая отлично сочетается с Java8 и не имеет других зависимостей. Он также обеспечивает свободную интерпретацию некоторых идей из функционального программирования и позволяет вам отображать/фильтровать/обрезать/искать все дерево или поддеревья.

https://github.com/RutledgePaulV/prune

Реализация ничего особенного с индексацией не делать, и я не отклонялся от рекурсии, так что вполне возможно, что при производительности больших деревьев будет деградировать, и вы могли бы взорвать стек. Но если все, что вам нужно, - это простое дерево с небольшой до средней глубиной, я думаю, что он работает достаточно хорошо. Он обеспечивает разумное (основанное на значении) определение равенства, а также имеет реализацию toString, которая позволяет визуализировать дерево!

0

Вы можете использовать класс TreeSet в java.util. *. Он работает как дерево двоичного поиска, поэтому он уже отсортирован. Класс TreeSet реализует интерфейсы Iterable, Collection и Set. Вы можете проходить через дерево с помощью итератора, как набор.

TreeSet<String> treeSet = new TreeSet<String>(); 
Iterator<String> it = treeSet.Iterator(); 
while(it.hasNext()){ 
... 
} 

Вы можете проверить, Java Doc и некоторые other.

5

Если вы делаете кодирование в доске, интервью или даже планируете использовать дерево, то многословие из них очень мало.

Следует также сказать, что причина, по которой дерево не существует, например, Pair (о котором то же самое можно сказать), заключается в том, что вы должны инкапсулировать свои данные в классе, используя его, и простейшая реализация выглядит следующим образом:

/*** 
/* Within the class that's using a binary tree for any reason. You could 
/* generalize with generics IFF the parent class needs different value types. 
*/ 
private class Node { 
    public String value; 
    public Node[] nodes; // Or an Iterable<Node> nodes; 
} 

это действительно его для произвольной ширины дерева.

Если вы хотите бинарное дерево часто бывает проще использовать с именованными полями:

private class Node { // Using package visibility is an option 
    String value; 
    Node left; 
    Node right; 
} 

Или, если вы хотели синтаксического дерева:

private class Node { 
    String value; 
    Map<char, Node> nodes; 
} 

Теперь вы сказали, что вы хотите

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

Это звучит как ваша домашняя работа.
Но так как я достаточно уверен, что любой срок уже прошел ...

import java.util.Arrays; 
import java.util.ArrayList; 
import java.util.List; 

public class kidsOfMatchTheseDays { 
static private class Node { 
    String value; 
    Node[] nodes; 
} 

// Pre-order; you didn't specify. 
static public List<String> list(Node node, String find) { 
    return list(node, find, new ArrayList<String>(), false); 
} 

static private ArrayList<String> list(
    Node node, 
    String find, 
    ArrayList<String> list, 
    boolean add) { 
    if (node == null) { 
    return list; 
    } 
    if (node.value.equals(find)) { 
    add = true; 
    } 
    if (add) { 
    list.add(node.value); 
    } 
    if (node.nodes != null) { 
    for (Node child: node.nodes) { 
     list(child, find, list, add); 
    } 
    } 
    return list; 
} 

public static final void main(String... args) { 
    // Usually never have to do setup like this, so excuse the style 
    // And it could be cleaner by adding a constructor like: 
    //  Node(String val, Node... children) { 
    //   value = val; 
    //   nodes = children; 
    //  } 
    Node tree = new Node(); 
    tree.value = "root"; 
    Node[] n = {new Node(), new Node()}; 
    tree.nodes = n; 
    tree.nodes[0].value = "leftish"; 
    tree.nodes[1].value = "rightish-leafy"; 
    Node[] nn = {new Node()}; 
    tree.nodes[0].nodes = nn; 
    tree.nodes[0].nodes[0].value = "off-leftish-leaf"; 
    // Enough setup 
    System.out.println(Arrays.toString(list(tree, args[0]).toArray())); 
} 
} 

Это заставляет вас использовать как:

$ java kidsOfMatchTheseDays leftish 
[leftish, off-leftish-leaf] 
$ java kidsOfMatchTheseDays root 
[root, leftish, off-leftish-leaf, rightish-leafy] 
$ java kidsOfMatchTheseDays rightish-leafy 
[rightish-leafy] 
$ java kidsOfMatchTheseDays a 
[] 
0

Я написал небольшой «TreeMap» класс на базе «HashMap», который поддерживает добавляющие пути:

import java.util.HashMap; 
import java.util.LinkedList; 

public class TreeMap<T> extends LinkedHashMap<T, TreeMap<T>> { 

    public void put(T[] path) { 
     LinkedList<T> list = new LinkedList<>(); 
     for (T key : path) { 
      list.add(key); 
     } 
     return put(list); 
    } 

    public void put(LinkedList<T> path) { 
     if (path.isEmpty()) { 
      return; 
     } 
     T key = path.removeFirst(); 
     TreeMap<T> val = get(key); 
     if (val == null) { 
      val = new TreeMap<>(); 
      put(key, val); 
     } 
     val.put(path); 
    } 

} 

это можно использовать для хранения дерева вещей типа «Т» (общего), но не (пока) поддержки хранения дополнительных данных в этих узлах. Если у вас есть файл, как это:

root, child 1 
root, child 1, child 1a 
root, child 1, child 1b 
root, child 2 
root, child 3, child 3a 

Тогда вы можете сделать это дерево, выполнив:

TreeMap<String> root = new TreeMap<>(); 
Scanner scanner = new Scanner(new File("input.txt")); 
while (scanner.hasNextLine()) { 
    root.put(scanner.nextLine().split(", ")); 
} 

И вы получите хорошее дерево. Его нужно легко адаптировать к вашим потребностям.

Смежные вопросы