23

具体的には、アクセスに1つのフィールドAを使用し、並べ替えに別のフィールド(フィールドS)を使用するコレクションが必要ですが、重複を受け入れる並べ替えられたコレクションで十分です。

私はしばしばこのコレクションが必要になるこの時点に到達しますが、TreeMapは重複を許可しないため、オプションではありません。では、ここで質問しましょう。ここここのstackoverflowで指摘されているように、いくつかの回避策があります。つまり、次のようなものがあります。

  • PriorityQueue:遅い更新(remove(Object)+ add(Object))、およびプリミティブキーのボクシング
  • フィボナッチヒープ:メモリの浪費(?)
  • TreeMap<Field_S, List<Value>>:私にとっての問題は、リストのメモリオーバーヘッドと、プリミティブキーのボックス化です。
  • ソートされたリストまたは配列:問題は挿入と削除が遅いことです-> 1つのセグメント化されたソートされたリストを実装する必要がありますか?
  • guavaからのTreeMultimap(docs):外部依存とおそらくメモリ非効率(?)

より良い提案をお持ちの方はいますか?または、自分のソートされたデータ構造(どれを使用しますか?)を使用する必要がありますか?また、他のソース(Javaでは、単体テストと小さなdepsを備えたオープンソース)があればよいでしょう。


アップデート

現時点での私のユースケースの詳細(前回も同様の需要がありますが)。できるようにしたい参考文献のコレクション(数百万)があります

  • フィールドSに関する最小の要素をポーリングまたは取得します
  • フィールドAを使用してフィールドSを更新します
  • フィールドSの同じ値が発生する可能性があります。フィールドAは、実際には別の配列を指す整数です。
  • 私が欲しい唯一の依存関係はtrove4jです。必要に応じて、mahoutコレクションのような別のものを使用できます。しかし、素晴らしいライブラリであるにもかかわらず、コレクションがメモリ効率(ボクシング/アンボクシング)になるように調整されていないため、グアバではありません。

したがって、すべての人がフィボナッチヒープを求めていますが、要素ごとのオーバーヘッドが多すぎるのではないかと心配しています->それが、よりメモリ効率の高い「ソート+セグメント化配列」ソリューションを考えた理由です。

4

6 に答える 6

7

ソートされたコレクションが必要な場合は、ニーズを注意深く分析する必要があります。
操作の大部分が挿入であり、検索するのがごくわずかである場合、並べ替えられたコレクションを使用する、つまりコレクション内で要素を常に並べ替えておくのは適切なオプションではありません(挿入時に要素を並べ替えたままにするオーバーヘッドがあるため、最も一般的な操作)。
この場合、ソートされていないコレクションを保持し、必要な場合にのみソートを実行するのが最善です。つまり、検索の前に。単純なものを使用しListて並べ替えることもできます(Collections.sortつまり、必要に応じてマージソート)。ただし、これを効率的に行うためには、大規模なデータで作業することを前提としているため、注意してこれをお勧めします。非常に小さなデータでは、線形検索でも十分です。

操作の大部分が検索である場合は、ソートされたコレクションを使用できます。これは、私の観点からは、選択できるデータ構造があり(すでに言及したものもあります)、ベンチマークを使用してニーズに合ったものを確認できます。

于 2012-10-10T20:25:56.680 に答える
3

グアバTreeMultisetはどうですか?あなたが求めたもの:重複を受け入れるソートされたコレクション。しかし、そのパフォーマンスについては何も知りません。

于 2012-10-10T20:21:00.160 に答える
2

私は自分でロールすることにしましたが、TreeMapのバリアントだけでは最適なソリューションではありませんでした。メモリに関してこのコレクションを微調整する場合は、これを更新し続けます。collection.remove(Object)メソッド(エントリの更新用)が必要だったため、速度は以前のPriorityQueueの試行よりもはるかに優れています。

package com.graphhopper.coll;

import gnu.trove.iterator.TIntIterator;
import gnu.trove.set.hash.TIntHashSet;
import java.util.Map.Entry;
import java.util.TreeMap;

/**
 * A priority queue implemented by a treemap to allow fast key update. Or should we use a standard
 * b-tree?
 */
public class MySortedCollection {

    private int size;
    private int slidingMeanValue = 20;
    private TreeMap<Integer, TIntHashSet> map;

    public MySortedCollection(int size) {
        map = new TreeMap<Integer, TIntHashSet>();
    }

    void remove(int key, int value) {
        TIntHashSet set = map.get(value);
        if (set == null || !set.remove(key))
            throw new IllegalStateException("cannot remove key " + key + " with value " + value
                    + " - did you insert " + key + "," + value + " before?");
        size--;
        if (set.isEmpty())
            map.remove(value);
    }

