8

データ構造の説明は次のとおりです。

getput、およびremoveメソッドを使用して通常のマップのように動作しますがsort、マップをソートするために呼び出すことができるメソッドがあります。ただし、マップはソートされた構造を記憶しているため、その後の sort の呼び出しははるかに高速になります ( の呼び出し間で構造があまり変化しない場合sort)。

例えば:

  • putメソッドを 1,000,000 回呼び出します。
  • メソッドを呼び出しますsort
  • putメソッドをあと 100 回呼び出します。
  • メソッドを呼び出しますsort

このメソッドを 2 回目に呼び出すとsort、マップの構造があまり変わっていないため、操作がはるかに高速になります。への呼び出し間でマップがソートされた順序を維持する必要がないことに注意してくださいsort

無理かもしれませんが、 O(1) getputremove操作を期待しています。TreeMapのようなものは、これらの操作に保証された O(log(n)) 時間コストを提供しますが、常にソートされた順序を維持します (sortメソッドなし)。

では、このデータ構造の設計は何ですか?

編集 1 - 上位 K エントリを返す

上記の一般的なケースに対する答えを聞くのは楽しいですが、私のユースケースはより具体的になりました。すべてをソートする必要はありません。上位の K 要素のみ。

ハッシュ テーブルの上位 Kエントリを効率的に返すためのデータ構造(マップ、辞書)

ありがとう!

4

6 に答える 6

8

「O(1) get、put、remove 操作」の場合、基本的に O(1) ルックアップが必要です。これはハッシュ関数を意味しますが (ご存じのとおり)、優れたハッシュ関数の要件は、簡単に並べ替えるという要件を破ることがよくあります。 . (隣接する値が同じバケットにマップされているハッシュ テーブルがある場合、多くの共通データで O(N) に縮退します。これは通常、ハッシュ関数で回避したい最悪のケースです。)

90% の方法でそこにたどり着く方法を考えることができます。ソートされた並列インデックスと一緒にハッシュテーブルを設定します。インデックスには、クリーンな部分 (順序付き) とダーティな部分 (順序なし) があります。インデックスは、キーを値 (またはハッシュテーブルに格納されている値への参照 - パフォーマンスまたはメモリ使用の観点から適切なもの) にマップします。ハッシュテーブルに追加すると、新しいエントリはダーティ リストの後ろにプッシュされます。ハッシュテーブルから削除すると、エントリは null になり、インデックスのクリーン部分とダーティ部分から削除されます。インデックスを並べ替えると、ダーティ エントリのみが並べ替えられ、インデックスの既に並べ替えられた「クリーンな」部分にマージされます。そして明らかに、インデックスを反復処理できます。

私が見る限り、これにより、削除操作を除くすべての場所で O(1) が得られ、標準コンテナー (少なくとも C++、Java、または Python によって提供される) を使用して実装するのは依然としてかなり簡単です。また、ダーティ インデックス エントリを並べ替えてから O(N) マージを実行できるようにするだけで、「2 番目の並べ替えの方が安価」な状態になります。これらすべてのコストは、明らかにインデックス用の余分なメモリと、それを使用する際の余分な間接化です。

于 2010-01-05T16:25:38.640 に答える
4

なぜ正確に sort() 関数が必要なのですか?
あなたがおそらく欲しくて必要としているのは、赤黒の木です。

http://en.wikipedia.org/wiki/Red-black_tree

これらのツリーは、指定したコンパレーターによって入力を自動的にソートします。それらは複雑ですが、優れた O(n) 特性を備えています。ツリー エントリをキーとしてハッシュ マップをディクショナリとして結合すると、データ構造が得られます。

Java では、SortedMap のインスタンスとして TreeMap として実装されます。

于 2010-01-26T22:32:50.720 に答える
1

順序付き辞書

Pythonの最近のバージョン(2.7、3.1)には、あなたが説明しているように聞こえる「順序付き辞書」があります。

