【问题标题】:Last item of vector not displaying/vector indexing issue最后一项矢量不显示/矢量索引问题
【发布时间】:2015-12-14 05:20:52
【问题描述】:

我有一个奇怪的错误,我根本找不到。

我正在使用 Boost Graph Library 构建一个 adjacency_list 图,并将一个顶点列表填充到一个向量中。当我遍历向量时,它会正确打印出所有顶点,但是,当我运行算法时,例如 Dijkstra 的最短路径,last 顶点显示为空白。

例如:

Shortest path from C to R 
C -> H = 55 
H ->  = 97
  -> R = 56

Distance: 208

更糟糕的是,如果我编写一个简单的搜索来选择一个特定的顶点,那么向量中的 last 顶点又是一个问题,因为它表明它不存在。

std::string start_vertex;
bool valid = false;
std::cout << "Vertices:" << std::endl;
for (auto &i : _vertices) {
    std::cout << i << " ";
}
std::cout << std::endl;
while (!valid) {
    std::cout << "Enter starting vertex: ";
    std::cin >> start_vertex;
    for (auto &i : _vertices) {
        if (i == start_vertex) {
            valid = true;
            break;
        }
    }
}

上述,在搜索问题顶点时,继续循环,而所有其他顶点都正常工作。如前所述,否则迭代时所有顶点都会打印出来。

最后,当上面的foreach循环运行时,first顶点是空白的。我想所有这些都是相关的,但我无法弄清楚我在这里做了什么。我很乐意提供更多代码,但了解我应该首先寻找什么会有所帮助。

谢谢。


#include <fstream>
#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/kruskal_min_spanning_tree.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/config.hpp>
#include <boost/algorithm/string.hpp>
#include <utility>
#include <vector>
#include <map>

int main(int , const char * argv[]) {
    std::ifstream input(argv[1]);
    typedef int Weight;
    typedef boost::property<boost::vertex_name_t, std::string> VertexNameProperty;
    typedef boost::property<boost::edge_weight_t, Weight> EdgeWeightProperty;
    typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS,
                                                                VertexNameProperty, EdgeWeightProperty> Graph;
    typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
    typedef boost::property_map<Graph, boost::vertex_index_t>::type IndexMap;
    typedef boost::property_map<Graph, boost::vertex_name_t>::type NameMap;
    typedef boost::iterator_property_map<Vertex*, IndexMap, Vertex, Vertex&>
    PredecessorMap;
    typedef boost::iterator_property_map<Weight*, IndexMap, Weight, Weight&>
    DistanceMap;
    std::string line, vertex;
    std::getline(input, line);
    std::getline(input, line);
    boost::char_separator<char> sep(",");
    typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
    tokenizer tok(line, sep);
    std::vector<std::string> _vertices;
    for (auto &i : tok) {
        _vertices.push_back(i);
    }
    Graph g(sizeof(_vertices));
    std::map<std::string, Vertex> vertex_map;
    for (auto &i : _vertices) {
        vertex_map[i] = boost::add_vertex(std::string(i), g);
    }
    char c;
    struct GraphParameters {
        char vertex_one, vertex_two;
        Weight edge_weight;
    };
    std::getline(input, line);
    while (getline(input, line)) {
        GraphParameters p;
        std::istringstream iss(line);
        iss >> c >> p.vertex_one >> c >> p.vertex_two >> c >> p.edge_weight >> c;
        std::string v1, v2;
        std::stringstream ss1 ,ss2;
        ss1 << p.vertex_one;
        ss1 >> v1;
        ss2 << p.vertex_two;
        ss2 >> v2;
        boost::add_edge(vertex_map[v1], vertex_map[v2], p.edge_weight, g);
    }
std::string start_vertex, end_vertex;
bool valid = false;
std::cout << "Vertices:" << std::endl;
for (auto &i : _vertices) {
    std::cout << i << " ";
}
std::cout << std::endl;
while (!valid) {
    std::cout << "Enter starting vertex: ";
    std::cin >> start_vertex;
    for (auto &i : _vertices) {
        if (i == start_vertex) {
            valid = true;
            break;
        }
  }
}
while (valid) {
    std::cout << "Enter ending vertex: ";
    std::cin >> end_vertex;
    for (auto &i : _vertices) {
        if (i == end_vertex) {
            valid = false;
            break;
        }
    }
}
    std::vector<Vertex> predecessors(boost::num_vertices(g));
    std::vector<Weight> distances(boost::num_vertices(g));
    IndexMap indexMap = boost::get(boost::vertex_index, g);
    PredecessorMap predecessorMap(&predecessors[0], indexMap);
    DistanceMap distanceMap(&distances[0], indexMap);
    boost::dijkstra_shortest_paths(g, vertex_map[start_vertex],
                                                                 boost::distance_map(distanceMap)
                                                                 .predecessor_map(predecessorMap));
    NameMap nameMap = boost::get(boost::vertex_name, g);
    std::cout << std::endl;
    typedef std::vector<Graph::edge_descriptor> PathType;
    PathType path;
    Vertex v = vertex_map[end_vertex];
    for(Vertex u = predecessorMap[v]; u != v; v = u, u = predecessorMap[v]) {
        std::pair<Graph::edge_descriptor, bool> edgePair = boost::edge(u, v, g);
        Graph::edge_descriptor edge = edgePair.first;
        path.push_back(edge);
    }
    std::cout << "Shortest path from " << start_vertex << " to " << end_vertex
                        << std::endl;
    for(PathType::reverse_iterator pathIterator = path.rbegin(); pathIterator
            != path.rend(); ++pathIterator) {
        std::cout << nameMap[boost::source(*pathIterator, g)] << " -> "
                            << nameMap[boost::target(*pathIterator, g)]
                            << " = " << boost::get(boost::edge_weight, g, *pathIterator)
                            << std::endl;
    }
    std::cout << std::endl;
    std::cout << "Distance: " << distanceMap[vertex_map[end_vertex]] << std::endl;
    std::cout << std::end;
  return EXIT_SUCCESS;
}

