[英]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.