简体   繁体   English

找到 INT 数组的第 N 个最大数的最快方法是什么?

[英]What is the fastest way to find Nth biggest number of an INT array?

I want a faster function to find the Nth biggest number of an Int array in C#.我想要一个更快的函数来查找 C# 中 Int 数组的第 N 个最大数。 This function takes N and Array and returns index of that number.此函数接受 N 和 Array 并返回该数字的索引

Here is what i have already.这是我已经拥有的。 It simply sorts the array and then returns the index of that number.它只是对数组进行排序,然后返回该数字的索引。 It works perfectly but I'm not sure if this is the fastest way.它工作得很好,但我不确定这是否是最快的方法。 it seems logical to be an algorithm without complete sorting.没有完全排序的算法似乎是合乎逻辑的。

static int myFunction(int[] array, int N){
    int[] indexes = new int[array.Length];
    for (int i = 0; i < indexes.Length; i++)
        indexes[i] = i;

    for (int i = 0; i < array.Length; i++)
    {
        for (int j = i + 1; j < array.Length; j++)
        {
            if (array[i] < array[j])
            {
                int m = array[j];
                array[j] = array[i];
                array[i] = m;

                m = indexes[j];
                indexes[j] = indexes[i];
                indexes[i] = m;
            }
        }
    }
    return indexes[N];
}

some results:一些结果:

myFunction(new int[] { 1, 3, 2, 0, 10 }, 0); //returns 4 (index of 10)
myFunction(new int[] { 1, 3, 2, 0, 10 }, 1); //returns 1 (index of 3)
myFunction(new int[] { 1, 3, 2, 0, 10 }, 2); //returns 2 (index of 2)

Randomized quickselect algorithm works in average case complexity O(n).随机快速选择算法在平均案例复杂度 O(n) 下工作。 Practically it's very rare to be O(n^2).实际上,O(n^2) 是非常罕见的。 It uses quicksort's partition function它使用快速排序的分区功能

If your array has a size of a zillion numbers and you need the fifth largest number then you are sorting a lot of numbers that you won't need.如果您的数组有无数个数字,而您需要第五大数字,那么您正在对很多不需要的数字进行排序。

Wouldn't it be faster to keep an ascending sorted sequence of length n (linked list?), and for every element check if it is larger than the first one (which is the smallest in the ascending order保持长度为 n 的升序排序序列(链表?)是否会更快,并且对于每个元素检查它是否大于第一个(升序中最小的元素)

  • If smaller: skip to the next element in your large array如果较小:跳到大数组中的下一个元素
  • If larger: remove the smallest one from your sorted array which is the first element and insert the larger element in the proper place, keep the array sorted.如果较大:从排序数组中删除最小的元素,即第一个元素,并将较大的元素插入适当的位置,保持数组排序。

After having scanned your complete array, the first element in your sorted sequence is the one you are looking for.扫描完整数组后,排序序列中的第一个元素就是您要查找的元素。

Most comparisons are only with the first element of your sorted array.大多数比较仅与排序数组的第一个元素进行。 You'll have to change the array N-times, one time for the N largest numbers.您必须更改数组 N 次,一次更改 N 个最大的数字。 A change of the array is to remove the first element (the smallest) and find the place where to insert the new element to keep the array sorted数组的一个变化是移除第一个元素(最小的)并找到插入新元素的地方以保持数组排序

Correction: my statement that the array has to be changed N-time is incorrect.更正:我关于数组必须更改 N 次的说法是不正确的。 This can be seen most easily when offering an array sorted in ascending order: every compared number will be larger than the smallest in the N-size array, and thus cause a replace这在提供按升序排序的数组时最容易看出:每个比较的数字都将大于 N 大小数组中的最小数字,从而导致替换

This would be the implementation of @HaraldDutch's answer.这将是@HaraldDutch 答案的实现。

int get(int[] array, int n)
{
    var comparer = Comparer<int>.Create((x, y) => array[x].CompareTo(array[y]));    //compare the array entries, not the indices
    var highestIndices = new SortedSet<int>(comparer);
    for (var i = 0; i < array.Length; i++)
    {
        var entry = array[i];
        if (highestIndices.Count < n) highestIndices.Add(i);
        else if (array[highestIndices.Min] < entry)
        {
            highestIndices.Remove(highestIndices.Min);
            highestIndices.Add(i);
        }
    }

    return highestIndices.Min;
}

You'd have to pass in 1 instead of 0 though.不过,您必须传入 1 而不是 0。

you need to use Selection algorithm https://en.wikipedia.org/wiki/Selection_algorithm你需要使用选择算法https://en.wikipedia.org/wiki/Selection_algorithm

here nice slides: https://c3p0demo.googlecode.com/svn/trunk/scalaDemo/script/Order_statistics.ppt generally algorithm:这里有不错的幻灯片: https ://c3p0demo.googlecode.com/svn/trunk/scalaDemo/script/Order_statistics.ppt 一般算法:

Select(A,n,i):
    Divide input into ⌈n/5⌉ groups of size 5.

    /* Partition on median-of-medians */
    medians = array of each group’s median.
    pivot = Select(medians, ⌈n/5⌉, ⌈n/10⌉)
    Left Array L and Right Array G = partition(A, pivot)

    /* Find ith element in L, pivot, or G */
    k = |L| + 1
    If i = k, return pivot
    If i < k, return Select(L, k-1, i)
    If i > k, return Select(G, n-k, i-k)

You could create a heap of size N which has the largest number as its first element (as opposed to the smallest one usually given).你可以创建一个大小为 N 的堆,它的第一个元素是最大的(而不是通常给出的最小的)。 Then you walk through your integer array, and whenever you have an element smaller than the largest member of the heap, you insert it into the heap.然后遍历整数数组,只要有一个元素小于堆的最大成员,就将其插入堆中。 If that makes the heap exceed a size of N, you remove the largest member in it.如果这使得堆超过 N 的大小,则删除其中最大的成员。

That should be one of the cheapest ways to do this.这应该是最便宜的方法之一。 Specific "nth largest of m" algorithms may beat it, but probably not asymptotically.特定的“m 中第 n 大”算法可能会击败它,但可能不会渐近。

Your sorting algorithm is by far not the fastest.您的排序算法目前还不是最快的。 You should google for "Quicksort" for a much, much faster algorithm.您应该在谷歌上搜索“Quicksort”以获得更快的算法。

And after you have implemented Quicksort, you would then think about whether you really needed to sort the complete array.而当你实现了快速排序之后,你就会考虑是否真的需要对整个数组进行排序。 Say you want to find the 20 largest out of 10,000 numbers, why would you sort the remaining 9,980 numbers?假设你要从 10,000 个数字中找出最大的 20 个,为什么要对剩余的 9,980 个数字进行排序? You can easily modify Quicksort so that it will find the N largest numbers but mostly ignore the rest.您可以轻松修改 Quicksort,使其找到 N 个最大的数字,但大部分忽略其余数字。

Maybe this could help someone.也许这可以帮助某人。 finding the nth largest number in an int array.在 int 数组中找到第 n 个最大的数字。

            int[] arr = new int[] { 3, 2, 1, 5 };
            Array.Sort(arr);
            int elemCount = 0;
            int? thirdLargestNumber = null;
            foreach (var elem in arr)
            {
                var temp = arr.Skip(elemCount).ToArray();
                if (temp.Length == 3) //replace `3` with variable.
                { 
                    thirdLargestNumber = temp[0];
                    break;
                }
                elemCount++;
            }
            Console.WriteLine($"Third largest number = {thirdLargestNumber}");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM