在一个数组中计算最大值和最小值

3
我有一个整数数组,需要找到数组中最大数字和最小数字的位置。我已经实现了这个功能,但是似乎这���是一个很好的方法。有没有人可以建议一种更好的方法来实现我的需求?
以下是我的代码:
int[] usageHours = { 3, 3, 5, 4, 0, 0, 2, 2, 4, 25, 158, 320, 212, 356, 401, 460, 480, 403, 298, 213, 102, 87, 34, 45 };
double myAverage = usageHours.Average();
int runningTotal = 0;
int runningMaxPosition = 0;

for (int i = 0; i < usageHours.Length; i++)
{
    if (usageHours[i] > runningTotal)
    {
        runningMaxPosition = i;
        runningTotal = usageHours[i];
    }
}

txtmax.Text = Convert.ToString(runningMaxPosition)+" With: "+Convert.ToString(runningTotal)+" Users";
txtAv.Text = Convert.ToString(myAverage);

感谢您的帮助和建议。现在我需要花一些时间学习和改进我的代码。 - Tumble
7个回答

7

那段代码大部分都没问题。我建议稍微改一下变量名,但仅此而已。你可以在同一个循环中计算最小值。我稍微修改了“if”条件以确保它们始终至少选择一个元素(即使所有值都是int.MinValue)。还有其他方法来处理这个问题,但这只是一个例子。如果你有一个空数组,你将得到max=min=0,两个索引均为-1。

int currentMax = 0;
int currentMaxIndex = -1;
int currentMin = 0;
int currentMinIndex = -1;

for (int i = 0; i < usageHours.Length; i++)
{
    if (currentMaxIndex == -1 || usageHours[i] > currentMax)
    {
        currentMaxIndex = i;
        currentMax = usageHours[i];
    }
    if (currentMinIndex == -1 || usageHours[i] < currentMin)
    {
        currentMinIndex = i;
        currentMin = usageHours[i];
    }
}

这里有一种使用可空值类型来表示“没有值”答案的替代方法:

int currentMax? = null;
int currentMaxIndex? = null;
int currentMin? = null;
int currentMinIndex? = null;

for (int i = 0; i < usageHours.Length; i++)
{
    if (currentMax == null || usageHours[i] > currentMax.Value)
    {
        currentMax = i;
        currentMax = usageHours[i];
    }
    if (currentMin == null || usageHours[i] < currentMin.Value)
    {
        currentMinIndex = i;
        currentMin = usageHours[i];
    }
}

如果你还没有接触过可空值类型,不用担心...


+1,不仅这非常有教育意义并且有助于理解算法,而且它也是最快的方法:O(n)。 - Darin Dimitrov
这是最快的方法。建议使用Linq方法会在同一数组上运行多个循环,这使它们不够高效,但在现代计算机和如此小的数组上,您不会注意到任何差异。 - Andrew
在数组中所有数字都是负数的情况下,使用minvalue和maxvalue而不是0是更明智的选择。 - TStamper
我会使用int?(即Nullable<int>)并将null作为您的标志值。此外,对于空数组的最大值,null似乎是一个合理的答案。 - Daniel Pryden
@Daniel:总的来说,我喜欢这个想法,但我想知道它是否对提问者有点复杂。我会进行编辑,建议它作为一种替代方案。 - Jon Skeet
显示剩余5条评论

2

这段代码用于查找最大值,看起来还不错。如果你使用的是C# 3或更高版本,则可以使用LINQ扩展方法(其中包括MinMaxAverage方法,在List上还有一个FindIndex方法等)。但我感觉你正在学习编程,因此有时候实现一些可能已经内置在框架中的东西也是一个很好的学习方法。


+1 是因为你提到学习编程而非仅使用框架。正在解决的问题的运行时间为O(n)。数组中需要检查所有节点。了解Linq方法的工作原理以及由于它们而不需要编写的代码是很好的。我猜这门课程希望学生们理解如何找到数据点,而不是理解存在哪些函数来找到数据点。 - NerdFury

1

我只是想提供一个简洁的解决方案来回答这个问题(为了完整性)。

在原始问题中,OP只要求最大值和最小值的索引。

让我们专注于这个问题。这是最有趣的问题,因为要找到最大值,我们可以简单地使用Enumerable.Max LINQ方法。同样适用于Min和Average。

让我们只提供最大值的索引,最小值的索引可以使用类似的代码检索。

int indexOfMax = Enumerable.Range(0, usageHours.Length).Aggregate(
    (indexOfMax, i) => (usageHours[i] > usageHours[indexOfMax] ? i : indexOfMax)
);

Aggregate括号内的委托将针对数组的每个索引执行。它以“到目前为止找到的最大值的索引”和当前索引作为参数。它返回“到目前为止找到的最大值的索引”。显然,在每次迭代中,“到目前为止找到的最大值的索引”只有在相应的数组元素大于先前的最大值时才会更改为当前索引。


0

删掉那段Linq代码,它没有按照你想要的方式工作

你可以让你的代码更加简洁一些

for (int i = 0; i < usageHours.Length; i++)
{
    if (usageHours[i] > usageHours[runningMaxPosition])
        runningMaxPosition = i;
}

它所做的不同之处在于省略了临时变量runningTotal。


他需要最大值和最小值的索引,而不仅仅是它们的值。 - Alex Reitbort
这不是返回最小值和最大值数值,而不是数组索引吗? - Ken White
这会得到最大值和最小值,但不会得到这些值的索引。 - NerdFury
改为更可能是更好答案的内容。 - John Boker
你可以使用 ((IList<int>)usageHours).IndexOf 来查找这两个值的索引。然而,我猜因为这是一个大学问题,他们希望你展示一个循环算法,因此不要使用内置的 Linq 函数来查找这些值。 - Travis Heseman

0
这样怎么样:
double average = usageHours.Average();
int maxPosition = Enumerable.Range(0, usageHours.Length).Max(i => usageHours[i]);
int minPosition = Enumerable.Range(0, usageHours.Length).Min(i => usageHours[i]);

2
你必须先学会走路才能跑步。这对于初学者来说太高级了。 - Jon B
这是O(3n),对数组进行了3次循环。我知道我对性能有一种不健康的痴迷,但我们不都是这样吗? - Andrew

0

你的代码不错,但如果所有值都小于零,它将无法工作。

试试这个:

int getArrayMaxPosition (double[] theArray) 
{    
    double maxVal = theArray[0];
    int ret = 0;
    int currentIndex = 0;

    foreach (double aValue in theArray) 
    {
        if (aValue > maxVal)
        {
             ret = currentIndex;
             maxVal = avalue;
        }
        currentIndex++;
    }

    return ret;
 }

0

正如在Jon的回答评论中提到的那样,Jon的解决方案确实是最好、最直接、最快捷的方法。

然而,如果您确实想使用Igor的解决方案,这里是其余部分(获取实际位置以及值):

int maxValue = Enumerable.Range(0, usageHours.Length).Max(i => usageHours[i]);
int maxPosition = Array.FindIndex(usageHours, i => i == maxValue);
int minValue = Enumerable.Range(0, usageHours.Length).Min(i => usageHours[i]);
int minPosition = Array.FindIndex(usageHours, i => i == minValue);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接