    public void update(int key, int oldValue, int value) {
        remove(key, oldValue);
        insert(key, value);
    }

    public void insert(int key, int value) {
        TIntHashSet set = map.get(value);
        if (set == null)
            map.put(value, set = new TIntHashSet(slidingMeanValue));
//        else
//            slidingMeanValue = Math.max(5, (slidingMeanValue + set.size()) / 2);
        if (!set.add(key))
            throw new IllegalStateException("use update if you want to update " + key);
        size++;
    }

    public int peekValue() {
        if (size == 0)
            throw new IllegalStateException("collection is already empty!?");
        Entry<Integer, TIntHashSet> e = map.firstEntry();
        if (e.getValue().isEmpty())
            throw new IllegalStateException("internal set is already empty!?");
        return map.firstEntry().getKey();
    }

    public int peekKey() {
        if (size == 0)
            throw new IllegalStateException("collection is already empty!?");
        TIntHashSet set = map.firstEntry().getValue();
        if (set.isEmpty())
            throw new IllegalStateException("internal set is already empty!?");
        return set.iterator().next();
    }

    public int pollKey() {
        size--;
        if (size < 0)
            throw new IllegalStateException("collection is already empty!?");
        Entry<Integer, TIntHashSet> e = map.firstEntry();
        TIntHashSet set = e.getValue();
        TIntIterator iter = set.iterator();
        if (set.isEmpty())
            throw new IllegalStateException("internal set is already empty!?");
        int val = iter.next();
        iter.remove();
        if (set.isEmpty())
            map.remove(e.getKey());
        return val;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public int getSlidingMeanValue() {
        return slidingMeanValue;
    }

    @Override
    public String toString() {
        return "size " + size + " min=(" + peekKey() + "=>" + peekValue() + ")";
    }
}
于 2012-10-15T20:15:34.617 に答える
1

外部依存関係が必要かどうかを決定する必要があります。私はこのようなもののために私自身の実装をロールバックしません。

とは言うものの、あなたはこれを何のために使っているのか、そしてあなたがそれをどうするつもりなのかについてほとんど何も教えてくれませんでした。十分なデータがなければ、私たちがあなたに伝えることができるのはそれほど多くありません-あなたは実際にランダムな順序で要素にアクセスする必要がありますか?このコレクションはどれくらいの大きさになると思いますか?ニーズに合った適切なデータ構造を選択するのに十分なデータがありません。

そうは言っても、ここに私が検討するいくつかのオプションがあります。

  • ArrayListまたはPriorityQueue、実際にサポートする必要があるかどうかによって異なりますremove(Object)。あなたは?よろしいです?(サポートする必要があるremove(Object)場合でも、コレクションが小さいままである可​​能性が高い場合は、このオプションを選択します。)
  • TreeListリンク先ではなく、ApacheCommonsCollectionsですTreeList。名前にもかかわらず、実際にはソートされた順序を維持しませんが、O(log n)の追加、削除、およびリスト内の任意の場所からの取得をサポートします。バイナリ検索を使用すると、値の並べ替えられた部分に応じて、追加、削除、または検索のO((log n)^ 2)時間を達成できる可能性があります。
  • あなたTreeListがリンクした、または-あなたが私のようで、契約を気にかけている場合-で取得しListたカスタムグアバ。ListMultimapMultimaps.newListMultimap(new TreeMap<K, Collection<V>>, new Supplier<List<V>>() { public List<V> get() { return new ArrayList<V>(); }})

プリミティブボクシングにも関心がある場合、またはサードパーティの依存関係を許容できない場合は、独自のデータ構造を作成する以外に選択肢はありません。上記の実装の1つをプリミティブ型に適合させるだけですが、これは非常に苦痛になります。

最後に、あなたのユースケースを本当に聞きたいです。Guavaは、十分な需要がなかったか、より高度なデータ構造が本当に適切なユースケースを見たため、このようなことをサポートしていません。

于 2012-10-10T23:41:23.963 に答える
1

私はスキップリストを使用します-ツリーよりもメモリ効率が高く、重複を許可し、挿入と削除にO(logn)を提供しますインデックス付きスキップリストを実装することもできます。これにより、ツリーでは取得が難しいインデックス付きアクセスが可能になります。

于 2016-12-28T22:55:08.943 に答える
0

TreeMultimaphttps: //guava.dev/releases/19.0/api/docs/com/google/common/collect/TreeMultimap.htmlで良い経験があります

于 2012-10-10T20:29:46.533 に答える