一个示例输入文件:

Vertices:
S,H,R,C,G
Edges
(S,C,39)
(R,S,86)
(G,S,74)
(C,H,55)
(R,C,126)
(G,C,68)
(R,H,111)
(G,R,56)
(H,G,97)
(S,H,27)

【问题讨论】:

  • 这种情况会发生在任意数量的顶点上吗?您是否尝试过在您测试的集合中删除/添加一个?
  • 是的。如果我添加,它只会将错误推回。
  • 好的,让我们看看一些填充和打印 sn-ps。理想情况下,作为可以使用链接的 boost 库编译的 MCVE
  • 可能与您将项目放入向量中的方式有​​关。您还必须显示该代码
  • 当您使用 Graph g(n); 然后调用 add_vertex n 次时,您最终会得到一个具有 2*n 个顶点的图(其中 n 个默认已初始化)。此外,sizeof(vertices)vertices.size() 不同。

标签: c++ boost vector cout boost-graph


【解决方案1】:
Graph g(sizeof(_vertices));

这是一个错误。你想写。

Graph g(_vertices.size());

但是,这仍然是错误的。您稍后已经在循环中添加顶点 (add_vertex),因此您无需预先填充图表。

Graph g;

工作演示

下面的程序有一些样式修复(允许我阅读代码,以及更多地依赖解析),我用所有可能的有效输入对它进行了详尽的测试:

for i in {S,H,R,C,G}\ {S,H,R,C,G}; do valgrind ./test <<< $i; done

