Java中的多级映射

Java中的多级映射,java,tree,Java,Tree,在Java中,将值(“o”)保存在树结构中的最佳方法是什么: obj1 /\ / \ / \ obj2 obj3 /\ /\ / \ / \

在Java中,将值(“o”)保存在树结构中的最佳方法是什么:

                    obj1                 
                     /\
                    /  \
                   /    \
              obj2        obj3
              /\            /\
             /  \          /  \
            /    \        /    \
          obj4  obj5    obj6   obj7
          /\     /\     /\      /\
         /  \   /  \   /  \    /  \
        o8   oN...
它看起来像一棵树,但我不需要任意的深度。我需要强大的数据类型和预定义的好看的方法来处理最终的结构

我需要能够通过键获得某种类型的值列表,就像我的图片一样。换句话说,结构不应该以任何方式变成平面

我需要
.get(obj3)
返回
{obj6,obj7},.get(obj1){obj2,obj3}

现在我用地图来做这个,但放大这样的地图很难看,因为我需要检查结构的每一层。看起来是这样的(数据就是地图):

if(data.get(somedouble)=null){
Map inm=新树映射();
输入(someint,obj);
Map m=新树映射();
m、 put(somedouble2,inm);
数据。put(somedouble,m);
}
否则{
if(data.get(somedouble.get(somedouble2)=null){
Map inm=新树映射();
输入(someint,obj);
data.get(somedouble)、put(somedouble2,inm);
}
其他的
data.get(somedouble.get(somedouble2.put)(someint,obj);
}

性能不是问题,但代码美是问题。

您可以使用特定的键:

class MyKey {
    Double beta;
    Double yaw;
    int minute;

    public int hashCode() {
        /* Returns hash code from a combination of hash of the key members. */
    }

    @Override
    public boolean equals(Object obj) {
        /* Returns true if obj is a MyKey with same members. */
    }
}
然后简单地说:

data.put(myKey, obj);
这样,“多级检查”都隐藏在
MyKey.equals()
中。它保持了客户端代码的干净性,并且将密钥复杂性放在一个安全的地方

需求更改后编辑: 如果在此基础上,您希望能够拥有从double
beta
到您的对象的映射,那么我仍然会保持这样的平面

实际上,您想要的是为您的数据建立多个“索引”,就像在数据库中一样,这样您就可以查询具有相同“beta”或“yaw”的对象。为此,最好的方法是使用多个映射(实际上是Multimap),每个“索引”对应一个映射

使用:

listmultimapmapforbeta;
ListMultiMapforYaw;
您可以将所有的多重映射和
映射
放在特定的类中。实际上,最好的方法是将
Map
子类化:

公共类MyMap扩展了HashMap{
ListMultimap-Forbeta;
ListMultiMapforYaw;
公共数据输入(MyKey,数据值){
super.put(键、值);
mapfforbeta.add(key.beta,value);
mapForYaw.add(key.yaw,value);
};
公共列表getFromBeta(双倍测试版){
返回mappforbeta.get(beta);
}
公共列表getFromYaw(双偏航){
返回mapForYaw.get(偏航);
}
}
使用更好的解决方案进行新编辑: 事实上,这让我思考,我意识到你的地图的默认值确实有问题,这就是你的代码有点混乱的原因

您可以通过使用生成器创建基础贴图的默认贴图来解决此问题:

public class DefaultMap<K, V> extends TreeMap<K, V> {

    static abstract class Generator<V>{
        abstract V create();
    }

    final Generator<V> generator;


    DefaultMap(Generator<V> generator) {
        this.generator = generator;
    }

    @Override
    public V get(Object key) {
        V val = super.get(key);
        if (val == null) {
            val = generator.create();

            put((K)key, val);
        }

        return val;
    }
}
public类DefaultMap扩展了TreeMap{
静态抽象类生成器{
抽象V create();
}
最终发电机;
DefaultMap(生成器){
这个。发电机=发电机;
}
@凌驾
public V get(对象键){
V val=super.get(键);
if(val==null){
val=generator.create();
put((K)键,val);
}
返回val;
}
}
现在,您可以使用实用工具树类来存储所有数据:

public class MyTree {
  private final Map<Double, Map<Double, Map<Integer, Data>>> data;

  public MyTree() {
    data = new DefaultMap<>(new Generator<Map<Double, Map<Integer, Data>>>() {
      @Override
      Map<Double, Map<Integer, Data>> create() {
        return new DefaultMap<>(new Generator<Map<Integer, Data>>() {

          @Override
          Map<Integer, Data> create() {
            return new TreeMap<>();
          }

        });
      }
    });
  }

  void add(MyKey d, Data obj) {
    data.get(d.beta).get(d.yaw).put(d.minute, obj);
  }
}
公共类MyTree{
私人最终地图数据;
公共MyTree(){
数据=新的DefaultMap(新的生成器(){
@凌驾
映射创建(){
返回新的DefaultMap(新生成器(){
@凌驾
映射创建(){
返回新树映射();
}
});
}
});
}
无效添加(MyKey d,数据对象){
数据获取(d.beta)、获取(d.yaw)、放置(d.minute,obj);
}
}

现在,您可以使用data.get(beta).get(yaw)访问数据,而且您没有意大利面代码来存储您的值。

二叉树呢

Node.java

java

例如,如果要生成以下树:

         root
          /\
         /  \
        /    \
   node1     node2
   /\           /\
  /  \         /  \
leaf1 leaf2  leaf3 leaf4
使用:


是的,它将简化使用这种映射,但它如何帮助我摆脱创建时冗长的多级检查?duffymo,我考虑过它(实际上,我只需要一些特殊的哈希和相等函数),但对于这样简单的任务来说,它看起来太多了。你所说的“平面”并不明显。你能再说一遍吗?我想知道规格还会改变多少次。我现在就停下来。再一次抱歉。根据我的回答中的注释,“但是我如何通过双d1获得所有值?”我担心规范会改变。规格改变了,我明白了。嗯,我可能有点固执,但再加上一点补充,我认为我的解决方案仍然是最好的那么getByYaw和Beta呢?像这样:data.get(double1.get(double2.get)(int)那么,您总是可以有另一个YawBetaKey和另一个Multimap来存储关系。但我明白你的意思。我喜欢我的东西,因为你可以创建像getFromBetaAndYaw()这样的命名很好的方法。“数据”是一种映射,而不是二叉树。
public class DefaultMap<K, V> extends TreeMap<K, V> {

    static abstract class Generator<V>{
        abstract V create();
    }

    final Generator<V> generator;


    DefaultMap(Generator<V> generator) {
        this.generator = generator;
    }

    @Override
    public V get(Object key) {
        V val = super.get(key);
        if (val == null) {
            val = generator.create();

            put((K)key, val);
        }

        return val;
    }
}
public class MyTree {
  private final Map<Double, Map<Double, Map<Integer, Data>>> data;

  public MyTree() {
    data = new DefaultMap<>(new Generator<Map<Double, Map<Integer, Data>>>() {
      @Override
      Map<Double, Map<Integer, Data>> create() {
        return new DefaultMap<>(new Generator<Map<Integer, Data>>() {

          @Override
          Map<Integer, Data> create() {
            return new TreeMap<>();
          }

        });
      }
    });
  }

  void add(MyKey d, Data obj) {
    data.get(d.beta).get(d.yaw).put(d.minute, obj);
  }
}
public class Node {

    private Node leftChild;
    private Node rightChild;

    public Node(Node leftChild, Node rightChild) {
        this.leftChild = leftChild;
        this.rightChild = rightChild;
    }

    public boolean isLeaf() {
        return this instanceof Leaf;
    }

}
public class Leaf extends Node {

    private Data data;

    public Leaf(Data data) {
        super(null, null);
        this.data = data;
    }

}
         root
          /\
         /  \
        /    \
   node1     node2
   /\           /\
  /  \         /  \
leaf1 leaf2  leaf3 leaf4
Leaf leaf1 = new Leaf(new Data());
Leaf leaf2 = new Leaf(new Data());
Leaf leaf3 = new Leaf(new Data());
Leaf leaf4 = new Leaf(new Data());

Node node1 = new Node(leaf1, leaf2);
Node node2 = new Node(leaf3, leaf4);

Node root = new Node(node1, node2);