2012-01-06 150 views
1

我的程序有問題。對於少量的邊緣它可以很好地工作,但是當它獲得15000個方向圖的邊緣時,我會在運行一分鐘後出現分段錯誤。調試器說它是由vector_back_back方法拋出的。是否有人知道代碼有什麼問題,以及如何避免它?std :: vector :: push_back拋出分段錯誤

dfs程序在行result.push_back(tmpResult)中拋出錯誤;

#include <cstdlib> 
#include <iostream> 
#include <vector> 

using namespace std; 

typedef struct { 
    unsigned int endNode;  // Number of dest node 
    bool used;     // true, if edge was used in dfs 
} EdgeType; 

typedef struct { 
    unsigned int startNode;  // Number of source node 
    vector<EdgeType> edge;  // Outgoing edges from node 
} NodeType; 

typedef struct { 
    unsigned int startNode; 
    unsigned int endNode; 
} ResultType; 


bool loadInput(vector<NodeType>& graph, unsigned int& numEdges); 
void dfs(vector<NodeType>& graph, unsigned int i, unsigned int numEdges, vector<ResultType>& result); 

int main(int argc, char** argv) { 
    vector<NodeType> graph; 
    vector<ResultType> result; 
    unsigned int numEdges; 

    result.reserve(300000); 

    // Generate oriented multigraph (3 nodes, 150000 edges) 
    numEdges = 150000; 
    NodeType tmpNode; 
    EdgeType tmpEdge; 

    for (unsigned int i = 0; i < 50000; i++) { 
     tmpEdge.used = false; 
     tmpEdge.endNode = 1; 
     tmpNode.edge.push_back(tmpEdge);  
    } 
    tmpNode.startNode = 0; 
    graph.push_back(tmpNode); 
    tmpNode.edge.clear(); 

    for (unsigned int i = 0; i < 50000; i++) { 
     tmpEdge.used = false; 
     tmpEdge.endNode = 2; 
     tmpNode.edge.push_back(tmpEdge);  
    } 
    tmpNode.startNode = 1; 
    graph.push_back(tmpNode); 
    tmpNode.edge.clear(); 

    for (unsigned int i = 0; i < 50000; i++) { 
     tmpEdge.used = false; 
     tmpEdge.endNode = 0; 
     tmpNode.edge.push_back(tmpEdge);  
    } 
    tmpNode.startNode = 2; 
    graph.push_back(tmpNode); 
    tmpNode.edge.clear(); 

    cout << "numEdges: " << numEdges << endl; 

    // Find way 
    for (unsigned int i = 0; i < graph.size(); i++) { 
     dfs(graph, i, numEdges, result); 
    } 

    // No way found 
    cout << "-1" << endl; 

    return 0; 
} 

void dfs(vector<NodeType>& graph, unsigned int i, unsigned int numEdges, vector<ResultType>& result) { 
    // Way was found, print it and exit program (bad style, only for testing) 
    if (numEdges == result.size()) { 
     cout << graph.size() << endl; 
     vector<ResultType>::iterator it; 
     for (it = result.begin(); it != result.end(); it++) { 
      cout << (*it).startNode << " " << (*it).endNode << endl; 
     } 
     cout << "0 0" << endl; 
     exit(0); 
    } 
    // For each outgoing edge do recursion 
    for (unsigned int j = 0; j < graph[i].edge.size(); j++) { 
     if (i >= graph.size()) return; 
     if (!graph[i].edge[j].used) { 
      graph[i].edge[j].used = true; 
      ResultType tmpResult; 
      tmpResult.startNode = graph[i].startNode; 
      tmpResult.endNode = graph[i].edge[j].endNode; 
      result.push_back(tmpResult); 
      dfs(graph, graph[i].edge[j].endNode, numEdges, result); 
      result.pop_back(); 
      graph[i].edge[j].used = false; 
     } 
    } 
} 

與我的計劃,我的目標是要找到在面向圖形,其中每個邊緣只使用一次的方式。

+0

難道你不能縮小它嗎? – 2012-01-06 16:13:01

+1

你不應該使用'graph [i]'來訪問向量。使用'graph.at(i)'更安全,因爲這將檢查圖形是否足夠大,如果現在會引發異常。 '[i]'的危險在於它可能會嘗試訪問超出數組邊界並損壞你的內存,給你一個seg錯誤或類似的錯誤。有些人可能會試圖爭辯說'.at(i)'較慢,但忽略它們:-)在真實世界的程序中,您的配置文件通常會確認這是微不足道的。優化前關注正確性。 – 2012-01-06 16:23:16

+0

@Aaron:索引超出範圍是一個編程錯誤,即一個錯誤。使用'.at()'而不是'operator []'不能修復這個bug,它只是使它變得不同。建議應該是實際修復bug,而不是在遇到bug時拋出異常。 – ildjarn 2012-01-06 16:25:18

回答

6

dfs遞歸調用;增加numEdges會增加遞歸深度,因此,增加numEdges會導致堆棧溢出(表現爲平臺上的段錯誤)。

要麼使用更大的堆棧大小(特定於編譯器)來構建程序,要麼在此場景中不使用遞歸。

+0

+1。Tho可能只是出於記憶的目的,因爲拋出了異常。當耗盡堆棧空間時,它應該死掉。 – 2012-01-06 16:21:17

+0

@VladLazarenko:問題說有分段錯誤,而不是一個例外 – 2012-01-06 16:22:44

+0

@Vlad:沒有拋出異常,調試器只是不正確只顯示實際導致問題的那一行_efore_(對'dfs'的遞歸調用)。 – ildjarn 2012-01-06 16:23:31

0

如果輸入push_back,很可能是因爲您的程序內存不足。由於您沒有捕獲任何異常,因此將調用默認異常處理程序並終止應用程序。在gdb中,您可以使用catch throw命令停止每個「throw」語句。

+1

他得到了段錯誤,沒有引發實際異常。 – ildjarn 2012-01-06 16:21:10

+0

@ildjarn:嗯,OP說「調試器說....拋出」。我無法想象GDB會這麼說,關於信號,因爲它說的是類似「節目接收信號...」。 – 2012-01-06 16:23:33

+1

OP實際上說「*段錯誤...被拋出*」,這顯然是無意義的。 ; - ] – ildjarn 2012-01-06 16:27:21

1

這很可能是您遞歸太深,導致堆棧溢出。在大多數平臺上,堆棧的大小是固定的;你可能會做得更大,但你可能仍然無法支持任意大的圖表。

也許你可以用迭代算法替換遞歸,維護你自己的堆棧(例如std::stack)你需要在回溯時恢復的狀態。然後,圖形大小的唯一限制是可用內存。

+0

是的,就是這樣。謝謝。可以用更大的堆棧。我必須在不遞歸的情況下重寫程序。 – user1134632 2012-01-06 17:03:59