2015-02-10 104 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

相關問題