以下是我的问题描述:
该计划的说明:
我正在用C ++实现一个程序来测试Prim用于查找最小生成树的算法。该程序的目标是计算为选定数量的随机图找到最小生成树所需的秒数。
到目前为止我做了什么?
我完成了整个程序的函数和头文件的实现。由于源代码很小,为了清晰起见,我决定将其粘贴到此邮件中,以便更好地显示问题。
问题:
出于某种原因,我在应用程序的运行时遇到某种“超出范围”的向量问题。
该问题在(“Prim_and_Kruskal_Algorithms.cpp”)文件中标记。
请求帮助:
如果有人能帮助我发现问题,我将非常感激。我已经用这个问题内联了源代码。
源代码:
(Undirected_Graph.h)文件:
#ifndef UNDIRECTED_GRAPH_H
#define UNDIRECTED_GRAPH_H
#include <vector>
using std::vector;
#include <climits>
class Edge;
class Node
{
public:
Node(int); //The constructor.
int id; //For the id of the node.
bool visited; //For checking visited nodes.
int distance;
vector <Edge*> adj; //The adjacent nodes.
};
class Edge
{
public:
Edge(Node*, Node*, int); //The constructor.
Node* start_Node; //The start_Node start of the edge.
Node* end_Node; //The end of the edge.
int w; //The weight of the edge.
bool isConnected(Node* node1, Node* node2) //Checks if the nodes are connected.
{
return((node1 == this->start_Node && node2 == this->end_Node) ||
(node1 == this->end_Node && node2 == this->start_Node));
}
};
class Graph
{
public:
Graph(int); //The Constructor.
int max_Nodes; //Maximum Number of allowed Nodes.
vector <Edge*> edges_List; //For storing the edges of the graph.
vector <Node*> nodes_List; //For storing the nodes of the graph.
void insertEdge(int, int, int);
int getNumNodes();
int getNumEdges();
};
#endif
(Undirected_Graph.cpp)文件:
#include "Undirected_Graph.h"
Node::Node(int id_Num)
{
id = id_Num;
visited = 0;
distance = INT_MAX;
}
Edge::Edge(Node* a, Node* b, int weight)
{
start_Node = a;
end_Node = b;
w = weight;
}
Graph::Graph(int size)
{
max_Nodes = size;
for (int i = 1; i <= max_Nodes; ++i)
{
Node* temp = new Node(i);
nodes_List.push_back(temp);
}
}
void Graph::insertEdge(int x, int y, int w)
{
Node* a = nodes_List[x-1];
Node* b = nodes_List[y-1];
Edge* edge1 = new Edge(a, b, w);
Edge* edge2 = new Edge(b, a, w);
edges_List.push_back(edge1);
a->adj.push_back(edge1);
b->adj.push_back(edge2);
}
int Graph::getNumNodes()
{
return max_Nodes;
}
int Graph::getNumEdges()
{
return edges_List.size();
}
(Prim_and_Kruskal_Algorithms.h)文件:
#ifndef PRIM_AND_KRUSKAL_ALGORITHMS_H
#define PRIM_AND_KRUSKAL_ALGORITHMS_H
class PKA
{
private:
//inline void generateRandomGraph();
protected:
//-No Protected Data Members in this Class.
public:
void runAlgorithms();
void prim();
};
#endif
(Prim_and_Kruskal_Algorithms.cpp)文件 * (问题出在此文件中并标在下面): *
#include "Prim_and_Kruskal_Algorithms.h"
#include "Undirected_Graph.h"
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
#include <cstdlib>
using std::rand;
using std::srand;
#include <ctime>
using std::time;
//=============================================================================
//============Global Variables and Settings for the program====================
//=============================================================================
const int numIterations = 1; //How many times the Prim function will run.
const int numNodes = 10; //The number of nodes in each graph.
const int numEdges = 9; //The number of edges for each graph.
const int sRandWeight = 1; //The "start" range of the weight of each edge in the graph.
const int eRandWeight = 100; //The "end" range of the weight of each edge in the graph.
//=============================================================================
//=============================================================================
//=============================================================================
void PKA::runAlgorithms() //Runs the Algorithms
{
srand( time(0) );
cout << "------------------------------" << endl;
//Calling the Functions:
cout << "\nRunning the Prim's Algorithms:\nPlease wait till the completion of the execution time" << endl;
//===============================================
//Start the clock for Prim's Algorithm:
clock_t start, finish;
start = clock();
for(int iter1 = 1; iter1 <= numIterations; ++iter1)
{
prim();
}
//Stop the clock for Prim and print the results:
finish = clock();
cout << "\n\tThe execution time of Prim's Algorithm:\t" << ((double)(finish - start) / CLOCKS_PER_SEC) << " s";
return;
}
void PKA::prim()
{
//=============================================================================
//=============================Generating A Random Graph=======================
//=============================================================================
//Randomizing Values:
//===============================================
int randStartNode = rand() % numNodes; //Generation a random start node.
int randEndNode = rand() % numNodes; //Generating a random end node.
int randWeight; //Random weight for the edge.
while(randEndNode == randStartNode) //Checking if both randomized nodes are equal.
{
randEndNode = (rand() % numNodes);
}
//===============================================
Graph myGraph(numNodes);
for(int i = 0; i < numEdges; ++i)
{
//Generating a random weight:
randWeight = sRandWeight + rand() % eRandWeight;
//Inserting a new Edge:
myGraph.insertEdge(randStartNode, randEndNode, randWeight);
}
//=============================================================================
//=============================================================================
//=============================================================================
int currentNode = 0; //The current Node being under investigation.
int adjCounter = NULL; //How many adjacent nodes do we have for the current node.
int minDistance = NULL;
int minIndex = 0;
myGraph.nodes_List[0]->distance = 0; //Indicate the start node.
myGraph.nodes_List[0]->visited = 1; //The starting node is already considered as a visited node.
for(int i = 0; i < numNodes - 1; i++)
{
//Determine how many adjacent nodes there are for the current node:
adjCounter = myGraph.nodes_List[currentNode]->adj.size();
if(adjCounter == 0) //If there are no adjacent nodes to the current node:
{
myGraph.nodes_List[currentNode]->adj.at(minIndex)->end_Node->visited = 1;
cout << "\n*******Not all nodes are connected!*******" << endl;
continue;
}
minDistance = myGraph.nodes_List[currentNode]->adj.at(0)->w;
minIndex = 0;
for(int counter = 0; adjCounter > 0; adjCounter--, counter++)
{
if(myGraph.nodes_List[currentNode]->adj[counter]->end_Node->visited == false)
{
if(myGraph.nodes_List[currentNode]->distance > myGraph.nodes_List[currentNode]->adj[counter]->w)
{
myGraph.nodes_List[currentNode]->distance = myGraph.nodes_List[currentNode]->adj[counter]->w;
}
if(minDistance > myGraph.nodes_List[currentNode]->adj[counter]->w)
{
minDistance = myGraph.nodes_List[currentNode]->adj[counter]->w;
minIndex = counter;
}
}
}
//======================================================================================
//=========================The Problem is in the following two lines====================
//======================================================================================
//Mark the current node as visited:
myGraph.nodes_List[currentNode]->adj.at(minIndex)->end_Node->visited = 1;
//Switching to the next node that we have just visited:
currentNode = myGraph.nodes_List[currentNode]->adj.at(minIndex)->start_Node->id;
//======================================================================================
//======================================================================================
//======================================================================================
}
}
(Client_Code.cpp)文件:用于测试程序。
#include "Prim_and_Kruskal_Algorithms.h"
#include <iostream>
using std::cout;
using std::endl;
int main()
{
cout << "\nWelcome to the Prim and Kruskal Algorithms Comparison!" << endl;
cout << "\nPlease wait until the completion of the algorithms." << endl;
PKA myPKA; //Creating an object of the class.
myPKA.runAlgorithms(); //Running the Algorithm.
cout << "\n\nThe program terminated successfully!" << endl;
return 0;
}
答案 0 :(得分:3)
看看这一行:
myGraph.nodes_List[currentNode]->adj.at(minIndex)->end_Node->visited = 1;
作为一名经验丰富的C ++程序员,我发现这条线很可怕。
麻烦的直接原因是adj
没有你想象的那么多成员;你要求(在我的测试运行中)大小为零的列表的第5个元素。这会让你离开地图,然后开始操纵记忆。
更一般地说,你没有检查界限。
更一般地说,您应该允许这些类管理自己的成员。使用访问器和更改器(getX()
和setX(...)
),以便成员访问在一个地方发生,您可以在那里检查边界。像myGraph
这样的喉咙靠近是非常不安全的。
你会注意到我没有说程序偏离意图的地点/时间/方式,因此列表没有应有的那么多元素。那是因为跟踪它对我来说太麻烦了。如果按照我的建议组织这些类,那么代码将更加清晰,您可以在各个地方检查您的假设,并且该错误应该变得明显。
修改:
要创建随机连接图,请尝试以下操作:
Graph myGraph(numNodes); //Create a new Graph.
// This ensures that the kth node is connected to the [1...(k-1)] subgraph.
for(int k=2 ; k<=numNodes ; ++k)
{
randWeight = rand() % eRandWeight;
myGraph.insertEdge(k, rand()%(k-1)+1, randWeight);
}
// This adds as many extra links as you want.
for(int i = 0; i < numExtraEdges; ++i)
{
randWeight = rand() % eRandWeight;
randStartNode = rand()%(numNodes-1)+1;
randEndNode = rand()%(numNodes-1)+1;
myGraph.insertEdge(randStartNode, randEndNode, randWeight);
}
答案 1 :(得分:1)
你有太多的代码可以进行随意检查以确定任何事情。但.at()
方法会抛出您提到的超出范围的异常,并且在您更新minIndex
之后发生崩溃行,因此我建议您查看确定该值的代码。你在使用调试器吗?例外点minIndex
的值是多少,允许的范围是多少?
此外,当你有一个像这样的复杂语句的怪物系列时,它可以帮助调试这样的问题,如果你打破它,给你更清晰,更简单的代码。而不是一遍又一遍地重复大块代码,你可以得到类似的东西:
Node * node = myGraph.nodes_List[currentNode];
assert(node);
Edge * minAdjEdge = node->adj.at(minIndex);
assert(minAdjEdge);
然后使用minAdjEdge来引用该边缘而不是重复的复合语句。
对我来说,在大循环中首次使用minIndex
仍然使用从上一次迭代中的节点确定的值,但它将它应用于新的当前节点,这似乎也很奇怪。然后在可能使用陈旧值后将其重置为零。但这并不是你所说的导致崩溃的线,所以这可能不是你的问题。就像我说的那样,你在这里粘贴了很多代码,所以很难跟上整个事情。
答案 2 :(得分:0)
代码太多了,但我乍一看的是,由于某种原因,你混合了基于0和基于1的迭代。
这是故意的吗?这可能不是你问题的原因吗?