Учитывая случайно распределенный набор ключей, каждый из которых сопоставлен с набором значений, как бы вы преобразовали его в несколько деревьев?

Пример набора данных

  • NB 2 => {NC 2 ND 2 }
  • ND 1 => {NG 1 NH 1 }
  • NA 1 => {NB 1 }
  • NB 1 => {NC 1 ND 1 NE 1 }
  • NA 2 => {NB 2 }
  • NC 1 => {NF 1 }
  • NE 1 => {NI 1 NJ 1 NK 1 }

Результирующее дерево для NA 1

NA1
`-- NB1
    |-- NC1
    |   `-- NF1
    |-- ND1
    |   |-- NG1
    |   `-- NH1
    `-- NE1
        |-- NI1
        |-- NJ1
        `-- NK1

Результирующее дерево для NA 2

NA2
`-- NB2
    |-- NC2
    `-- ND2
1
Dave Jarvis 9 Авг 2009 в 03:50
Это зависит от того, какие операции вам нужно выполнить с деревьями. Что тебе нужно делать с деревьями?
 – 
Doug Currie
9 Авг 2009 в 04:07

2 ответа

Лучший ответ

Мне неизвестны какие-либо библиотечные методы, которые сделают это преобразование. Вот как бы я это сделал. Это довольно просто, ИМО.

public class Tree {
    public Tree(String key) {
        // ...
    }
    public void addChild(Tree child) {
        // ...
    }
}

public Set<Tree> transform(Map<String, List<String>> input) {
    // Potential tree roots.  We start with all LHS keys as potential roots,
    // and eliminate them when we see their keys on the RHS.
    Set<String> roots = new HashSet<String>(input.keySet());

    // This map associates keys with the tree nodes that we create for them
    Map<String, Tree> map = new HashMap<String, Tree>();

    for (Map.Entry<String, List<String>> entry : input.entrySet()) {
        String key = entry.getKey();
        List<String> childKeys = entry.getValue();
        Tree tree = map.get(key);
        if (tree == null) {
            tree = new Tree(key);
            map.put(key, tree);
        }
        for (String childKey : childKeys) {
            roots.remove(childKey);
            Tree child = map.get(childKey);
            if (child == null) {
                child = new Tree(childKey);
                map.put(childKey, child);
            }
            tree.addChild(child);
        }
    }
    Set<Tree> res = new HashSet<Tree>(roots.size());
    for (String key : roots) {
        res.add(map.get(key));
    }
    return res;
}

РЕДАКТИРОВАТЬ: Обратите внимание, что этот алгоритм будет «работать», если входные данные представляют собой набор DAG (направленных ациклических графов). Однако я только что понял, что результирующий набор деревьев будет использовать экземпляры TreeNode для любых общих поддеревьев входных данных.

Помните, что я не отлаживал этот код :-)

3
Stephen C 10 Авг 2009 в 01:29

Когда вы говорите о преобразовании их в набор деревьев, вы имеете в виду метод их представления в памяти?

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

Или вы про графическое представление?

0
CPerkins 9 Авг 2009 в 06:05
В этом случае решение Stephen C , по его словам, довольно прямолинейно (поэтому я голосую за его ответ - и, кстати, оно работает после добавления методов для Tree. ). Между прочим, вы не сказали, как вы хотите обрабатывать циклы. Решение Стивена молча пропускает циклы, но было бы просто создать исключение, если бы это потребовалось.
 – 
CPerkins
9 Авг 2009 в 21:25
@Thangalin: Я обновил свой ответ, чтобы сказать, что означает аббревиатура DAG. По сути, DAG - это дерево, в котором подузлы могут быть общими, но в котором нет циклов (циклов).
 – 
Stephen C
10 Авг 2009 в 01:23