2016-02-15 2 views
0

Я работаю над преобразованием файла с разделителями в упорядоченную древовидную структуру. Ниже приведен пример входных ...Преобразование файла с разделителями в дерево

1.2.3.4.5 
1.3.2.4.5 
1.2.4.5.6 

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

1 
-2 
--3 
---4 
----5 
--4 
---5 
----6 
-3 
--2 
---4 
----5 

Мои мысли о решение этой проблемы было ...

  1. Итерации текстового файла и создать ArrayList, который представляет каждую строку
  2. Использование Collections.sort(), чтобы сделать ArrayList отсортировано
  3. Используйте TreeMap для хранения «базы» записи в качестве ключа (1, в данном случае) и ArrayList строк содержат все записи
  4. итерацию ключи в TreeMap и преобразовать его ArrayList в LinkedHashSet, который содержит узлы, которые представлять каждую запись
  5. итерацию ключи дерева и печати каждого узла купить его значение индекса

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

1 
-2 
--3 
---4 
----5 
--4 
---5 
----6 
-3 
--2 

Как видно, узлы под 3/2/xx отсутствуют, это связано с логикой, которую я использую для построения LinkedHashSet для значений моего узла (Node (3, 4)), будет просто проигнорировано, потому что его дублирующий узел. Я думал, что с этим я пойду в правильном направлении, но теперь я вижу, что моя логика явно ошибочна. Есть ли у кого-нибудь предложения по подходу к чему-то подобному? Мой текущий код ниже ...

TreeBuilder.java

