繁体   English   中英

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

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

我想要一个更快的函数来查找 C# 中 Int 数组的第 N 个最大数。 此函数接受 N 和 Array 并返回该数字的索引

这是我已经拥有的。 它只是对数组进行排序,然后返回该数字的索引。 它工作得很好,但我不确定这是否是最快的方法。 没有完全排序的算法似乎是合乎逻辑的。

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];
}

一些结果:

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)

随机快速选择算法在平均案例复杂度 O(n) 下工作。 实际上,O(n^2) 是非常罕见的。 它使用快速排序的分区功能

如果您的数组有无数个数字,而您需要第五大数字,那么您正在对很多不需要的数字进行排序。

保持长度为 n 的升序排序序列(链表?)是否会更快,并且对于每个元素检查它是否大于第一个(升序中最小的元素)

  • 如果较小:跳到大数组中的下一个元素
  • 如果较大:从排序数组中删除最小的元素,即第一个元素,并将较大的元素插入适当的位置,保持数组排序。

扫描完整数组后,排序序列中的第一个元素就是您要查找的元素。

大多数比较仅与排序数组的第一个元素进行。 您必须更改数组 N 次,一次更改 N 个最大的数字。 数组的一个变化是移除第一个元素(最小的)并找到插入新元素的地方以保持数组排序

更正:我关于数组必须更改 N 次的说法是不正确的。 这在提供按升序排序的数组时最容易看出:每个比较的数字都将大于 N 大小数组中的最小数字,从而导致替换

这将是@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;
}

不过,您必须传入 1 而不是 0。

你需要使用选择算法https://en.wikipedia.org/wiki/Selection_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)

你可以创建一个大小为 N 的堆,它的第一个元素是最大的(而不是通常给出的最小的)。 然后遍历整数数组,只要有一个元素小于堆的最大成员,就将其插入堆中。 如果这使得堆超过 N 的大小,则删除其中最大的成员。

这应该是最便宜的方法之一。 特定的“m 中第 n 大”算法可能会击败它,但可能不会渐近。

您的排序算法目前还不是最快的。 您应该在谷歌上搜索“Quicksort”以获得更快的算法。

而当你实现了快速排序之后,你就会考虑是否真的需要对整个数组进行排序。 假设你要从 10,000 个数字中找出最大的 20 个,为什么要对剩余的 9,980 个数字进行排序? 您可以轻松修改 Quicksort,使其找到 N 个最大的数字,但大部分忽略其余数字。

也许这可以帮助某人。 在 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