Is there a C# equivalent to C++ std::partial_sort?

前端 未结 3 779
孤城傲影
孤城傲影 2021-02-05 20:06

I\'m trying to implement a paging algorithm for a dataset sortable via many criteria. Unfortunately, while some of those criteria can be implemented at the database level, some

3条回答
  •  执笔经年
    2021-02-05 20:54

    OK. Here's what I would try based on what you said in reply to my comment.

    I want to be able to say "4th through 6th" and get something like: 3, 2, 1 (unsorted, but all less than proper 4th element); 4, 5, 6 (sorted and in the same place they would be for a sorted list); 8, 7, 9 (unsorted, but all greater than proper 6th element).

    Lets add 10 to our list to make it easier: 10, 9, 8, 7, 6, 5, 4, 3, 2, 1.

    So, what you could do is use the quick select algorithm to find the the ith and kth elements. In your case above i is 4 and k is 6. That will of course return the values 4 and 6. That's going to take two passes through your list. So, so far the runtime is O(2n) = O(n). The next part is easy, of course. We have lower and upper bounds on the data we care about. All we need to do is make another pass through our list looking for any element that is between our upper and lower bounds. If we find such an element we throw it into a new List. Finally, we then sort our List which contains only the ith through kth elements that we care about.

    So, I believe the total runtime ends up being O(N) + O((k-i)lg(k-i))

    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(IList list , int k) where T : IComparable {
        Random rand = new Random();
        int r = rand.Next(0, list.Count);
        T pivot = list[r];
        List smaller = new List();
        List larger = new List();
        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;
        }
    }
    

提交回复
热议问题