Как имплементировать tree в Java?

Проблема такова:

У меня есть три List:

List<String> origins; //10 элементов
List<String> destinations;  //10 элементов
List<String> distances;     //100 элементов

Задача моя соединить их всех в одну структуру. Структура такова:

1 -> 10 -> 10

То есть, каждый элемент в origins по отдельности должен быть связан со всеми 10 элементов из destinations. То бишь 1 origin - 10 destinations - (0,10) distances, 2 origin - 10 destinations - (10,20) distances, 3 origin - (20,30) destinations ...

Мне кажется это выглядит как Tree data structure, хотя я пробовал и Hashmap, но что-то не выходит.

Также вопрос, могу ли я использовать Lists как root или оно должно быть string, то есть одним значение?

root (List<String> origins)
|
List<String> destinations -0 |  List<String> destinations -1| List<String> destinations -2... -10
|
List<String> distances (0,10)| List<String> distances (10,20)| List<String> distances (20,30) ...(90,100)

Вот что я попробовал сделать c помошью HashMap:

for ( Map.Entry<List<String>, Map<List<String>, List<String>>> entry : mapMap.entrySet()) {
        List<String> key = entry.getKey(); //origins
        Map<List<String>, List<String>> tab = entry.getValue(); //destinations and distances
        // do something with key and/or tab
        System.out.println(key.toString() + " " + tab.toString());
    }

или

Map<List<String>,List<String>> map1 = new LinkedHashMap<>();  // ordered
    Map<List<String>,Map<List<String>,List<String>>> map2 = new LinkedHashMap<>();  // ordered
    map1.put(placesDestinations, placeDistances);
    map2.put(placesOrigins, map1);

Оба результата, не выводят, так как мне нужно. Что происходит, это просто выводит первый лист origins, потом destinations, а затем все distances.


Ответы (1 шт):

Автор решения: Alex Krass

Если строить дерево на каких-то простых структурах, то нужно использовать Map, так как дерево имеет одно ключевое значение и несколько дочерних. Поскольку в данном случае мы работает с String, это будет множество вида Map<String, Map<String, Map<String, Map<String, .... >>>>. Работать с такой структурой без какой-либо оболочки достаточно затруднительно.

Поскольку у нас конечное кол-во вариантов и дерево ограничено тремя уровнями, его можно построить так начиная с конца:

    Map<String, List<String>> destinationMap = new LinkedHashMap<String, List<String>>();
    for(int i = 0; i < destinations.size(); i++) {
        destinationMap.put(destinations.get(i), distances.subList(i*10, i*10 + 10));
    }
    Map<String, Map<String, List<String>>>  originsMap = new LinkedHashMap<String, Map<String, List<String>>>();
    for(int i = 0; i < origins.size(); i++) {
        originsMap.put(origins.get(i), destinationMap);
    }
    List<String> distanceList = originsMap.get("o5").get("d3");

Получается своеобразное дерево. Мы получим в качестве ключа String, а в качестве потомков Map<String, List<String>> и List<String> на втором и третьем уровне дерева соответственно.

введите сюда описание изображения

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

class Node {
    private String key;
    private Node parent;
    private List<Node> childs;
}

Ну или так, если делать полную и правильную реализацию: https://stackoverflow.com/questions/19330731/tree-implementation-in-java-root-parents-and-children

В данном случае достаточно будет такой структуры на классах:

public class Root {

    private List<Origin> origins;

    public Origin get(String name) {
        for(Origin origin : origins)
            if(origin.getName().equals(name))
                return origin;
        return null;
    }

    public Root(List<String> origins, List<String> destinations, List<String> distances ) {
        List<Destination> destinationList = new ArrayList<Destination>();
        for(int i = 0; i < destinations.size(); i++) {
            destinationList.add(new Destination(destinations.get(i), distances.subList(i*10, i*10 + 10)));
        }

        List<Origin> originsList = new ArrayList<Origin>();
        for(int i = 0; i < origins.size(); i++) {
            originsList.add(new Origin(origins.get(i), destinationList));
        }

        this.origins = originsList;
    }

    public List<Origin> getOrigins() {
        return origins;
    }

    public void setOrigins(List<Origin> origins) {
        this.origins = origins;
    }
}

public class Origin {
    private String name;
    private List<Destination> destinations;

    public Destination get(String name) {
        for(Destination destination : destinations)
            if(destination.getName().equals(name))
                return destination;
        return null;
    }

    public Origin(String name, List<Destination> destinations) {
        this.name = name;
        this.destinations = destinations;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Destination> getDestinations() {
        return destinations;
    }

    public void setDestinations(List<Destination> destinations) {
        this.destinations = destinations;
    }
}

public class Destination {
    private String name;
    private List<Distance> distances = new ArrayList<Distance>();

    public Distance get(String name) {
        for(Distance distance : distances)
            if(distance.getName().equals(name))
                return distance;
        return null;
    }

    public Destination(String name, List<String> distances) {
        this.name = name;
        for(String el : distances)
            this.distances.add(new Distance(el));
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Distance> getDistances() {
        return distances;
    }

    public void setDistances(List<Distance> distances) {
        this.distances = distances;
    }
}

public class Distance {
    private String name;

    public Distance(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Main {
    public static void main(String[] args) {
        List<String> origins = Arrays.asList("o1", "o2", "o3", "o4", "o5", "o6", "o7", "o8", "o9", "o10");
        List<String> destinations = Arrays.asList("d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10");
        List<String> distances = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
                "21", "22", "23", "24", "25", "26", "27", "28", "29", "30",
                "31", "32", "33", "34", "35", "36", "37", "38", "39", "40",
                "41", "42", "43", "44", "45", "46", "47", "48", "49", "50",
                "51", "52", "53", "54", "55", "56", "57", "58", "59", "60",
                "61", "62", "63", "64", "65", "66", "67", "68", "69", "70",
                "71", "72", "73", "74", "75", "76", "77", "78", "79", "80",
                "81", "82", "83", "84", "85", "86", "87", "88", "89", "90",
                "91", "92", "93", "94", "95", "96", "97", "98", "99", "100");


        Root root = new Root(origins, destinations, distances);
        List<Distance> distanceList = root.get("o2").get("d5").getDistances();

        System.out.println(distanceList.toString());
    }
}
→ Ссылка