使用嵌套的HashMaps是不好的做法吗?

时间:2014-03-23 06:55:58

标签: java data-structures hashmap

让我解释一下我的情景。我有一些我需要维护的层次结构。在下面找到显示此层次结构的图像。我将在图片后解释。

   A
   |          +--> A1.1 ---> X
   |          | 
   +--> A1 ---+--> A1.2 ---> Y
   |          |
   |          .
   +--> A2    .
   .
   .
  • AA1, A2... 一对多关系
  • A1A1.1, A1.2... 一对多关系
  • A1.1XA1.2Y,这是一对一关系。

最初我设计的方式是使用多个HashMap来维护它。但后来我很快意识到更新变得非常困难。

拥有多个HashMap s意味着我必须自己处理不同关系中的唯一性。例如,A1.1也可以存在于根B节点中。所以我必须将A追加到A1.1,以便我可以确保唯一性。现在,如果我必须修改值A,那么我遇到了大麻烦,因为我使用它来将A中的所有密钥限定为A_A1.1

现在我想我可以使用嵌套HashMaps。所以这个代码就变成了:

HashMap<String, HashMap<String, HashMap<String, CustomObject>>> _worldsBiggestHash; 

这种做法可以吗?我确实要做很多记账,因为我将使用嵌套哈希,但至少CRUD和唯一性问题会处理自己。

如果这不合适,有人可以提出另一个我可以使用的更好的结构吗?

2 个答案:

答案 0 :(得分:5)

你显然想要为树建模。此树不一定与TreeMap明确相关。诚然,我没有看到TreeMap如何帮助表示整个结构(尽管它可以在各个树节点中使用)。

你可以创建一个这样的类

class Node 
{
    private final String name;
    private final Map<String, Node> children;
    private final CustomObject customObject;

    Node(String name, CustomObject customObject)
    {
        this.name = name;
        this.children = new LinkedHashMap<String, Node>();
        this.customObject = customObject;
    }

    String getName()
    {
        return name;
    }

    void addChild(Node child) 
    {
        children.put(child.getName(), child);
    }

    void removeChild(String name)
    {
        children.remove(name);
    }

    Node getChild(String name)
    {
        return children.get(name);
    }

    Set<Node> getChildren()
    {
        return Collections.unmodifiableSet(
            new LinkedHashSet<Node>(children.values()));
    }

(只是快速草图)

然后你可以像这样构建层次结构

Node root = new Node("", null);
Node a1 = new Node("A1", null);
Node a2 = new Node("A2", null);
root.addChild(a1);
root.addChild(a2);

Node a11 = new Node("A11", x);
Node a12 = new Node("A12", y);
a1.addChild(a11);
a1.addChild(a12);

这将允许您在层次结构中导航,并且维护关系将非常容易。

我并不完全理解你所说的“独特性”。在任何情况下,在这样的树中,每个节点由路径唯一标识。你甚至可以创建一个像

这样的实用工具方法
CustomObject c = root.find("A", "A1", "A11");

通过节点名称序列快速访问对象。


抛开:正如已经指出的那样,深层嵌套的地图(或列表或集合)是值得怀疑的。但无论如何,你应该总是使用 interfaces ,就像在

中一样
Map<String, Map<String, CustomObject>> maps;

对于某些用例, 可以,但是根据确切地想要建模什么(特别是当有另一层时),这可能已经不方便。

答案 1 :(得分:2)

您的建议不可取。

假设您的要求是能够基于密钥在O(log(n))时间内获取项目。 我建议做以下任何一种方法作为解决这个问题的更好方法:

  1. 使用TreeMap,或者如果您需要并发,请使用ConcurrentSkipListMap(这将是我解决问题的第一选择)
  2. 让TreeSet包含键,并使用单独的HashMap在键和值之间进行映射
  3. 创建一个封装映射的类(即HashMap Decorator),它将递归地处理唯一键检查(同样,第一种方法更可取)