公式の Python の「順序付き辞書」実装は、 PEP 372で説明されているように、以前のサードパーティの実装に触発されています。

参考文献:

于 2010-01-20T01:51:24.037 に答える
1

あなたが見ているのは、ソートされた順序で次のエントリへのポインタを持つハッシュテーブルです。リンクが挿入順ではなくソート順を追跡していることを除いて、Java の LinkedHashMap によく似ています。LinkedHashMap をラップし、並べ替えの実装で LinkedHashMap から TreeMap にエントリを転送してから、LinkedHashMap に戻すことで、実際にこれを完全に実装できます。

以下は、ツリー マップに転送するのではなく、配列リスト内のエントリを並べ替える実装です。Collection.sort で使用される並べ替えアルゴリズムは、新しいエントリを既に並べ替えられた部分にマージするのに適していると思います。

public class SortaSortedMap<K extends Comparable<K>,V> implements Map<K,V> {

    private LinkedHashMap<K,V> innerMap;

    public SortaSortedMap() {
        this.innerMap = new LinkedHashMap<K,V>();
    }

    public SortaSortedMap(Map<K,V> map) {
        this.innerMap = new LinkedHashMap<K,V>(map);
    }

    public Collection<V> values() {
        return innerMap.values();
    }

    public int size() {
        return innerMap.size();
    }

    public V remove(Object key) {
        return innerMap.remove(key);
    }

    public V put(K key, V value) {
        return innerMap.put(key, value);
    }

    public Set<K> keySet() {
        return innerMap.keySet();
    }

    public boolean isEmpty() {
        return innerMap.isEmpty();
    }

    public Set<Entry<K, V>> entrySet() {
        return innerMap.entrySet();
    }

    public boolean containsKey(Object key) {
        return innerMap.containsKey(key);
    }

    public V get(Object key) {
        return innerMap.get(key);
    }

    public boolean containsValue(Object value) {
        return innerMap.containsValue(value);
    }

    public void clear() {
        innerMap.clear();
    }

    public void putAll(Map<? extends K, ? extends V> m) {
        innerMap.putAll(m);
    }

    public void sort() {
        List<Map.Entry<K,V>> entries = new ArrayList<Map.Entry<K,V>>(innerMap.entrySet());
        Collections.sort(entries, new KeyComparator());
        LinkedHashMap<K,V> newMap = new LinkedHashMap<K,V>();
        for (Map.Entry<K,V> e: entries) {
            newMap.put(e.getKey(), e.getValue());
        }
        innerMap = newMap;
    }

    private class KeyComparator implements Comparator<Map.Entry<K,V>> {

        public int compare(Entry<K, V> o1, Entry<K, V> o2) {
            return o1.getKey().compareTo(o2.getKey());
        }

    }

}
于 2010-01-20T04:39:40.843 に答える
1

名前があるかどうかはわかりませんが、各アイテムの現在のインデックスをハッシュに保存できます。

つまり、 aHashMap< Object, Pair( Integer, Object ) > および aList<Object>オブジェクトがあります。

、リストの末尾または先頭にput追加し、データと挿入のインデックスをハッシュマップに挿入します。これはO(1)

場合はget、ハッシュマップからプルし、インデックスを無視します。これはO(1)

のときはremove、マップから引っ張ります。インデックスを取得して、リストからも削除します。これはO(1)

ときはsort、リストを並べ替えるだけです。並べ替え中にマップ内のインデックスを更新するか、並べ替えが完了した後に更新します。O(nlgn)これは線形ステップであるため、並べ替えには影響しません。O(nlgn + n) == O(nlgn)

于 2010-01-05T16:25:10.497 に答える
0

少なくともJavaコレクション(または非線形データ構造クラス)では、その正確な動作を伴うデータ構造分類を認識していません。おそらくあなたはそれを実装することができます、そしてそれは以後として知られるでしょうRudigerMap

于 2010-01-05T16:01:20.373 に答える