簡體   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