c – 向量的最后一项不显示/向量索引问题

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

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

例如:

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

Distance: 208

更糟糕的是,如果我编写一个简单的搜索来选择一个特定的顶点,那么矢量中的最后一个顶点再次成为问题,因为它表明它不存在.

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循环运行时,第一个顶点是空白的.我想所有这些都是相关的,但我无法弄清楚我在这里做了什么.我很乐意提供更多代码,但了解我应该首先考虑的内容会很有帮助.

谢谢.

#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)

最佳答案

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;
}
点赞