我目前正在用 C++ 编写一个控制台程序,该程序构建使用无序映射相互连接的节点和弧的网络/图。该应用程序的目的是演示处理命令和从网络/图形检索信息的“最有效”方式。我已附上[类似示例的图表]。(https://i.sstatic.net/51FY0RHO.png)。
下面是我的
BuildNetwork()
文件中的 Network.cpp
方法以及我的 Graph.cpp
、Node.cpp
和 Arc.cpp
类,以便您可以了解我的网络是如何构建的:
bool Navigation::BuildNetwork(const std::string& fileNamePlaces, const std::string& fileNameLinks)
{
std::ifstream finPlaces(fileNamePlaces), finLinks(fileNameLinks);
if (!finPlaces || !finLinks)
return false;
std::string line;
// Parse Places
while (getline(finPlaces, line)) {
std::istringstream iss(line);
std::string name, idStr, latitudeStr, longitudeStr;
if (getline(iss, name, ',') && getline(iss, idStr, ',') && getline(iss, latitudeStr, ',') && getline(iss, longitudeStr)) {
int id = std::stoi(idStr);
double latitude = std::stod(latitudeStr), longitude = std::stod(longitudeStr);
Node node(id, name, latitude, longitude);
networkGraph.addNode(node);
}
}
// Parse Links
while (getline(finLinks, line)) {
std::istringstream iss(line);
std::string startIdStr, endIdStr, modeStr;
if (getline(iss, startIdStr, ',') && getline(iss, endIdStr, ',') && getline(iss, modeStr)) {
int startNodeId = std::stoi(startIdStr), endNodeId = std::stoi(endIdStr);
TransportMode mode = parseTransportMode(modeStr);
Arc arc(startNodeId, endNodeId, mode);
networkGraph.addArc(startNodeId, arc);
}
}
return true;
}
// Helper function to parse string to TransportMode
TransportMode Navigation::parseTransportMode(const std::string& modeStr) {
static const std::unordered_map<std::string, TransportMode> modeMap = {
{"Ship", TransportMode::Ship}, {"Rail", TransportMode::Rail},
{"Bus", TransportMode::Bus}, {"Car", TransportMode::Car},
{"Bike", TransportMode::Bike}, {"Foot", TransportMode::Foot}
};
auto it = modeMap.find(modeStr);
if (it != modeMap.end())
return it->second;
return TransportMode::Foot; // Default or error case
}
#include "Graph.h"
Graph::Graph() {}
Graph::~Graph() {}
void Graph::addNode(const Node& node) {
nodes[node.getId()] = node;
}
void Graph::addArc(int startNodeID, const Arc& arc) {
if (nodeExists(startNodeID) && nodeExists(arc.getEndNodeID())) {
if (adjacencyList.find(startNodeID) == adjacencyList.end()) {
adjacencyList[startNodeID] = std::vector<Arc>(); // Initialize if not already
}
adjacencyList[startNodeID].push_back(arc);
}
}
Node& Graph::getNode(int nodeId) {
return nodes.at(nodeId);
}
const Node& Graph::getNode(int nodeId) const {
return nodes.at(nodeId);
}
const std::vector<Arc>& Graph::getArcs(int nodeId) const {
return adjacencyList.at(nodeId);
}
bool Graph::nodeExists(int nodeId) const {
return nodes.find(nodeId) != nodes.end();
}
bool Graph::arcExists(int startNodeID, int endNodeID) const {
auto it = adjacencyList.find(startNodeID);
if (it != adjacencyList.end()) {
return std::any_of(it->second.begin(), it->second.end(), [endNodeID](const Arc& arc) {
return arc.getEndNodeID() == endNodeID;
});
}
return false;
}
const std::unordered_map<int, Node> Graph::getAllNodes() const {
return nodes;
}
#include "Node.h"
Node::Node(int id, const std::string& name, double latitude, double longitude)
: id(id), name(name)
{
Utility::LLtoUTM(latitude, longitude, y, x);
}
//Setting "getters" as const as they're not changing once set
int Node::getId() const
{
return id;
}
std::string Node::getName() const
{
return name;
}
double Node::getX() const
{
return x;
}
double Node::getY() const
{
return y;
}
#include "Arc.h"
Arc::Arc(int startNodeID, int endNodeID, TransportMode transportMode, double distance)
: startNodeID(startNodeID), endNodeID(endNodeID), transportMode(transportMode), distance(distance) {}
int Arc::getStartNodeID() const {
return startNodeID;
}
int Arc::getEndNodeID() const {
return endNodeID;
}
TransportMode Arc::getTransportMode() const {
return transportMode;
}
double Arc::getDistance() const {
return distance;
}
void Arc::setDistance(double dist) {
distance = dist;
}
如您所见,它利用无序映射来存储节点和弧。我已经实现了一种计算
Network.cpp
中两个节点之间最远距离的方法。请记住,这可以完美地工作:
bool Navigation::maxDist(const std::string& params) {
double maxDistance = 0.0;
std::string farthestNodes;
const auto& nodes = networkGraph.getAllNodes(); // Ensure this returns a reference to the map
for (auto it1 = nodes.begin(); it1 != nodes.end(); ++it1) {
for (auto it2 = std::next(it1); it2 != nodes.end(); ++it2) {
// Calculate Euclidean distance between nodes in meters, then convert to kilometers
double dx = it2->second.getX() - it1->second.getX();
double dy = it2->second.getY() - it1->second.getY();
double squaredDistance = dx * dx + dy * dy;
if (squaredDistance > maxDistance) {
maxDistance = squaredDistance;
farthestNodes = it1->second.getName() + " to " + it2->second.getName();
}
}
}
maxDistance = sqrt(maxDistance) / 1000.0; // Convert from meters to kilometers
std::cout << "Max Distance: " << maxDistance << " km between " << farthestNodes << std::endl;
return true;
}
然而,问题是当我尝试实现一种方法来计算哪个节点具有最多的连接弧时:
bool Navigation::maxLink(const std::string& params)
{
double maxDistance = 0.0;
std::string longestLinkDescription;
Node startNode, endNode;
// Iterate over all nodes to access their adjacency lists
for (const auto& nodePair : networkGraph.getAllNodes()) {
int nodeId = nodePair.first;
const auto& arcs = networkGraph.getArcs(nodeId);
// Check each arc for this node
for (const auto& arc : arcs) {
// Make sure the end node exists to avoid out of bounds
if (!networkGraph.nodeExists(arc.getEndNodeID())) {
continue; // Skip this arc if the end node doesn't exist
}
Node start = networkGraph.getNode(nodeId);
Node end = networkGraph.getNode(arc.getEndNodeID());
// Calculate distance using the coordinates stored in nodes
double distance = Utility::arcLength(start.getY(), start.getX(), end.getY(), end.getX());
// Check if this is the longest arc found so far
if (distance > maxDistance) {
maxDistance = distance;
startNode = start;
endNode = end;
longestLinkDescription = start.getName() + " to " + end.getName();
}
}
}
// Output the longest link found and its distance
if (longestLinkDescription.empty()) {
std::cout << "No valid links found." << std::endl;
return false;
}
else {
std::cout << "Longest Link: " << longestLinkDescription << " - " << std::fixed << std::setprecision(3) << maxDistance << " km" << std::endl;
return true;
}
}
当我编译并运行程序时,出现以下错误:
Unhandled exception at 0x00007FF924A2AB89 in Network.exe: Microsoft C++ exception: std::out_of_range at memory location 0x0000008FF973E380.
这让我很困惑,因为我已经测试过,每个节点和弧都是通过程序早期的调试构建和初始化的,所以肯定不应该有任何超出范围的内存位置。这让我认为这不是网络构建本身的问题,而是该方法在无序映射中运行的方式的问题。由于它没有具体告诉我出了什么问题,我真的不确定如何解决这个问题。我对使用无序映射相对缺乏经验,但有人告诉我这是建立这样的网络的有效方法。如何解决我看到的错误?
我很确定问题是由于我的
GetArcs()
中的 Grid.cpp
方法不接受没有附加弧的节点。我已更新该方法以仅返回空列表/弧向量。现在运行完美。
const std::vector<Arc>& Graph::getArcs(int nodeId) const {
static const std::vector<Arc> emptyArcList;
auto it = adjacencyList.find(nodeId);
if (it != adjacencyList.end()) {
return it->second;
}
else {
return emptyArcList;
}