web-dev-qa-db-ja.com

順序を維持する実装のリスト

提供されたListに基づいて順序を維持する既存のComparator実装がJavaにありますか?

次の方法で使用できるもの:

Comparator<T> cmp = new MyComparator<T>();
List<T> l = new OrderedList<T>(cmp);
l.add(someT);

someTが挿入され、リスト内の順序がcmpに従って維持されるようにします。

(@andersojの提案では、もう1つのリクエストで質問を完了しています)

また、要素を削除せずにリストをソートされた順序でトラバースできるようにしたい、つまり:

T min = Const.SMALLEST_T;
for (T e: l) {
  assertTrue(cmp.compare(min, e) >= 0);
  min = e;
}

合格する必要があります。

すべての提案を歓迎します(Collections.sort順不同の完全なリストでは)、しかし、私はJava.*または最終的にorg.Apache.*現在、新しいライブラリを導入するのは難しいため。

注:(UPDATE4)この種類のリストを実装すると、パフォーマンスが不十分になることに気付きました。 2つの一般的なアプローチがあります。

  1. リンク構造(一種の)Bツリーまたは類似のものを使用する
  2. 配列と挿入を使用する(バイナリ検索を使用)

いいえ1. CPUキャッシュミスに問題があります。いいえ2.配列内の要素のシフトに問題があります。

UPDATE2:TreeSetは、提供されたコンパレータ(MyComparator)が等しいかどうかをチェックし、それに基づいて、要素が等しいと見なして除外します。 「一意性」フィルタリングではなく、順序付けのためだけにそのコンパレータが必要です(自然な順序付けによる要素が等しくないため)

UPDATE3:PriorityQueueListとして機能しません私が必要とするのは、要素を「ソート」された順序でトラバースする方法がないためです。要素をソートされた順序で取得するには、コレクションから削除する必要があります。

更新:

同様の質問:
Javaに適したソートリスト
Javaのソートされた配列リスト

16
Op De Cirkel

新しい要件への対応。私には2つの可能性があります。

  • PriorityQueueのJavaDocが言うことを実行します。

    このクラスとその反復子は、CollectionおよびIteratorインターフェースのすべてのオプションメソッドを実装します。メソッドiterator()で提供されるイテレータは、特定の順序で優先度キューの要素をトラバースすることが保証されていません。順序付けられた走査が必要な場合は、Arrays.sort(pq.toArray())の使用を検討してください。

    私はこれがあなたの要件を与えられた最高のパフォーマンスをもたらすと思います。これが受け入れられない場合は、達成しようとしていることをよりよく説明する必要があります。

  • Listを作成します。このリストは、新しい要素の追加時に自動的にソートされます。これは本当に大変です...リンク構造を使用すると、効率的な挿入ソートを実行できますが、局所性は悪いです。配列支援構造を使用した場合、挿入ソートは面倒ですが、トラバーサルの方が優れています。反復/走査が頻繁でない場合は、リストのコンテンツを並べ替えずに保持し、オンデマンドでのみ並べ替えることができます。

  • 私が提案したようにPriorityQueueの使用を検討してください。順番に反復する必要がある場合は、ラッパー反復子を作成してください:

    _class PqIter implements Iterator<T>
    {
       final PriorityQueue<T> pq;
       public PqIter(PriorityQueue <T> source)
       {
         pq = new PriorityQueue(source); 
       }
    
       @Override
       public boolean hasNext()
       {
         return pq.peek() != null
       }
    
       @Override
       public T next()
       { return pq.poll(); }
    
       @Override
       public void remove()
       { throw new UnsupportedOperationException(""); }
    }
    _
  • Guavaの TreeMultiSet を使用します。次のコードをIntegerでテストしましたが、正しく機能しているようです。

    _import com.google.common.collect.TreeMultiset;
    
    public class TreeMultiSetTest { 
      public static void main(String[] args) {
        TreeMultiset<Integer> ts = TreeMultiset.create();
        ts.add(1);  ts.add(0); ts.add(2);
        ts.add(-1); ts.add(5); ts.add(2);
    
        for (Integer i : ts) {
          System.out.println(i);
        } 
      } 
    }
    _

以下は、SortedSetを使用するときに発生していた一意性/フィルタリングの問題に対処しています。イテレータも必要なので、これは機能しません。

本当に必要なものが順序付けられたlistのようなものである場合、 PriorityQueue を使用できます。

_Comparator<T> cmp = new MyComparator<T>();
PriorityQueue<T> pq = new PriorityQueue<T>(cmp);
pq.add(someT);
_

APIドキュメントがさまざまな操作の時間プロパティについて述べていることに注意してください。

実装メモ:この実装は、エンキューおよびデキューのメソッド(offerpollremove()およびadd); remove(Object)およびcontains(Object)メソッドの線形時間。および定数検索メソッドの時間(peekelement、およびsize)。

また、PriorityQueueによって生成されたイテレータは、期待どおりに動作しないことにも注意してください。

メソッドiterator()で提供されるIteratorは、特定の順序で優先度キューの要素をトラバースすることが保証されていません。順序付けられた走査が必要な場合は、Arrays.sort(pq.toArray())の使用を検討してください。

Guavaが MinMaxPriorityQueue を提供していることに気づきました。この実装は、JDKのPriorityQueueで提供されるリンクされたフォームではなく、配列でサポートされているため、タイミングの動作が異なる可能性があります。パフォーマンスに敏感な何かをしている場合は、確認することをお勧めします。ノートは、わずかに異なる(線形および対数)big-O時間を示しますが、それらすべての時間も制限されているはずです。

順序付けを維持するList実装自体はありませんが、探しているのは SortedSet の実装です。 TreeSet が最も一般的です。もう1つの実装であるConcurrentSkipListSetは、より具体的な用途向けです。 SortedSetは順序付けを提供しますが、Listのように重複したエントリは許可しないことに注意してください。

参照:

9
andersoj

おそらく TreeSet を使用する必要があります。

要素は、使用されるコンストラクターに応じて、自然な順序を使用して、またはセットの作成時に提供されるコンパレーターによって順序付けられます。

例:

Comparator<T> cmp = new MyComparator<T>();
TreeSet<T> t = new TreeSet<T>(cmp);
l.add(someT);

これはsetなので、重複したエントリは許可されないことに注意してください。これは、特定のユースケースで機能する場合と機能しない場合があります。

17
beerbajay