假设我有一组数字:[2,3,3,4,2,2,5,6,7,2]
在该数组中找到最小值或最大值的最佳方法是什么?
现在,为了获得最大值,我循环遍历数组,并将变量重置为该值,如果它大于现有值:
var myArray:Array /* of Number */ = [2,3,3,4,2,2,5,6,7,2];
var maxValue:Number = 0;
for each (var num:Number in myArray)
{
if (num > maxValue)
maxValue = num;
}
这似乎不是执行此操作的最佳方式(我尽可能避免循环)。
答案 0 :(得分:81)
其他人的理论答案都很整洁,但让我们务实。 ActionScript提供了您需要的工具,因此在这种情况下甚至不必编写循环!
首先,请注意Math.min()
和Math.max()
可以使用任意数量的参数。此外,了解apply()
对象可用的Function
方法非常重要。它允许您使用Array
将参数传递给函数。让我们利用两者:
var myArray:Array = [2,3,3,4,2,2,5,6,7,2];
var maxValue:Number = Math.max.apply(null, myArray);
var minValue:Number = Math.min.apply(null, myArray);
这是最好的部分:“循环”实际上是使用本机代码(在Flash Player内部)运行的,因此它比使用纯ActionScript循环搜索最小值或最大值更快。
答案 1 :(得分:30)
没有任何可靠的方法可以在不测试每个值的情况下获得最小值/最大值。你不想尝试排序或类似的东西,遍历数组是O(n),这比一般情况下任何排序算法都要好。
答案 2 :(得分:27)
如果
然后有一个算法可以找到3n / 2个比较中的最小值和最大值。我们需要做的是成对处理数组的元素。应将该对中较大的一对与当前最大值进行比较,并将该对中较小的一对与当前最小值进行比较。此外,如果数组包含奇数个元素,则需要特别小心。
在c ++代码中(借用Mehrdad的一些代码)。
struct MinMax{
int Min,Max;
}
MinMax FindMinMax(int[] array, int start, int end) {
MinMax min_max;
int index;
int n = end - start + 1;//n: the number of elements to be sorted, assuming n>0
if ( n%2 != 0 ){// if n is odd
min_max.Min = array[start];
min_max.Max = array[start];
index = start + 1;
}
else{// n is even
if ( array[start] < array[start+1] ){
min_max.Min = array[start];
min_max.Max = array[start+1];
}
else{
min_max.Min = array[start+1];
min_max.Max = array[start];
}
index = start + 2;
}
int big, small;
for ( int i = index; i < n-1; i = i+2 ){
if ( array[i] < array[i+1] ){ //one comparison
small = array[i];
big = array[i+1];
}
else{
small = array[i+1];
big = array[i];
}
if ( min_max.Min > small ){ //one comparison
min_max.Min = small;
}
if ( min_max.Max < big ){ //one comparison
min_max.Max = big;
}
}
return min_max;
}
很容易看出它所需的比较次数是3n / 2。循环运行n / 2次,并且在每次迭代中执行3次比较。这可能是最佳的。在这一刻,我无法指出这一点。 (但是,我想我已经在某处看到过这方面的证据。)
上面Mehrdad给出的递归解决方案可能也实现了这种最小数量的比较(最后一行需要改变)。但是,通过相同数量的比较,迭代解决方案将始终击败递归解决方案,因为他提到了函数调用的开销。然而,如果只关心找到一些数字的最小值和最大值(正如Eric Belair所做的那样),没有人会注意到今天的计算机与上述任何方法有任何区别。对于大型阵列,差异可能很大。
虽然这个解决方案和Matthew Brubaker给出的解决方案具有O(n)复杂性,但在实践中应该仔细评估所涉及的隐藏常数。他的解决方案中的比较次数是2n。与2n比较相比,使用3n / 2比较的解决方案获得的加速将是显而易见的。
答案 3 :(得分:19)
除非对数组进行排序,否则这将是您获得的最佳选择。如果它已排序,只需取第一个和最后一个元素。
当然,如果它没有排序,那么首先排序并抓住第一个和最后一个保证效率低于仅循环一次。即使是最好的排序算法也必须多次查看每个元素(每个元素的平均O(log N)次。这就是O(N * Log N)总数。一次扫描的简单只是O(N)。
如果您想快速访问数据结构中的最大元素,请查看堆,以便有效地保持对象的某种顺序。
答案 4 :(得分:12)
你必须遍历数组,没有其他方法来检查所有元素。只需对代码进行一次校正 - 如果所有元素都为负数,则maxValue最后为0。您应该使用整数的最小可能值对其进行初始化。
如果你要多次搜索数组,最好先对它进行排序,而不是搜索更快(二进制搜索),最小和最大元素只是第一个和最后一个。
答案 5 :(得分:4)
取决于你所谓的“最佳”。从理论的角度来看,在确定性的图灵机中,你不能在O(n)
以内解决问题。
天真算法太循环并且更新min,max。但是,如果你想同时获得最小值,最大值(由于函数调用开销,它不一定更快),递归解决方案比朴素算法需要更少的比较。
struct MinMax{
public int Min,Max;
}
MinMax FindMinMax(int[] array, int start, int end) {
if (start == end)
return new MinMax { Min = array[start], Max = array[start] };
if (start == end - 1)
return new MinMax { Min = Math.Min(array[start], array[end]), Max = Math.Max(array[start], array[end]) } ;
MinMax res1 = FindMinMax(array, start, (start + end)/2);
MinMax res2 = FindMinMax(array, (start+end)/2+1, end);
return new MinMax { Min = Math.Min(res1.Min, res2.Min), Max = Math.Max(res1.Max, res2.Max) } ;
}
最简单的解决方案是排序并获取第一个和最后一个项目,尽管它显然不是最快的;)
在性能方面,找到最小或最大值的最佳解决方案是您编写的简单算法(使用单个循环)。
答案 6 :(得分:3)
Math.max()实际上是as3代码编译成AVM2操作码,因此不是更多&#34; native&#34;比任何其他as3代码。因此,它不一定是最快的实施。
实际上,鉴于它适用于Array类型,它比精心编写的代码使用Vector:
慢我使用gskinner的PerformanceTest(Vector和Array填充相同的随机数)对Math.max的几个天真的Vector和Array实现进行了快速基准比较。 使用最新的AIR SDK /发布播放器(使用AIR SDK 14编译的Flash播放器WIN 14,0,0,122 RELEASE),最快的Vector实现似乎比Math.max快3倍以上:
对于1,000,000个值,平均为3.5 ms,而Math.max()的平均值为11 ms:
function max(values:Vector.<Number>):Number
{
var max:Number = Number.MIN_VALUE;
var length:uint = values.length;
for (var i:uint = 0; i < length ; ++i)
if (values[i] > max)
max = values[i];
return max;
}
结论是,如果你担心性能,你应该首先在任何地方使用Vector over Array,而不是总是依赖于默认实现,特别是当它们强制使用Array时
PS:使用for each()循环的相同实现速度慢了12倍......!
答案 7 :(得分:2)
如果您正在构建一次,并希望只找到一次最大值,那么迭代是您可以做的最好的。
如果要修改数组并偶尔想知道最大元素,则应使用Priority Queue。其中一个最好的数据结构是Fibonacci Heap,如果这太复杂,请使用Binary Heap,但速度较慢但仍然很好。
要查找最小值和最大值,只需构建两个堆并更改其中一个数字的符号。
答案 8 :(得分:2)
这取决于实际应用要求。
如果您的问题仅仅是假设,那么基本原理已经解释过了。这是典型的搜索与排序问题。已经提到过,从算法上来说,在这种情况下你不会比O(n)更好。
但是,如果你正在寻找实际用途,事情会变得更有趣。然后,您需要考虑数组的大小,以及添加和删除数据集所涉及的过程。在这些情况下,最好在插入/移除时通过动态排序来计算“命中”。插入预先排序的数组并不昂贵。
对Min Max请求的最快查询响应将始终来自已排序的数组,因为正如其他人所提到的那样,您只需要使用第一个或最后一个元素 - 给您一个O(1)成本。
有关计算成本和Big O表示法的更多技术解释,请查看维基百科文章here。
尼克。
答案 9 :(得分:1)
请注意,对数组进行排序只会比循环到某个大小的数组更快。如果你的阵列很小(并且它会像任何时候一样)那么你的解决方案就完全没问题了。但是如果它可能变得太大,你应该使用条件来在数组很小时使用排序方法,并在它太大时使用正常迭代
答案 10 :(得分:0)
最短路:
Math.min.apply(NULL,数组); //这将从数组中返回最小值 Math.max.apply(NULL,数组); //这将从数组返回最大值
获得分钟&amp; amp;数组的最大值
function maxVal(givenArray):Number
{
var max = givenArray[0];
for (var ma:int = 0; ma<givenArray.length; ma++)
{
if (givenArray[ma] > max)
{
max = givenArray[ma];
}
}
return max;
}
function minVal(givenArray):Number
{
var min = givenArray[0];
for (var mi:int = 0; mi<givenArray.length; mi++)
{
if (givenArray[mi] < min)
{
min = givenArray[mi];
}
}
return min;
}
如您所见,这两个函数中的代码非常相似。该函数设置一个变量--max(或min),然后通过循环遍历数组,检查每个下一个元素。如果下一个元素高于当前值,则将其设置为max(或min)。最后,返回号码。
答案 11 :(得分:0)
如果你想同时找到最小值和最大值,可以按如下方式修改循环:
int min = int.maxValue;
int max = int.minValue;
foreach num in someArray {
if(num < min)
min = num;
if(num > max)
max = num;
}
这应该达到O(n)时间。
答案 12 :(得分:0)
有很多方法可以做到。
How to find max. and min. in array using minimum comparisons?
如果你真的对速度,运行时间和比较次数,也可参考 http://www.geeksforgeeks.org/maximum-and-minimum-in-an-array/
答案 13 :(得分:0)
算法MaxMin(第一个,最后一个,最大值,最小值)
//此算法存储最高和最低元素
//全局变量max和min中全局数组A的值
// tmax和tmin是临时全局变量
{
if (first==last) //Sub-array contains single element
{
max=A[first];
min=A[first];
}
else if(first+1==last) //Sub-array contains two elements
{
if(A[first]<A[Last])
{
max=a[last]; //Second element is largest
min=a[first]; //First element is smallest
}
else
{
max=a[first]; //First element is Largest
min=a[last]; //Second element is smallest
}
}
else
//sub-array contains more than two elements
{
//Hence partition the sub-array into smaller sub-array
mid=(first+last)/2;
//Recursively solve the sub-array
MaxMin(first,mid,max,min);
MaxMin(mid+1,last,tmax,tmin);
if(max<tmax)
{
max=tmax;
}
if(min>tmin)
{
min=tmin;
}
}
}
答案 14 :(得分:0)
以下是o(n)的解决方案: -
public static void findMaxAndMinValue(int A[]){
int min =0, max = 0;
if(A[0] > A[1] ){
min = A[1];
max = A[0];
}else{
max = A[1];
min = A[0];
}
for(int i = 2;i<A.length ;i++){
if(A[i] > max){
max = A[i];
}
if(min > A[i]){
min = A[i];
}
}
System.out.println("Maxinum Value is "+min+" & Minimum Value is "+max);
}
答案 15 :(得分:0)
惊讶没有人提到这里的并行性。
如果你真的有一个巨大的数组,你可以在子范围上使用parallel-for。 最后比较所有子范围。 但并行性也会给宽度带来一些损失,所以这不会在小数组上进行优化。但是,如果您拥有庞大的数据集,它就会开始变得有意义,并且您可以将时间分割减少到接近执行测试的线程数量。
答案 16 :(得分:0)
从数组中查找最大值 让我们看看如何通过单个功能获得最小值,最大值
public void findMaxValue(){
int[] my_array = {1,2,,6,5,8,3,9,0,23};
int max = my_array[0];
for(int i=1; i<my_array.length; i++)
{
if(my_array[i] > max)
max = my_array[i];
}
return max;
}
同样的事情可以找到最小值
答案 17 :(得分:-5)
在阅读了所有人的评论后(感谢您的兴趣),我发现执行此操作的“最佳”方式(代码量最少,性能最佳)只是对数组进行排序,然后获取第一个值。阵列:
var myArray:Array /* of Number */ = [2,3,3,4,2,2,5,6,7,2];
myArray.sort(Array.NUMERIC);
var minValue:int = myArray[0];
这也适用于对象数组 - 您只需使用Array.sortOn()函数并指定属性:
// Sample data
var myArray:Array /* of XML */ =
[
<item level="2" name="a" />
<item level="3" name="b" />
<item level="3" name="c" />
<item level="2" name="d" />
<item level="5" name="e" />
]
// Perform a descending sort on the specified attribute in Array to get the maximum value
myArray.sortOn("@level", Array.DESCENDING | Array.NUMERIC);
var lowestLevel:int = myArray[0].@level;
我希望有一天能帮助别人!