我正在尝试使用递归在数组中找到所有偶数的平均值,而且我被卡住了。
我意识到n
必须为每个奇数递减,所以我除以正确的值,但我无法用递归来解决如何做到这一点
我不明白如何随时跟踪n
,考虑到return
时它会恢复。
我是否有一种方法可以跟踪n
,或者我是否完全以错误的方式看待这种情况?
编辑:我应该指定,我需要专门使用递归。这是一项任务。
public static int getEvenAverage(int[] A, int i, int n)
{
// first element
if (i == 0)
if (A[i] % 2 == 0)
return A[0];
else
return 0;
// last element
if (i == n - 1)
{
if (A[i] % 2 == 0)
return (A[i] + getEvenAverage(A, i - 1, n)) / n;
else
return (0 + getEvenAverage(A, i - 1, n)) / n;
}
if (A[i] % 2 == 0)
return A[i] + getEvenAverage(A, i - 1, n);
else
return 0 + getEvenAverage(A, i - 1, n);
}
答案 0 :(得分:1)
为了跟踪到目前为止遇到的偶数,只需传递一个额外的参数。
此外,您还可以为偶数总和传递额外参数,当您点击基本情况时,您可以返回平均值,即偶数除以其数量的总和。
还有一件事,你的代码对于第一个以及最后一个不需要的元素有两个基本情况。
n
(从数组大小开始直到第一个元素),或者i
开始递增0
,直至达到数组大小,即n
。在这里,我试过了。
public static int getEvenAvg(int[] a, int n, int ct, int sum) {
if (n == -1) {
//make sure you handle the case
//when count of even numbers is zero
//otherwise you'll get Runtime Error.
return sum/ct;
}
if (a[n]%2 == 0) {
ct++;
sum+=a[n];
}
return getEvenAvg(a, n - 1, ct, sum);
}
您可以调用此函数getEvenAvg(a, size_of_array - 1, 0, 0);
答案 1 :(得分:1)
在处理递归操作时,从终止条件开始通常很有用。那么我们的终止条件是什么?
没有更多要处理的元素:
if (index >= a.length) {
// To avoid divide-by-zero
return count == 0 ? 0 : sum / count;
}
...好吧,现在我们如何减少要处理的元素数量?我们应该增加指数?
index++;
......哦,但只有在进入下一个级别时:
getEvenAverage(elements, index++, sum, count);
好吧,我们还必须添加到sum
和count
,对吗?
sum += a[index];
count++;
....除了,只有元素是偶数:
if (a[index] % 2 == 0) {
sum += a[index];
count++;
}
......那就是它:
static int getEvenAverage(int[] elements, int index, int sum, int count) {
if (index >= a.length) {
// To avoid divide-by-zero
return count == 0 ? 0 : sum / count;
}
if (a[index] % 2 == 0) {
sum += a[index];
count++;
}
return getEvenAverage(elements, index + 1, sum, count);
}
...虽然你可能想要一个包装函数来调用它更漂亮:
static int getEvenAverage(int[] elements) {
return getEvenAverage(elements, 0, 0, 0);
}
答案 2 :(得分:0)
这里遇到的困难是你需要记住两个值:
您需要返回平均值的最终值。
这意味着您需要一次记住三个值,而只能返回一个元素。
对于干净的设计,您需要某种容器来保存这些中间结果,例如这样的类:
public class Results {
public int totalValueOfEvens;
public int amountOfEvens;
public double getAverage() {
return totalValueOfEvens + 0.0 / amountOfEvens;
}
}
当然,您也可以使用int[]
之类的内容,包含两个条目。
之后,递归非常简单。您只需以递归方式遍历数组,例如:
public void method(int[] values, int index) {
// Abort if last element
if (index == values.length - 1) {
return;
}
method(array, index + 1);
}
在执行此操作时,使用当前值更新容器。
向后收集时,您需要将所有信息存储在返回值。
中由于您需要记住多个内容,因此应使用容器作为返回类型(Results
或2
- 条目int[]
)。然后简单地遍历到最后,收集并返回。
以下是它的样子:
public static Results getEvenAverage(int[] values, int curIndex) {
// Traverse to the end
if (curIndex != values.length - 1) {
results = getEvenAverage(values, curIndex + 1);
}
// Update container
int myValue = values[curIndex];
// Whether this element contributes
if (myValue % 2 == 0) {
// Update the result container
results.totalValueOfEvens += myValue;
results.amountOfEvens++;
}
// Return accumulated results
return results;
}
这种方法的优点是调用者不需要自己调用results.getAverage()
。您可以将信息存储在参数中,从而可以自由选择返回类型。
我们获取当前值并更新容器。然后我们调用下一个元素并将当前容器传递给他。
在调用最后一个元素之后,保存在容器中的信息是最终的。我们现在只需要结束递归并返回第一个元素。当再次访问第一个元素时,它将根据容器中的信息计算最终输出并返回。
public static double getEvenAverage(int[] values, int curIndex, Results results) {
// First element in recursion
if (curIndex == 0) {
// Setup the result container
results = new Results();
}
int myValue = values[curIndex];
// Whether this element contributes
if (myValue % 2 == 0) {
// Update the result container
results.totalValueOfEvens += myValue;
results.amountOfEvens++;
}
int returnValue = 0;
// Not the last element in recursion
if (curIndex != values.length - 1) {
getEvenAverage(values, curIndex + 1, results);
}
// Return current intermediate average,
// which is the correct result if current element
// is the first of the recursion
return results.getAverage();
}
使用向后方法,如:
Results results = getEvenAverage(values, 0);
double average results.getAverage();
而正向方法的使用方式如下:
double average = getEvenAverage(values, 0, null);
当然,您可以使用辅助方法将其隐藏起来:
public double computeEvenAverageBackward(int[] values) {
return getEvenAverage(values, 0).getAverage();
}
public double computeEvenAverageForward(int[] values) {
return getEvenAverage(values, 0, null);
}
然后,对于最终用户来说,只是这个电话:
double average = computeEvenAverageBackward(values);
答案 3 :(得分:0)
Java不是这种语言的好语言,但我们走了:
public class EvenAverageCalculation {
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6,7,8,9,10};
System.out.println(getEvenAverage(array));
}
public static double getEvenAverage(int[] values) {
return getEvenAverage(values, 0, 0);
}
private static double getEvenAverage(int[] values, double currentAverage, int nrEvenValues) {
if (values.length == 0) {
return currentAverage;
}
int head = values[0];
int[] tail = new int[values.length - 1];
System.arraycopy(values, 1, tail, 0, tail.length);
if (head % 2 != 0) {
return getEvenAverage(tail, currentAverage, nrEvenValues);
}
double newAverage = currentAverage * nrEvenValues + head;
nrEvenValues++;
newAverage = newAverage / nrEvenValues;
return getEvenAverage(tail, newAverage, nrEvenValues);
}
}
到目前为止,每个递归调用都会传递当前平均值和偶数元素数。新平均值是通过将平均值再次乘以到目前为止的元素数量计算出来的,添加新的单个值并将其除以新的元素数量,然后再将其传递给下一个递归调用。
为每个递归调用重新创建新数组的方法是使用Java不那么好的部分。还有其他语言具有分割数组头部和尾部的语法,其中内存占用空间也小得多(每次递归调用都会导致创建一个带有n-1个元素的新int数组)。但我实现的方式是函数式编程的经典方式(至少我是在1994年学习它的时候,当时我用编程语言Gofer进行类似的任务; - )
答案 4 :(得分:0)
这是另一种变体,它使用(适度)众所周知的平均复发关系:
avg 0 = 0
avg n = avg n-1 +(x n - avg n-1 )/ n
其中avg n 是指n个观测值的平均值,x n 是n th 观测值。 这导致:
/*
* a is the array of values to process
* i is the current index under consideration
* n is a counter which is incremented only if the current value gets used
* avg is the running average
*/
private static double getEvenAverage(int[] a, int i, int n, double avg) {
if (i >= a.length) {
return avg;
}
if (a[i] % 2 == 0) { // only do updates for even values
avg += (a[i] - avg) / n; // calculate delta and update the average
n += 1;
}
return getEvenAverage(a, i + 1, n, avg);
}
可以使用以下前端方法调用,以防止用户需要了解参数初始化:
public static double getEvenAverage(int[] a) {
return getEvenAverage(a, 0, 1, 0.0);
}
答案 5 :(得分:0)
现在采用完全不同的方法。
这个借鉴了这样一个事实:如果你有两个平均值,基于n 1 观察的avg 1 和基于n的avg 2 2 观察,你可以将它们结合起来产生一个合并的平均值:
avg 汇集 =(n 1 * avg 1 + n 2 * avg 2 < / sub>)/(n 1 + n 2 )。
这里唯一的问题是递归函数应该返回两个值,即平均值所基于的观察值的平均值和数量。在许多其他语言中,这不是问题。在Java中,它需要一些简单的,虽然有点烦人的辅助类形式的hackery:
// private helper class because Java doesn't allow multiple returns
private static class Pair {
public double avg;
public int n;
public Pair(double avg, int n) {
super();
this.avg = avg;
this.n = n;
}
}
应用分而治之策略会产生以下递归:
private static Pair getEvenAverage(int[] a, int first, int last) {
if (first == last) {
if (a[first] % 2 == 0) {
return new Pair(a[first], 1);
}
} else {
int mid = (first + last) / 2;
Pair p1 = getEvenAverage(a, first, mid);
Pair p2 = getEvenAverage(a, mid + 1, last);
int total = p1.n + p2.n;
if (total > 0) {
return new Pair((p1.n * p1.avg + p2.n * p2.avg) / total, total);
}
}
return new Pair(0.0, 0);
}
我们可以处理空数组,保护最终用户不必了解簿记参数,并使用以下公共前端返回平均值:
public static double getEvenAverage(int[] a) {
return a.length > 0 ? getEvenAverage(a, 0, a.length - 1).avg : 0.0;
}
对于已经提出的各种其他解决方案,该解决方案具有针对n个项目的数组的O(log n)堆栈增长的益处,而O(n)。因此,它可以处理更大的数组,而不必担心堆栈溢出。