11

次のようなツリー構造で値( "o")を保持するJavaの最良の方法は何ですか。

                    obj1                 
                     /\
                    /  \
                   /    \
              obj2        obj3
              /\            /\
             /  \          /  \
            /    \        /    \
          obj4  obj5    obj6   obj7
          /\     /\     /\      /\
         /  \   /  \   /  \    /  \
        o8   oN...

木のように見えますが、任意の深さは必要ありません。最終的な構造を操作するには、強力なデータタイピングと事前定義された見栄えの良い方法が必要です。

私の写真のように、キーによってある種の値のリストを取得できる必要があります。言い換えれば、構造は決して平面になるべきではありません。

.get(obj3)戻る必要があり{obj6, obj7}, .get(obj1) - {obj2, obj3}ます。

今のところ私はそのためにマップを使用していますが、構造の各レベルをチェックする必要があるため、そのようなマップを膨らませることは醜いです。そのように見えます(データは地図です):

if(data.get(somedouble) == null) {
    Map<Integer, Data> inm = new TreeMap<>();
    inm.put(someint, obj);
    Map<Double, Map<Integer, Data>> m = new TreeMap<>();
    m.put(somedouble2, inm);
    data.put(somedouble, m);
}
else {
    if(data.get(somedouble).get(somedouble2) == null) {
        Map<Integer, Data> inm = new TreeMap<>();
        inm.put(someint, obj);
        data.get(somedouble).put(somedouble2, inm);
    }
    else
        data.get(somedouble).get(somedouble2).put(someint, obj);
}

パフォーマンスは問題ではありませんが、コードの美しさは問題です。

4

2 に答える 2

7

特定のキーを使用できます。

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()ます。クライアントコードをクリーンに保ち、重要な複雑さを安全な場所に置きます。

要件変更後に編集:

これに加えて、ダブルbetaからオブジェクトへのマップを作成できるようにしたい場合でも、そのように平面を維持します。

実際に必要なのは、データベースのようにデータに複数の「インデックス」を設定して、同じ「ベータ」または「ヨー」を持つオブジェクトをクエリできるようにすることです。そのための最良の方法は、「インデックス」ごとに1つずつ、複数のマップ(実際にはマルチマップ)を使用することです。

Guavaのマルチマップの使用:

ListMultimap<Double, Data> mapForBeta;
ListMultimap<Double, Data> mapForYaw;

Map<MyKey, Data>すべてのマルチマップとを特定のクラスに入れることができます。実際には、サブクラス化するのが最善の方法Map<MyKey, Data>です。

public class MyMap extends HashMap<MyKey, Data> {

    ListMultimap<Double, Data> mapForBeta;
    ListMultimap<Double, Data> mapForYaw;


    public Data put(MyKey key, Data value) {
        super.put(key, value);
        mapForBeta.add(key.beta, value);
        mapForYaw.add(key.yaw, value);
    };

    public List<Data> getFromBeta(Double beta) {
        return mapForBeta.get(beta);
    }

    public List<Data> getFromYaw(Double yaw) {
        return mapForYaw.get(yaw);
    }
}

より良い解決策を備えた新しい編集:

実際、それは私に考えさせられました、そして私はあなたがあなたの地図のデフォルト値に本当に問題を抱えていることに気づきました、そしてそれがあなたのコードが少し厄介である理由です。

ジェネレータを使用してデフォルトマップでこれを解決し、基になるマップを作成できます。

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);
  }
}

これで、data.get(beta).get(yaw)を使用してデータにアクセスでき、値を格納するためのスパゲッティコードがありません。

于 2013-02-01T15:48:00.777 に答える
1

二分木はどうですか?

Node.java

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;
    }

}

Leaf.java

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);
于 2013-02-01T16:01:47.993 に答える