所以我写了一个程序,利用euclid算法找到2个整数的GCD。
用户输入一个int(n),然后程序获取8和n之间的每个可能的整数组合,找到它们各自的GCD(递归地),并打印哪些GCD计算需要最多模数运算。
我让程序正常工作,但是我在n = 50左右得到堆栈溢出,并且需要工作至少3000.
我已经检查了一段时间的代码,但找不到问题。
#include<iostream>
#include <math.h>
using namespace std;
int cost, gcd, greatestCost, n, beginningA, beginningB, finalA, finalB, finalGCD, iteration;
void findGCD(int num1, int num2, int startingCost) {
//findGCD
//finds GCD of every combination (a,b) from i to n
//prints those with the greatest number of modulus operations
int a = num1;
int b = num2;
cost = startingCost;
cost++;
if (b%a > 0) {
//cout << "gcd(" << b << "," << a << ") = ";
findGCD(b%a, a, cost);
}
else {
gcd = a;
if (cost > greatestCost) {
greatestCost = cost;
finalA = beginningA;
finalB = beginningB;
finalGCD = gcd;
}
//cout << "gcd(" << b << "," << a << ") = " << gcd << " With a cost of: " << cost << endl;
//do next iteration (2,8), (3,8) etc...
if (++beginningA <= beginningB) { //beginning A goes from 1-i first
findGCD(beginningA, beginningB, 0);
}
else {
if (beginningA <= n) { //begin next cycle with new b value (1,9), (2,9) while b <= n
beginningA = 1; //reset to 1 so it will increment from 1-i again
cout << "At i=" << iteration++ << "; gcd(" << finalA << "," << finalB << ") = " << finalGCD <<
" took " << greatestCost << " modulus operations" << endl;
findGCD(beginningA, ++beginningB, 0);
}
else //When it tries to continue iterating with a number > n
//print the last, most intensive, iteration and stop
cout << "At i=" << iteration++ << "; gcd(" << finalA << "," << finalB << ") = " << finalGCD <<
" took " << greatestCost << " modulus operations" << endl;
}
}
}
int main() {
greatestCost = 0; //cost of the iteration with the most modulus operations
beginningA = 1;
beginningB = 8;
iteration = 8;
cout << "Enter an integer greater than 8 " << endl; //receive n from user
cin >> n;
if (n <= beginningB) //begin GCD search, granted user input > 8
cout << "Error!!! integer must be greater than 8";
else
findGCD(beginningA, beginningB, 0); //algorithm begins at (1,8)
return 0;
}
此时我唯一可以想到的问题就是我在C ++中所做的事情,我不应该这样做(我是C ++新手并从java转移过来)
我尝试的事情:
答案 0 :(得分:1)
首先,您的解释尚不清楚,从您的代码中我了解到,对于每个8<=i<=n
,您可以x, y
y<=i
和x<=y
,并计算哪个gcd需要大多数步骤。
我已经重写了你的代码,以便findGCD只能找到2个数字的gcd,同时增加一些全局代价变量。
#include<iostream>
#include <math.h>
using namespace std;
int cost, gcd, greatestCost, n, beginningA, beginningB, finalA, finalB, finalGCD, iteration;
int findGCD(int a, int b) {
cost++;
if (b%a > 0)
return findGCD(b%a, a);
else
return a;
}
int main() {
greatestCost = 0; //cost of the iteration with the most modulus operations
beginningA = 1;
beginningB = 8;
iteration = 8;
cout << "Enter an integer greater than 8 " << endl; //receive n from user
cin >> n;
if (n <= beginningB) //begin GCD search, granted user input > 8
cout << "Error!!! integer must be greater than 8";
else {
for ( int i = beginningB; i <= n; i++ ) {
int greatestCost = 0, gcd0 = 1, i0 = 0, j0 = 0;
for ( int t = beginningB; t <= i; t++ )
for ( int j = 1; j <= t; j++ ) {
cost = 0;
int gcd = findGCD(j, t);
if ( cost > greatestCost ) {
greatestCost = cost;
gcd0 = gcd;
i0 = t;
j0 = j;
}
}
cout << "At i=" << i << "; gcd(" << j0 << "," << i0 << ") = " << gcd0 <<
" took " << greatestCost << " modulus operations" << endl;
}
}
return 0;
}
答案 1 :(得分:0)
使用过于递归的调用会导致您获得的堆栈溢出:每次调用函数时,都会在(调用)堆栈中创建一个新的堆栈帧(保存局部变量,参数和可能的其他东西) 。仅当从函数返回(通常或通过异常)时才释放该帧。但是对于递归调用,你不会在从第二个函数调用返回之前从第一个函数调用返回,而第二个函数调用仅在第三个之后返回,依此类推。因此堆栈帧堆积在堆栈上,通常大约为8 kB左右,直到堆栈的所有可用内存都被使用:堆栈溢出(你把它放得太多,因此溢出) )。
这可以通过使用迭代(使用循环)来解决:
从8增加到用户提供的最大值的外部,以及从0递增到外部循环的当前迭代变量的值的内部。这为您提供了您想要操作的所有值对。
计算最大公约数及其成本应计入函数中。
唯一剩下的就是从循环中调用该函数,以及如何跟踪最大值。
#include <iostream>
#include <vector>
#include <utility>
using namespace std;
unsigned gcd(unsigned a, unsigned b, unsigned * const cost) {
if (cost) {
*cost = 0;
}
while (b != 0) {
auto const rest = a % b;
if (cost) {
++(*cost);
}
a = b;
b = rest;
}
return a;
}
int main() {
unsigned const n = 3500;
unsigned greatestCost = 0;
vector<pair<unsigned, unsigned>> pairs;
for (unsigned b = 8; b <= n; ++b) {
for (unsigned a = 0; a <= b; ++a) {
unsigned cost;
gcd(a, b, &cost);
if (cost == greatestCost) {
pairs.emplace_back(a, b);
} else if (cost > greatestCost) {
pairs.clear();
pairs.emplace_back(a, b);
greatestCost = cost;
}
}
}
cout << "Greatest cost is " << greatestCost << " when calculating the GCD of " << endl;
for (auto const & p : pairs) {
cout << "(" << p.first << ", " << p.second << ")" << endl;
}
return 0;
}
特别注意我没有使用任何全局变量。
以上可能会让你觉得递归是一种无法使用的无用结构。不是这种情况。许多算法使用递归最清晰地表达。当将递归调用作为最后一个语句时,可以使用称为尾调用优化的优化:然后被调用函数重用调用函数的堆栈帧,因此不再使用任何内存。
不幸的是,由于各种原因,这种优化在像C ++这样的语言中实现起来非常棘手。
其他语言,主要是功能语言,使用它,因此也是递归而不是循环。这种语言的一个例子是Scheme,它甚至要求实现能够进行上述优化。
作为最后一点:你可以在这里使用递归调用来实现GCD计算,因为你看到最大深度将是17 + 1
,它应该足够小以适应任何(嵌入式系统之外)调用堆栈。我仍然使用迭代版本:它具有更好的性能,更好地适应语言的习语,并且是更安全的&#34;要走的路。