当我的 Johnson-Trotter 算法中没有打印语句时,为什么会出现分段错误?
Why do I get a segmentation fault when I don't have print statements in my Johnson-Trotter algorithm?
我正在尝试用 C++ 实现 Johnson-Trotter 算法来完成家庭作业。在(我认为)我弄明白之后我真的很兴奋,但结果是当我 运行 它时我遇到了段错误。这是它的代码(抱歉有点长):
#include <iostream>
#define N 3
#define RIGHT true
#define LEFT false
using namespace std;
// Struct to represent a number with its arrow and its mobility
struct number {
int num;
bool arrow;
};
void printPermutation(number permutation[], int n) {
for (int i = 0; i < n; i++) {
if (permutation[i].arrow == LEFT)
cout << '-';
cout << permutation[i].num << ' ';
}
}
void reverseArrows(number permutation[], int n, int k) {
for (int i = 0; i < n; i++)
if (permutation[i].num > permutation[k].num)
permutation[i].arrow ^= 1;
}
void swapMobile(number permutation[], int k) {
number temp;
temp.num = permutation[k].num;
temp.arrow = permutation[k].arrow;
int swapper;
if (permutation[k].arrow == RIGHT)
swapper = 1;
else // permutation[k].arrow == LEFT
swapper = -1;
permutation[k].num = permutation[k + swapper].num;
permutation[k].arrow = permutation[k + swapper].arrow;
permutation[k + swapper].num = temp.num;
permutation[k + swapper].arrow = temp.arrow;
}
void setNextPermutation(number current[], number next[], int n) {
for (int i = 0; i < n; i++) {
next[i].num = current[i].num;
next[i].arrow = current[i].arrow;
}
}
bool isMobile(number permutation[], int n, int k) {
if ((k == 0) && (permutation[k].arrow == LEFT))
return false;
if ((k == n - 1) && (permutation[k].arrow == RIGHT))
return false;
if ((permutation[k].arrow == LEFT) && (permutation[k - 1].num < permutation[k].num))
return true;
if ((permutation[k].arrow == RIGHT) && (permutation[k].num > permutation[k + 1].num))
return true;
return false;
}
int largestMobile(number permutation[], int n) {
int largest = 0;
cout << "Before isMobile\n";
for (int i = 1; i < n; i++)
if (i > largest && isMobile(permutation, n, i))
largest = i;
return largest;
}
bool hasMobile(number permutation[], int n) {
cout << "Before isMobile\n";
for (int i = 0; i < n; i++)
if (isMobile(permutation, n, i))
return true;
return false;
}
// Simple function to iteratively calculate n!
int factorial(int n) {
int factorial = 1;
for (int i = 1; i <= n; i++)
factorial *= i;
return factorial;
}
void JohnsonTrotter(int n) {
cout << "Before factorial\n";
int nFactorial = factorial(n);
number permutations[nFactorial][n];
// Initialize first permutation.
for (int i = 0; i < n; i++) {
permutations[0][i].num = i + 1;
permutations[0][i].arrow = LEFT;
}
int permutation = 0;
cout << "Before hasMobile\n";
while (hasMobile(permutations[permutation], n)) {
cout << "Before setNextPermutation\n";
setNextPermutation(permutations[permutation], permutations[permutation + 1], n);
permutation++;
cout << "Before largestMobile\n";
int k = largestMobile(permutations[permutation], n);
cout << "Before swapMobile\n";
swapMobile(permutations[permutation], k);
cout << "Before reverseArrows\n";
reverseArrows(permutations[permutation], n, k);
}
cout << "Before printPermutation\n";
for (int i = 0; i < nFactorial; i++) {
printPermutation(permutations[i], n);
cout << ' ';
if (!((i + 1) % n))
cout << '\n';
}
}
int main() {
JohnsonTrotter(N);
return 0;
}
我首先 运行 它没有任何打印语句,它给了我一个段错误。我输入了一些打印语句,但没有出现段错误,但也没有得到预期的结果。我删除了 print 语句,将 N
更改为 2,并再次出现段错误。我将 N
更改为 1 并得到了预期的结果。我将 N
更改为 4,并且在有和没有打印语句的情况下都出现了段错误。
此外,如果这是错误的提问方式,我很抱歉,但我以前从未在这里提问过。
感谢所有回复的人。你们都是对的,它试图访问比为数组分配的内存更多的元素。我在 largestMobile
函数中找到了罪魁祸首。这是重构后的代码:
int largestMobile(number permutation[], int n) {
int k = 0;
while (!isMobile(permutation, n, k))
k++;
if (k < n - 1)
for (int i = k + 1; i < n; i++)
if (permutation[i].num > permutation[k].num && isMobile(permutation, n, i))
k = i;
return k;
}
小(显而易见的)注意事项:我将变量名称 largest
更改为 k
以在一行中腾出更多空间,这也很有意义,因为无论如何我都会返回。最后我检查了要返回的元素是否是可移动的。以前的版本从不检查 largest
是否移动。同样在以前的版本中,如果 permutation
中的最大元素位于数组的前面,则没有其他元素可能更大,因此 largest
永远不会更新。
此外,在 swapMobile
中,k
也需要更新。
我正在尝试用 C++ 实现 Johnson-Trotter 算法来完成家庭作业。在(我认为)我弄明白之后我真的很兴奋,但结果是当我 运行 它时我遇到了段错误。这是它的代码(抱歉有点长):
#include <iostream>
#define N 3
#define RIGHT true
#define LEFT false
using namespace std;
// Struct to represent a number with its arrow and its mobility
struct number {
int num;
bool arrow;
};
void printPermutation(number permutation[], int n) {
for (int i = 0; i < n; i++) {
if (permutation[i].arrow == LEFT)
cout << '-';
cout << permutation[i].num << ' ';
}
}
void reverseArrows(number permutation[], int n, int k) {
for (int i = 0; i < n; i++)
if (permutation[i].num > permutation[k].num)
permutation[i].arrow ^= 1;
}
void swapMobile(number permutation[], int k) {
number temp;
temp.num = permutation[k].num;
temp.arrow = permutation[k].arrow;
int swapper;
if (permutation[k].arrow == RIGHT)
swapper = 1;
else // permutation[k].arrow == LEFT
swapper = -1;
permutation[k].num = permutation[k + swapper].num;
permutation[k].arrow = permutation[k + swapper].arrow;
permutation[k + swapper].num = temp.num;
permutation[k + swapper].arrow = temp.arrow;
}
void setNextPermutation(number current[], number next[], int n) {
for (int i = 0; i < n; i++) {
next[i].num = current[i].num;
next[i].arrow = current[i].arrow;
}
}
bool isMobile(number permutation[], int n, int k) {
if ((k == 0) && (permutation[k].arrow == LEFT))
return false;
if ((k == n - 1) && (permutation[k].arrow == RIGHT))
return false;
if ((permutation[k].arrow == LEFT) && (permutation[k - 1].num < permutation[k].num))
return true;
if ((permutation[k].arrow == RIGHT) && (permutation[k].num > permutation[k + 1].num))
return true;
return false;
}
int largestMobile(number permutation[], int n) {
int largest = 0;
cout << "Before isMobile\n";
for (int i = 1; i < n; i++)
if (i > largest && isMobile(permutation, n, i))
largest = i;
return largest;
}
bool hasMobile(number permutation[], int n) {
cout << "Before isMobile\n";
for (int i = 0; i < n; i++)
if (isMobile(permutation, n, i))
return true;
return false;
}
// Simple function to iteratively calculate n!
int factorial(int n) {
int factorial = 1;
for (int i = 1; i <= n; i++)
factorial *= i;
return factorial;
}
void JohnsonTrotter(int n) {
cout << "Before factorial\n";
int nFactorial = factorial(n);
number permutations[nFactorial][n];
// Initialize first permutation.
for (int i = 0; i < n; i++) {
permutations[0][i].num = i + 1;
permutations[0][i].arrow = LEFT;
}
int permutation = 0;
cout << "Before hasMobile\n";
while (hasMobile(permutations[permutation], n)) {
cout << "Before setNextPermutation\n";
setNextPermutation(permutations[permutation], permutations[permutation + 1], n);
permutation++;
cout << "Before largestMobile\n";
int k = largestMobile(permutations[permutation], n);
cout << "Before swapMobile\n";
swapMobile(permutations[permutation], k);
cout << "Before reverseArrows\n";
reverseArrows(permutations[permutation], n, k);
}
cout << "Before printPermutation\n";
for (int i = 0; i < nFactorial; i++) {
printPermutation(permutations[i], n);
cout << ' ';
if (!((i + 1) % n))
cout << '\n';
}
}
int main() {
JohnsonTrotter(N);
return 0;
}
我首先 运行 它没有任何打印语句,它给了我一个段错误。我输入了一些打印语句,但没有出现段错误,但也没有得到预期的结果。我删除了 print 语句,将 N
更改为 2,并再次出现段错误。我将 N
更改为 1 并得到了预期的结果。我将 N
更改为 4,并且在有和没有打印语句的情况下都出现了段错误。
此外,如果这是错误的提问方式,我很抱歉,但我以前从未在这里提问过。
感谢所有回复的人。你们都是对的,它试图访问比为数组分配的内存更多的元素。我在 largestMobile
函数中找到了罪魁祸首。这是重构后的代码:
int largestMobile(number permutation[], int n) {
int k = 0;
while (!isMobile(permutation, n, k))
k++;
if (k < n - 1)
for (int i = k + 1; i < n; i++)
if (permutation[i].num > permutation[k].num && isMobile(permutation, n, i))
k = i;
return k;
}
小(显而易见的)注意事项:我将变量名称 largest
更改为 k
以在一行中腾出更多空间,这也很有意义,因为无论如何我都会返回。最后我检查了要返回的元素是否是可移动的。以前的版本从不检查 largest
是否移动。同样在以前的版本中,如果 permutation
中的最大元素位于数组的前面,则没有其他元素可能更大,因此 largest
永远不会更新。
此外,在 swapMobile
中,k
也需要更新。