12

多くの基準でソート可能なデータセットのページングアルゴリズムを実装しようとしています。残念ながら、これらの基準の一部はデータベースレベルで実装できますが、一部はアプリレベルで実行する必要があります(別のデータソースと統合する必要があります)。ページング(実際には無限スクロール)の要件があり、ページング呼び出しごとにアプリレベルでデータセット全体を並べ替える手間を最小限に抑える方法を探しています。

絶対にソートする必要があるリストの部分のみをソートして、部分的なソートを行うための最良の方法は何ですか?std::partial_sort.NETライブラリで利用可能なC++の関数に相当するものはありますか?この問題をどのように解決すればよいですか?

編集:これが私がしようとしていることの例です:

いくつかの並べ替え基準に従って、1000要素セットの要素21〜40を取得する必要があるとします。並べ替えを高速化するために、そしてとにかく毎回データセット全体を調べる必要があるため(これは、ステートレスであるHTTPを介したWebサービスです)、データセット全体を注文する必要はありません。正しく注文するには、要素21〜40だけが必要です。3つのパーティションを作成するだけで十分です。要素1〜20、ソートされていません(ただし、すべて要素21未満)。要素21〜40、ソート済み; および要素41〜1000、ソートされていません(ただし、すべて要素40より大きい)。

4

3 に答える 3

5

わかった。私のコメントへの返信であなたが言ったことに基づいて、私が試みることは次のとおりです。

「4番目から6番目まで」と言って、3、2、1(ソートされていませんが、適切な4番目の要素よりも少ない)のようなものを取得できるようにしたいです。4、5、6 (ソート済みで、ソート済みリストの場合と同じ場所にあります); 8、7、9 (ソートされていませんが、すべて適切な 6 番目の要素よりも大きい)。

簡単にするために、リストに 10 を追加しましょう: 10、9、8、7、6、5、4、3、2、1。

したがって、クイック選択アルゴリズムを使用して i番目と k番目の要素を見つけることができます。上記の場合、i は 4 で、k は 6 です。もちろん、値 4 と 6 が返されます。リストを 2 回通過する必要があります。したがって、これまでの実行時間は O(2n) = O(n) です。もちろん、次の部分は簡単です。気になるデータには下限と上限があります。必要なことは、上限と下限の間にある要素を探して、リストをもう一度パスすることだけです。そのような要素が見つかった場合は、それを新しい List にスローします。最後に、関心のある i番目から k番目の要素のみを含む List を並べ替えます。

したがって、総実行時間は最終的に O(N) + O((ki)lg(ki)) になると思います

static void Main(string[] args) {
    //create an array of 10 million items that are randomly ordered
    var list = Enumerable.Range(1, 10000000).OrderBy(x => Guid.NewGuid()).ToList();

    var sw = Stopwatch.StartNew();
    var slowOrder = list.OrderBy(x => x).Skip(10).Take(10).ToList();
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
    //Took ~8 seconds on my machine

    sw.Restart();
    var smallVal = Quickselect(list, 11);
    var largeVal = Quickselect(list, 20);
    var elements = list.Where(el => el >= smallVal && el <= largeVal).OrderBy(el => el);
    Console.WriteLine(sw.ElapsedMilliseconds);
    //Took ~1 second on my machine
}

public static T Quickselect<T>(IList<T> list , int k) where T : IComparable {
    Random rand = new Random();
    int r = rand.Next(0, list.Count);
    T pivot = list[r];
    List<T> smaller = new List<T>();
    List<T> larger = new List<T>();
    foreach (T element in list) {
        var comparison = element.CompareTo(pivot);
        if (comparison == -1) {
            smaller.Add(element);
        }
        else if (comparison == 1) {
            larger.Add(element);
        }
    }

    if (k <= smaller.Count) {
        return Quickselect(smaller, k);
    }
    else if (k > list.Count - larger.Count) {
        return Quickselect(larger, k - (list.Count - larger.Count));
    }
    else {
        return pivot;
    }
}
于 2013-03-13T21:19:43.167 に答える
-1

List<T>.Sort(int, int, IComparer<T>)を使用できます。

inputList.Sort(startIndex, count, Comparer<T>.Default);
于 2013-03-13T20:11:44.207 に答える
-2

Array.Sort()には、配列のサブセットをソートできる引数indexと引数を受け入れるオーバーロードがあります。lengthについても同様ですList

IEnumerableもちろん、直接ソートすることはできません。

于 2013-03-13T20:12:57.837 に答える