Як реалізувати структуру даних дерева в Java? [зачинено]


496

Чи є стандартний клас бібліотеки Java, який представляє дерево на Java?

Конкретно мені потрібно представити наступне:

  • Піддерево на будь-якому вузлі може мати довільну кількість дітей
  • Кожен вузол (після кореня) та його діти матимуть значення рядка
  • Мені потрібно отримати всіх дітей (якийсь список або масив Strings) даного вузла, і це значення рядка (тобто метод, який буде приймати вузол як вхідний і повертати всі рядкові значення дочірнього вузла як вихід)

Чи є якась доступна структура для цього чи мені потрібно створити власну (якщо так, пропозиції щодо реалізації були б чудовими).


3
Якщо ви використовуєте Java 8 і хочете провести ваші вузли потоками, фільтрацією тощо; тоді ви можете поглянути на Durian github.com/diffplug/durian
Нед Твігг

1
Ви можете використовувати цей API: sourceforge.net/p/treeds4j
Мохамед Енахді Ель Ідріссі

Відповіді:


306

Тут:

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.


304
Строго говорити, що Treeклас не потрібен, тому що кожен Nodeсам по собі може розглядатися як дерево.
Йоахім Зауер

34
@Joa, мені подобається, що структура має містити корінь. Ви можете додати до класу дерев методи, які мають більше сенсу дзвонити на дерево, а не на один вузол.
jjnguy

24
@Justin: наприклад? Це чесне запитання: я не можу придумати єдиного методу, який має сенс для всього дерева, який не має сенсу для субдерева.
Йоахім Зауер

22
Я погоджуюся з @Joa, що клас Дерева не потрібен. Я вважаю за краще залишити рекурсивний характер дерев явним у коді, не додаючи окремий клас дерева та послідовно використовуючи клас Node. Натомість я називаю змінну "дерево" або "корінь", якщо їй потрібно зрозуміти, що ви маєте справу з кореневим Вузлом дерева.
jvdbogae

89
@Joa Чотирирічний старший я повністю згоден з тобою. Nix клас дерева.
jjnguy

122

Ще одна структура дерева:

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


2
Щойно знайшла вашу бібліотеку надзвичайно корисною. Дякую. Але я хотів би знати, як реалізувати динамічне заселення структури дерева на основі опорних зв’язків між батьком і дочірнім. Наведений приклад: у мене є один член1 спонсор, інший член2, і член2 спонсор член 3 і так, і так далі. Уже є взаємозв'язок записів таблиці, але просто не впевнений, що я можу заселити їх у дерево за допомогою вашої бібліотеки.
d4v1dv00

1
станом на 2016 рік, посилання не містить вихідних файлів та завантажень
Шарон Бен Ашер

2
На мою думку, ця відповідь через три роки після вищевказаної відповіді є більш чистою. Однак я би замінив LinkedList на ArrayList для цього.children.
HopeKing

1
Я б використав набір для дітей.
DPM

Я можу помилитися, але, схоже, що з цією реалізацією вам потрібно зателефонувати hasNext()перед кожним викликом, next()щоб отримати дійсні результати. Це не частина Iteratorспецифікації.
Роберт Льюїс

97

Насправді є досить хороша структура дерева, реалізована в JDK.

Подивіться на javax.swing.tree , TreeModel та TreeNode . Вони розроблені для використання з, JTreePanelале насправді вони є досить гарною реалізацією дерева, і це ніщо не заважає вам використовувати його з розгорнутим інтерфейсом.

Зауважте, що на Java 9 ви можете не використовувати ці класи, оскільки вони не будуть присутні у "Компактних профілях" .


5
Так, я раніше їх використовував, і вони з дерева зроблять все, що завгодно. Єдиний недолік, про який я можу подумати - це довжина імен їх відповідних класів реалізації: DefaultTreeModel та DefaultMutableTreeNode. Багатослівний, але не те, що його все, що важливо, я думаю.
Ultimate Gobblement

4
Хороший спосіб впоратися з цим - створити пару статичних методів newModel () і newNode (), а потім статичний імпорт.
Гарет Девіс

140
Я б уникав використання бібліотек Swing для функцій, що не стосуються Swing. Це погана практика кодування . Ніколи не знаєш, як Swing реалізує свої дерева, що таке їх залежність і як це може змінитися в майбутньому. Swing - це не бібліотека утиліт, а бібліотека інтерфейсу користувача.
jasop

44
Я думаю, що погана практика кодування трохи сувора.
Гарет Девіс

51
javax.swing.tree.TreeModel - це публічний інтерфейс (точно як java.util.List), і він не матиме несумісних змін. Додатковою перевагою є те, що ви можете легко налагоджувати / візуалізувати дерево під час розвитку.
lbalazscs

45

Як що до цього?

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

