【问题标题】:C# How to make recursive function to return the nth most common integer in an array of integersC#如何使递归函数返回整数数组中第n个最常见的整数
【发布时间】:2016-10-11 07:02:03
【问题描述】:

C#如何使递归函数返回整数数组中第n个最常见的整数

我正在使用 c#,我正在寻找最节省内存的方法,以按整数列表在整数数组中出现的频率对整数列表进行排序,然后返回第 n 个数组元素,其中 nth 是整数,表示降序键选择(最常用的整数、第二常用的整数、第三常用的整数等。

我可以使用 linq 和类似的东西来做到这一点......

public static void Main(string[] args)
{
    int x = NthMostCommon(new int[] { 5, 4, 3, 2, 1, 5, 4, 3, 2, 5, 4, 3, 5, 4, 5 }, 2);
    Console.WriteLine(x);
}

private static int NthMostCommon(int[] a, int k)
{
    int result = 0;
    var query = a.GroupBy(item => item).OrderByDescending(g => g.Count());
    if (query.Count() >= k)
    {
        result = query.ElementAt(k - 1).Key;
    }
    return result;
} 

这行得通,但有人告诉我,在处理较大的整数数组时,这不是获得所需结果的最节省内存的方法。我看不到如何减少内存占用。无论大小如何,我都必须迭代整个数组。是的?

有什么想法吗?

提前致谢。

【问题讨论】:

  • 嗯,我认为这只是一个关于排序算法的问题。关于该领域有大量文献,我认为这个问题超出了 SO 目的。
  • 我认为第 i 个最常见和第 i + 1 个最常见之间的循环关系并不简单。
  • 我认为内存膨胀实际上来自GroupBy,另一方面我不相信递归操作会更有效(甚至相反)。
  • 我从审阅者那里得到的评论是,当针对数组中的大量元素运行时,代码使用了太多的内存。我应该分析代码在执行过程中是如何分配和释放内存的。我只是不知道如何让它更有效地记忆。
  • 函数“递归”的意义何在?可以消除这个要求吗?

标签: c# linq sorting


【解决方案1】:

这篇文章可能会对您有所帮助。

http://www.developerfusion.com/article/84468/linq-to-log-files/

最常见的整数可能超过 1 个整数(请参阅我的代码中的 int 数组),因此我使函数返回 int[] 而不仅仅是 int。

我也有 GroupBy,它在最坏的情况下(输入数组中的相同整数)可能与前一个一样有效。您也可以重写它。

    public static void Main(string[] args)
    {
        int[] x = NthMostCommon(new int[] { 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6 }, 2);
        Console.WriteLine(x);
    }

    private static int[] NthMostCommon(int[] a, int k)
    {

        var query = GroupAndCount(a)
            .GroupBy(x => x.Value)
            .ToDictionary(x => x.Key, x => x.Select(n => n.Key))
            .OrderByDescending(x => x.Key);
        if (query.Count() >= k)
        {
            return query.ElementAt(k-1).Value.ToArray();
        }
        return null;
    }

    public static IEnumerable<KeyValuePair<T, int>> GroupAndCount<T>
    (IEnumerable<T> source)
    {
        Dictionary<T, int> dictionary =
            new Dictionary<T, int>();
        foreach (T element in source)
        {
            if (dictionary.ContainsKey(element))
            {
                dictionary[element]++;
            }
            else {
                dictionary[element] = 1;
            }
        }
        return dictionary;
    }

【讨论】:

    【解决方案2】:

    其中k Counting Sort开头并修改。

    计数排序需要 O(n + k) 内存和 O(n + k) 时间。

    在计算机科学中,计数排序是一种根据小整数键对对象集合进行排序的算法;也就是整数排序算法。它通过计算具有每个不同键值的对象的数量,并对这些计数使用算术来确定每个键值在输出序列中的位置。

    它的运行时间与item的个数和最大最小key值之差呈线性关系,所以只适合直接用在key的变化不显着大于的情况下项目。但是,它通常用作另一种排序算法(基数排序)中的子程序,可以更有效地处理更大的键

    根据频率对项目进行排序后,只需遍历结果即可。


    如果确实“要求”是递归的,则可以将过程循环代码转换为递归调用,但会牺牲堆栈帧。使用 LINQ(提供各种高阶函数)通常可以轻松消除递归的需要。

    【讨论】:

    • 递归要求可以被消除,因为这是一个建议,但在这里似乎没有优点。
    猜你喜欢
    • 2019-05-27
    • 2013-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-27
    相关资源
    最近更新 更多