2015-02-10 70 views
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); 

      // 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++; 
     } 
     } 
    } 

我拿到程序后,分段错误创建一个,就是要经过另一个列表的迭代器:

#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循环与另一个遍历第一个列表的迭代器相同。

下面是我输入表示树的数字输入后发生的情况的一个例子,然后程序打印邻接矩阵并进行实际计算(这部分工作正常,这是最后的结果计算):

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 
+1

请发布一个[最小完整可验证示例](http://stackoverflow.com/help/mcve) – 2015-02-10 19:59:53

+0

现在是时候让您使用_real_调试器,而不是'cout'。 – 2015-02-10 20:01:32

回答

2

当您迭代它时,您不能删除列表中的当前项(迭代器指向的内容)。你可以做这样的事情:

adjList[j].erase(it2++); 

然而,据我所知,它被认为是最好的做法既不缩小也不扩大,而迭代的列表。

+0

那么在那种情况下,应该如何删除不在开始或结束的列表中的特定元素?或者,在这种情况下使用邻接矩阵是否更好? – mudejar 2015-02-10 20:06:46

+0

答案中包含的代码将执行此操作。您可以使用迭代器上的修补后增量进行删除。 – 2015-02-10 20:07:12

+0

使用'std :: list'的重点是能够在任意点删除和插入,即在迭代时。 – 2015-02-10 20:17:32

3

擦除迭代器下的项目会使迭代器失效;使用它会进一步导致未定义的行为,所以任何事情都可能发生。对于这样的事情通常的习惯用法:

std::list<int>::iterator it = adjList[i].begin(); 
while (it != adjList[i].end()) { 
    if (*it == i) { 
     it = adjList[j].erase(it); 
    } else { 
     ++ it; 
    } 
} 

erase函数返回一个迭代到元件立即除去了一个以下。

这适用于所有序列类型,而不仅仅是std::list

相关问题