为什么我会在这个迭代器中遇到分段错误?
Why am I getting a segmentation fault in this iterator?
我正在编写一个程序,该程序应该查看图形并计算需要删除的最小边数以离开森林,其中每个连接的组都有偶数个顶点。我知道如何解决问题,但是当我尝试遍历列表时出现分段错误并且无法弄清楚原因。
#include <cmath>
#include <cstdio>
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int N;
cin >> N;
int M;
cin >> M;
// matrix of adjacency list to hold node values
vector<list<int> > adjList(N, list<int>());
// find the number of children nodes each node has
int ui, vi;
for (int i = 0; i < M; i++) {
cin >> ui;
cin >> vi;
ui--;
vi--;
//cout << ui << " " << vi << endl;
adjList[ui].push_back(vi);
adjList[vi].push_back(ui);
//cout << "list length: " << adjList[ui].size() << endl;
}
//cout << "after for loop" << endl;
// count the number of nodes with even numbers of children
for (int i = 0; i <= M; i++) {
cout << i << "-> ";
for (list<int>::iterator it = adjList[i].begin(); it != adjList[i].end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int edgesRemoved = 0;
for (int i = 0; i <= M; i++) {
for (list<int>::iterator it = adjList[i].begin(); it != adjList[i].end(); ++it) {
int j = *it;
if (adjList[j].size() % 2 == 1) {
// delete vertex from current list
cout << "test" << endl;
adjList[i].erase(it);
// delete vertex on the other list
cout << "test" << endl;
cout << j << endl;
cout << *adjList[j].begin() << endl;
for (list<int>::iterator it2 = adjList[j].begin(); it2 != adjList[j].end(); ++it2) {
cout << *it2 << " ";
if (i == *it2) {
adjList[j].erase(it2);
}
}
edgesRemoved++;
}
}
}
cout << edgesRemoved << endl;
return 0;
}
使用cout语句调试程序后发现问题出在这里:
for (int i = 0; i <= M; i++) {
for (list<int>::iterator it = adjList[i].begin(); it != adjList[i].end(); ++it) {
int j = *it;
if (adjList[j].size() % 2 == 1) {
// delete vertex from current list
cout << "test" << endl;
adjList[i].erase(it);
// RIGHT UNDER HERE
// vvvvvvvvvv
for (list<int>::iterator it2 = adjList[j].begin(); it2 != adjList[j].end(); ++it2) {
cout << *it2 << " ";
if (i == *it2) {
adjList[j].erase(it2);
}
}
edgesRemoved++;
}
}
}
程序创建一个迭代器后,我遇到了分段错误,该迭代器旨在遍历向量中的另一个列表。我不明白为什么,语法与第一个 for 循环相同,另一个迭代器遍历第一个列表。
这是一个示例,说明在我输入代表树的数字输入后,程序会打印出邻接矩阵并继续进行实际计算(这部分工作正常,这是最终结果计算期间):
10 9
2 1
3 1
4 3
5 2
6 1
7 2
8 6
9 8
10 8
0-> 1 2 5
1-> 0 4 6
2-> 0 3
3-> 2
4-> 1
5-> 0 7
6-> 1
7-> 5 8 9
8-> 7
9-> 7
test
test
1
0
Segmentation fault
在迭代列表时,您不得删除列表中的当前项(迭代器指向的内容)。你可以这样做:
adjList[j].erase(it2++);
但是,afaik,在迭代时既不收缩也不扩展列表被认为是最佳实践。
擦除迭代器下的项目会使迭代器失效;使用它会进一步导致未定义的行为,因此任何事情都可能发生。这种事情的常用成语是:
std::list<int>::iterator it = adjList[i].begin();
while ( it != adjList[i].end() ) {
if ( *it == i ) {
it = adjList[j].erase( it );
} else {
++ it;
}
}
erase
函数 returns 指向紧跟在被删除元素之后的元素的迭代器。
这对所有序列类型都有效,而不仅仅是 std::list
。
我正在编写一个程序,该程序应该查看图形并计算需要删除的最小边数以离开森林,其中每个连接的组都有偶数个顶点。我知道如何解决问题,但是当我尝试遍历列表时出现分段错误并且无法弄清楚原因。
#include <cmath>
#include <cstdio>
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int N;
cin >> N;
int M;
cin >> M;
// matrix of adjacency list to hold node values
vector<list<int> > adjList(N, list<int>());
// find the number of children nodes each node has
int ui, vi;
for (int i = 0; i < M; i++) {
cin >> ui;
cin >> vi;
ui--;
vi--;
//cout << ui << " " << vi << endl;
adjList[ui].push_back(vi);
adjList[vi].push_back(ui);
//cout << "list length: " << adjList[ui].size() << endl;
}
//cout << "after for loop" << endl;
// count the number of nodes with even numbers of children
for (int i = 0; i <= M; i++) {
cout << i << "-> ";
for (list<int>::iterator it = adjList[i].begin(); it != adjList[i].end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int edgesRemoved = 0;
for (int i = 0; i <= M; i++) {
for (list<int>::iterator it = adjList[i].begin(); it != adjList[i].end(); ++it) {
int j = *it;
if (adjList[j].size() % 2 == 1) {
// delete vertex from current list
cout << "test" << endl;
adjList[i].erase(it);
// delete vertex on the other list
cout << "test" << endl;
cout << j << endl;
cout << *adjList[j].begin() << endl;
for (list<int>::iterator it2 = adjList[j].begin(); it2 != adjList[j].end(); ++it2) {
cout << *it2 << " ";
if (i == *it2) {
adjList[j].erase(it2);
}
}
edgesRemoved++;
}
}
}
cout << edgesRemoved << endl;
return 0;
}
使用cout语句调试程序后发现问题出在这里:
for (int i = 0; i <= M; i++) {
for (list<int>::iterator it = adjList[i].begin(); it != adjList[i].end(); ++it) {
int j = *it;
if (adjList[j].size() % 2 == 1) {
// delete vertex from current list
cout << "test" << endl;
adjList[i].erase(it);
// RIGHT UNDER HERE
// vvvvvvvvvv
for (list<int>::iterator it2 = adjList[j].begin(); it2 != adjList[j].end(); ++it2) {
cout << *it2 << " ";
if (i == *it2) {
adjList[j].erase(it2);
}
}
edgesRemoved++;
}
}
}
程序创建一个迭代器后,我遇到了分段错误,该迭代器旨在遍历向量中的另一个列表。我不明白为什么,语法与第一个 for 循环相同,另一个迭代器遍历第一个列表。
这是一个示例,说明在我输入代表树的数字输入后,程序会打印出邻接矩阵并继续进行实际计算(这部分工作正常,这是最终结果计算期间):
10 9
2 1
3 1
4 3
5 2
6 1
7 2
8 6
9 8
10 8
0-> 1 2 5
1-> 0 4 6
2-> 0 3
3-> 2
4-> 1
5-> 0 7
6-> 1
7-> 5 8 9
8-> 7
9-> 7
test
test
1
0
Segmentation fault
在迭代列表时,您不得删除列表中的当前项(迭代器指向的内容)。你可以这样做:
adjList[j].erase(it2++);
但是,afaik,在迭代时既不收缩也不扩展列表被认为是最佳实践。
擦除迭代器下的项目会使迭代器失效;使用它会进一步导致未定义的行为,因此任何事情都可能发生。这种事情的常用成语是:
std::list<int>::iterator it = adjList[i].begin();
while ( it != adjList[i].end() ) {
if ( *it == i ) {
it = adjList[j].erase( it );
} else {
++ it;
}
}
erase
函数 returns 指向紧跟在被删除元素之后的元素的迭代器。
这对所有序列类型都有效,而不仅仅是 std::list
。