(与http://paste.ubuntu.com/14002530/相同)

它显示所有运行完全干净,没有可检测到的内存错误。

Live On Coliru

#include <boost/algorithm/string.hpp>
#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/kruskal_min_spanning_tree.hpp>
#include <boost/graph/properties.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/tokenizer.hpp>
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <utility>
#include <vector>

namespace {
    typedef int Weight;
    typedef boost::property<boost::vertex_name_t, std::string> VertexNameProperty;
    typedef boost::property<boost::edge_weight_t, Weight> EdgeWeightProperty;
    typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, VertexNameProperty, EdgeWeightProperty> Graph;
    typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
    typedef boost::property_map<Graph, boost::vertex_index_t>::type IndexMap;
    typedef boost::property_map<Graph, boost::vertex_name_t>::type NameMap;
    typedef boost::iterator_property_map<Vertex*, IndexMap, Vertex, Vertex&> PredecessorMap;
    typedef boost::iterator_property_map<Weight*, IndexMap, Weight, Weight&> DistanceMap;
}

template <typename V, typename VM>
Graph readGraph(std::string const& fname, V& _vertices, VM& vertex_map) {
    std::ifstream input(fname);
    std::string line, vertex;
    std::getline(input, line);
    assert(line == "Vertices:");

    std::getline(input, line);
    boost::char_separator<char> sep(",");
    typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
    tokenizer tok(line, sep);

    for (auto &i : tok) {
        _vertices.insert(_vertices.end(), i);
    }

    Graph g;
    for (auto &i : _vertices) {
        vertex_map[i] = boost::add_vertex(std::string(i), g);
    }

    char c;
    struct GraphParameters {
        char source, target;
        Weight weight;
    };

    std::getline(input, line);
    assert(line == "Edges");

    while (getline(input, line)) {
        GraphParameters p;
        std::istringstream iss(line);
        if (iss >> c && c == '('
                && iss >> p.source >> c && c == ','
                && iss >> p.target >> c && c == ','
                && iss >> p.weight >> c && c == ')') 
        {
            boost::add_edge(
                    vertex_map[std::string(1,p.source)],
                    vertex_map[std::string(1,p.target)],
                    p.weight,
                    g);
        } else {
            throw std::runtime_error("Parse error in '" + line + "'\n");
        }
    }

    return g;
}

int main() {
    std::vector<std::string>      _vertices;
    std::map<std::string, Vertex> vertex_map;
    auto g = readGraph("input.txt", _vertices, vertex_map);

    std::string start_vertex, end_vertex;
    bool valid = false;
    std::cout << "Vertices:" << std::endl;
    for (auto &i : _vertices) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    while (!valid) {
        std::cout << "Enter starting vertex: ";
        std::cin >> start_vertex;
        for (auto &i : _vertices) {
            if (i == start_vertex) {
                valid = true;
                break;
            }
        }
    }
    while (valid) {
        std::cout << "Enter ending vertex: ";
        std::cin >> end_vertex;
        for (auto &i : _vertices) {
            if (i == end_vertex) {
                valid = false;
                break;
            }
        }
    }
    std::vector<Vertex> predecessors(boost::num_vertices(g));
    std::vector<Weight> distances(boost::num_vertices(g));

    IndexMap indexMap = boost::get(boost::vertex_index, g);
    PredecessorMap predecessorMap(&predecessors[0], indexMap);
    DistanceMap distanceMap(&distances[0], indexMap);

    boost::dijkstra_shortest_paths(g, vertex_map[start_vertex],
                                   boost::distance_map(distanceMap).predecessor_map(predecessorMap));

    NameMap nameMap = boost::get(boost::vertex_name, g);

    std::cout << std::endl;
    typedef std::vector<Graph::edge_descriptor> PathType;

    PathType path;
    Vertex v = vertex_map[end_vertex];
    for (Vertex u = predecessorMap[v]; u != v; v = u, u = predecessorMap[v]) {
        std::pair<Graph::edge_descriptor, bool> edgePair = boost::edge(u, v, g);
        Graph::edge_descriptor edge = edgePair.first;
        path.push_back(edge);
    }
    std::cout << "Shortest path from " << start_vertex << " to " << end_vertex << std::endl;
    for (PathType::reverse_iterator pathIterator = path.rbegin(); pathIterator != path.rend(); ++pathIterator) {
        std::cout << nameMap[boost::source(*pathIterator, g)] << " -> " << nameMap[boost::target(*pathIterator, g)]
                  << " = " << boost::get(boost::edge_weight, g, *pathIterator) << std::endl;
    }
    std::cout << std::endl;
    std::cout << "Distance: " << distanceMap[vertex_map[end_vertex]] << std::endl;
    std::cout << std::endl;
    return EXIT_SUCCESS;
}

【讨论】:

  • 我认为他需要Graph g;
  • @cv_and_he 确实。完成了测试。录制的直播是here
  • 感谢您的精彩回答!
  • 干杯 :) session part #2: paste.ubuntu.com/14002676 中的更多清理(关注点分离、代码重用、简化属性使用)
  • 非常感谢您抽出宝贵时间来做这件事。作为一名学生,看到编写良好的代码非常有帮助,尤其是当它涉及到您要解决的问题时。
猜你喜欢
  • 2017-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-23
  • 2021-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多