public class TreeBuilder { 

public static void main(String[] args) { 

    // Get a list of records 
    List<String> data = new ArrayList<String>(); 
    data.add("1.2.3.4.5"); 
    data.add("1.3.2.4.5"); 
    data.add("1.2.4.5.6"); 

    Collections.sort(data); 

    // Build the "Base" tree 
    TreeMap<String, List<String>> tree = buildBaseTree(data); 

    // Build the target tree structure 
    TreeMap<String, LinkedHashSet<Node>> finalTree = convertListToSet(tree); 

    printRecords(finalTree); 

} 

public static void printRecords(
     TreeMap<String, LinkedHashSet<Node>> recordTree) { 

    System.out.println("---------Records---------"); 

    for (Map.Entry<String, LinkedHashSet<Node>> entry : recordTree 
      .entrySet()) { 

     System.out.println(entry.getKey()); 

     // Print out the structured data 
     StringBuilder stringBuilder = new StringBuilder(); 
     Iterator<Node> iterator = entry.getValue().iterator(); 
     while (iterator.hasNext()) { 

      Node node = iterator.next(); 
      for (int i = 0; i < node.index; i++) { 
       stringBuilder.append("-"); 
      } 

      System.out.println(stringBuilder.toString() + node.value); 

      // "reset" the builder 
      stringBuilder.setLength(0); 
     } 
    } 

} 

private static TreeMap<String, LinkedHashSet<Node>> convertListToSet(
     TreeMap<String, List<String>> tree) { 

    TreeMap<String, LinkedHashSet<Node>> finalMap = new TreeMap<String, LinkedHashSet<Node>>(); 
    LinkedHashSet<Node> linkedHashSet = new LinkedHashSet<Node>(); 

    // Iterate the entry set 
    for (Map.Entry<String, List<String>> entry : tree.entrySet()) { 

     List<String> records = entry.getValue(); 
     for (String record : records) { 
      String[] recordArray = record.split("\\."); 

      for (int i = 1; i < recordArray.length; i++) { 
       Node node = new Node(i, Integer.parseInt(recordArray[i])); 
       linkedHashSet.add(node); 
      } 
     } 

     finalMap.put(entry.getKey(), linkedHashSet); 

     // reset our linkedHashSet 
     linkedHashSet = new LinkedHashSet<Node>(); 

    } 

    System.out.println("Final map " + finalMap); 

    return finalMap; 
} 

/** 
    * Builds a tree with base record keys and a list of records for each key. 
    * 
    * @param data 
    * @return 
    */ 
private static TreeMap<String, List<String>> buildBaseTree(List<String> data) { 

    TreeMap<String, List<String>> tree = new TreeMap<String, List<String>>(); 
    List<String> recordList = null; 

    // First find all base records 
    for (String record : data) { 

     String[] baseEntry = record.split("\\."); 
     if (!tree.containsKey(baseEntry[0])) { 
      recordList = new ArrayList<String>(); 
      tree.put(baseEntry[0], recordList); 
     } 
    } 

    // Now place all sub-records in each base record 
    for (String record : data) { 

     String[] baseEntry = record.split("\\."); 
     tree.get(baseEntry[0]).add(record); 
    } 

    System.out.println("------------------Base Tree---------------"); 
    System.out.println(tree); 
    System.out.println("------------------------------------------"); 

    return tree; 
} 

private static List<String> readData(String file) { 

    BufferedReader bufferedReader = null; 
    try { 
     bufferedReader = new BufferedReader(new FileReader(new File(file))); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } 
    List<String> data = new ArrayList<String>(); 

    // Get a list of all the records 
    String line = null; 
    try { 
     while ((line = bufferedReader.readLine()) != null) { 
      data.add(line); 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    // Sort the list so its ordered 
    System.out.println("-------------Sorted Data Set-----------"); 
    Collections.sort(data); 
    for (String record : data) { 
     System.out.println(record); 
    } 
    System.out.println("---------------------------------------"); 

    return data; 
} 
} 

Node.java

public class Node implements Comparable<Node> { 

int index; 
int value; 

public Node(int index, int value) { 
    this.index = index; 
    this.value = value; 
} 

public int getIndex() { 
    return index; 
} 

@Override 
public String toString() { 
    return "Node [index=" + index + ", value=" + value + "]"; 
} 

public void setIndex(int index) { 
    this.index = index; 
} 

public int getValue() { 
    return value; 
} 

public void setValue(int value) { 
    this.value = value; 
} 

@Override 
public int compareTo(Node o) { 

    Node otherNode = (Node) o; 

    if (this.index > otherNode.index) 
     return 1; 

    if (this.index < otherNode.index) { 
     return -1; 
    } 

    return 0; 
} 

@Override 
public int hashCode() { 
    final int prime = 31; 
    int result = 1; 
    result = prime * result + index; 
    result = prime * result + value; 
    return result; 
} 

@Override 
public boolean equals(Object obj) { 
    if (this == obj) 
     return true; 
    if (obj == null) 
     return false; 
    if (getClass() != obj.getClass()) 
     return false; 
    Node other = (Node) obj; 
    if (index != other.index) 
     return false; 
    if (value != other.value) 
     return false; 
    return true; 
} 

} 
+0

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

ответ

1

Он не должен быть сложным. Все, что вам нужно, это SortedMap из SortedMap экземпляров, и есть только один трюк: Параметрирование рекурсивно для безопасности типа (при желании).

package com.acme; 

import java.util.ArrayList; 
import java.util.List; 
import java.util.Map.Entry; 
import java.util.TreeMap; 

public class Main { 

    public static void main(String[] args) { 
     List<String> rows = new ArrayList<>(); 
     rows.add("1.2.3.4.5"); 
     rows.add("1.3.2.4.5"); 
     rows.add("1.2.4.5.6"); 

     MyTreeMap root = new MyTreeMap(); 
     for (String row : rows) { 
      MyTreeMap n = root; 
      String[] cells = row.split("\\."); 
      for (String cell : cells) { 
       MyTreeMap child = n.get(cell); 
       if (child == null) { 
        n.put(cell, child = new MyTreeMap()); 
       } 
       n = child; 
      } 
     } 

     print(root, "", "-"); 
    } 

    static void print(MyTreeMap m, String indentationStr, String indentationStrAddition) { 
     for (Entry<String, MyTreeMap> o : m.entrySet()) { 
      System.out.println(indentationStr + o.getKey()); 
      print(o.getValue(), indentationStr + indentationStrAddition, indentationStrAddition); 
     } 
    } 

    /** 
    * This is just a construct that helps us to parameterize recursively. 
    */ 
    static class MyTreeMap extends TreeMap<String, MyTreeMap> {private static final long serialVersionUID = 1L;} 
} 
+0

Извините за задержку в возвращении к вам, это именно то, что я искал.Мне потребовалось несколько прочтений, чтобы понять, что происходит здесь, но для кого-то, кто считает это запутанным, подход, который предлагает Брайан, очень похож на создание двоичного дерева. Концепция в основном начинается с корня для каждого столбца из входных данных, пересекает текущее дерево, если ветка не имеет дочернего элемента, добавьте ее. Спасибо Брайан! – Jason

0

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

private static class TreeNode { 

    private final Map<Integer, TreeNode> children = new HashMap<>(); 

    public void insert(List<Integer> values) { 
     if (!values.isEmpty()) { 
      children.putIfAbsent(values.get(0), new TreeNode()); 
      children.get(values.get(0)).insert(values.subList(1, values.size())); 
     } 
    } 

    public void print(int level) { 
     for (Map.Entry<Integer, TreeNode> entry : children.entrySet()) { 
      System.out.print(String.join("", Collections.nCopies(level, "-"))); 
      System.out.println(entry.getKey()); 
      entry.getValue().print(level + 1); 
     } 
    } 
} 

Я не уверен, если вы собираетесь отсортировать список целых чисел. Если это так, вы можете добавить Collections.sort в соответствующее место в коде.

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