/**
  * @author ycoppel@google.com (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;
  }
}

5
Як DFS буде реалізований на дереві, створеному за допомогою цього об’єкта класу?
leba-lev

3
Як би реалізувати видалення аркуша за допомогою цього класу?
ghedas

2
Для чого використовуватиметься головне поле?
Acour83

2
Було б чудово, якби цей клас мав якусь документацію. Я не дуже розумію, які методи подобаються setAsParentчи getHeadроблять, і саме зараз я можу отримати допомогу щодо структури даних про дерево. Навіть до першоджерела документа немає коментарів.
disasterkid

23

Я написав невелику бібліотеку, яка обробляє родові дерева. Це набагато легше, ніж гойдалки. У мене також є проект Maven для цього.


3
Я зараз його використовую, працює чудово. Довелося істотно змінити джерело для моїх власних налаштувань, але це було чудовою відправною точкою. Дякую Вівін!
jasop

20
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;
    }
}

Очевидно, ви можете додати корисні методи для додавання / видалення дітей.


1
Це говорить про те, що батьком дерева є дерево. Я вважаю, ви намагалися створити клас Tree Node.
Мадхур Бхаргава

16

Спершу слід визначити, що таке дерево (для домену), це найкраще зробити, попередньо визначивши інтерфейс . Не всі структури дерев можна змінювати, можливість додавання та видалення вузлів має бути необов'язковою функцією, тому ми робимо для цього додатковий інтерфейс.

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

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

Структура дерева, що змінюється (дозволяє додавати та видаляти вузли):

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

Враховуючи ці інтерфейси, код, який використовує дерева, не повинен сильно дбати про те, як дерево реалізовано. Це дозволяє використовувати як загальні реалізації, так і спеціалізовані , де ви реалізуєте дерево, делегуючи функції в інший API.

Приклад: структура дерева файлів

public class FileTree implements Tree<File> {

    @Override
    public List<File> getRoots() {
        return Arrays.stream(File.listRoots()).collect(Collectors.toList());
    }

    @Override
    public File getParent(File node) {
        return node.getParentFile();
    }

    @Override
    public List<File> getChildren(File node) {
        if (node.isDirectory()) {
            File[] children = node.listFiles();
            if (children != null) {
                return Arrays.stream(children).collect(Collectors.toList());
            }
        }
        return Collections.emptyList();
    }
}

Приклад: загальна структура дерева (заснована на стосунках батьків / дитини):

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

    public static void main(String[] args) {

        MutableTree<String> tree = new MappedTreeStructure<>();
        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<>();
    private final LinkedHashSet<N> nodeList = new LinkedHashSet<>();

    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<>();
        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);
        }
    }
}

1
Я стикаюся з проблемою, коли я слідую за цією структурою, коли роблю tree.add ("A", "B"); tree.add ("А", "С"); tree.add ("C", "D"); tree.add ("Е", "А"); Е - це батько A Як нам це робити?
saNiks

1
Привіт saNicks, у коді сталася помилка, яка спричинила не додавання останнього зв’язку. Це тепер виправлено, і я також додав ненульові перевірки та (що важливіше): циклічні перевірки, які запобігають порушенню структури дерева (додавання коду чи одного з його предків як дитина до себе). Дякую за підказку!
Пітер Уолсер

1
Я виправив помилку, якщо хтось шукає виправлення для цієї помилки, що вам потрібно зробити, це побачити, якщо метод додавання повертає помилкове, а якщо він помилковий, просто створіть темп новий LinkedHashSet <N> і клонуйте в нього ноделіст дерева, тоді ви можете очистити дерево, додайте батьківський вузол, який не був доданий на попередньому кроці, а потім addAll tempNode назад до батьківського дерева ... Хоча дякую за структуру!
saNiks

2
Просто видаліть ці марні публічні модифікатори зі своїх інтерфейсів.
Хамедзь

1
як я можу генерувати з цього масив json
Pawan Pandey

12

Жодна відповідь не згадує надто спрощений, але робочий код, тому ось він:

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

10

Ви можете використовувати будь-який XML API Java як Document and Node .. так як XML - це структура дерева зі Strings


5
відмінна ідея. Ми могли б використовувати в XML-схемі пам'яті використання dom4j + jaxen xpath для пошуку вузлів.
Ben Rhouma Zied

8

Якщо ви робите кодування на дошці, інтерв'ю або навіть просто плануєте використовувати дерево, то багатослівність цих матеріалів небагато.

Слід сказати, що причина, коли дерево не знаходиться там, як, скажімо, 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;
}

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

щоб мати змогу отримати всіх дітей (якийсь список або масив Strings) з введеною рядком, що представляє даний вузол

Це звучить як ваше домашнє завдання.
Але оскільки я досить впевнений, що зараз минув будь-який термін ...

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
[]

7

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


Лол, як ти навіть натрапив на цей клас?
Pacerier

7

У Java є кілька структур даних дерев, таких як DefaultMutableTreeNode в JDK Swing, Tree in Stanford parser parser та інші коди іграшок. Але жодне з них не є достатньою, але достатньо малою для загальних цілей.

Проект Java-дерево намагається надати іншу структуру даних дерева загального призначення на Java. Різниця між цим та іншими є

  • Цілком безкоштовно. Ви можете використовувати його будь-де (крім домашнього завдання: P)
  • Невеликий, але досить загальний. Я помістив усі структури даних в один файл класу, тому було б легко скопіювати / вставити.
  • Не просто іграшки. Мені відомо десятки кодів дерев Java, які можуть обробляти лише бінарні дерева або обмежені операції. Цей TreeNode набагато більше, ніж це. Він передбачає різні способи відвідування вузлів, таких як передпорядкування, порядок, широта, листя, шлях до кореня тощо. Більше того, ітератори також передбачені для достатності.
  • Буде додано більше утиліт. Я готовий додати більше операцій, щоб зробити цей проект всеосяжним, особливо якщо ви надсилаєте запит через github.


5

Оскільки питання вимагає доступної структури даних, дерево може бути побудовано зі списків або масивів:

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

instanceof може використовуватися для визначення того, чи є елементом піддерево або термінальний вузол.


2
Досить потворно. І не працює, якщо ваші об’єкти даних можуть бути масивами відповідно списками.
user686249

1
Я згоден, що це некрасиво. ObjectИ буде або об'єкти листа (наприклад, Stringз) або гілки (представлені масивами). І це працює: цей код буде компілюватися, і він створює невелике дерево Strings.
Олате

5
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;
  ...
}

3

Наприклад :

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;
    }
}

3

Раніше я просто використовував для цього вкладену карту. Це те, що я використовую сьогодні, це дуже просто, але відповідає моїм потребам. Можливо, це допоможе іншому.

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"));
    }
}

3

Я написав невеликий клас "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);
    }

}

Він може бути використаний для зберігання Дерева речей типу "T" (загальне), але не підтримує (поки що) зберігання додаткових даних у його вузлах. Якщо у вас є такий файл:

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(", "));
}

І ви отримаєте гарне дерево. Він повинен легко адаптуватися до ваших потреб.


2

Ви можете використовувати клас HashTree, включений до Apache JMeter, який є частиною проекту Джакарта.

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

1) Завантажте джерела JMeter .

2) Створіть новий пакет.

3) Скопіюйте на нього / src / jorphan / org / apache / jorphan / collection /. Усі файли, крім Data.java

4) Скопіюйте також /src/jorphan/org/apache/jorphan/util/JOrphanUtils.java

5) HashTree готовий до використання.


2

На Java немає конкретної структури даних, яка б відповідала вашим вимогам. Ваші вимоги досить специфічні, і для цього вам потрібно створити власну структуру даних. Дивлячись на ваші вимоги, кожен може сказати, що вам потрібне якесь n-ary дерево з певною функціональністю. Ви можете спроектувати структуру даних таким чином:

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

Я б запропонував, ви записуєте структуру вузла в один клас на зразок вузла Class {String value; Перелічіть дітей;} та всі інші методи, такі як пошук, вставлення та отриманняChildren в інший клас NodeUtils, щоб ви також могли передати корінь дерева для виконання операцій на конкретному дереві, як-от: клас NodeUtils {public static Node search (root Node, String value) {// виконати BFS та повернути Вузол}


2
    // 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);
  }
}

3
Будь ласка, не просто дамп-код - поясніть, що він робить, і особливо, чому він відрізняється (краще), ніж усі інші відповіді.
Ян Догген

2

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

https://github.com/RutledgePaulV/prune

Реалізація не робить нічого особливого в індексації, і я не відхилявся від рекурсії, тому можливо, що при великих деревах продуктивність погіршиться, і ви можете підірвати стек. Але якщо все, що вам потрібно, це пряме дерево невеликої та помірної глибини, я думаю, що це працює досить добре. Він надає здорове (на основі значення) визначення рівності, а також має реалізацію toString, яка дозволяє візуалізувати дерево!


1

Перевірте наведений нижче код, де я використовував структури даних Tree, не використовуючи класи колекції. У коді можуть бути помилки / покращення, але будь ласка, використовуйте це лише для довідки

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();

    }

}

2
" без використання колекційних класів " А? То звідки походить клас черги? І як було сказано вище, це двійкове дерево, не вдається на перших порах (будь-яка кількість дитячих вузлів).
PhiLho

1

Ви можете використовувати клас TreeSet в java.util. *. Він працює як дерево двійкового пошуку, тому його вже сортують. Клас TreeSet реалізує інтерфейси Iterable, Collection та Set. Ви можете пройти по дереву за допомогою ітератора, як набір.

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

Ви можете перевірити, Java Doc та деякі інші .


-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);             
    }

}

11
Це бінарне дерево, воно виходить з ладу при першій вимозі ОП ...
PhiLho
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.