簡體   English   中英

為什么我不能使用我的無序 map 從 boost 圖形庫中打印出這個頂點的名稱

[英]Why can't I use my unordered map to print out a name for this vertex from boost graph library

我正在從文件中讀取邊緣列表,並嘗試使用 boost 圖形庫從中制作圖形。 最終目標是實現 girvan newman 算法,但現在我只是在讀入圖形。我將數據作為兩個無序映射讀取,這些映射與開關鍵和值對重復,這樣我可以使用.find 同時包含鍵和值。 這是我的代碼:


#include <iostream>
#include <utility>  //std::pair
#include <algorithm>  //std::for_each
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/small_world_generator.hpp>
#include <boost/random/linear_congruential.hpp>
#include <fstream>

typedef adjacency_list< vecS, vecS, bidirectionalS, no_property,
        property< edge_weight_t, float > >
        Graph_type;
typedef std::pair< int, int > Edge;
typedef typename graph_traits< Graph_type >::vertex_descriptor Vertex;

void readInGraph(){



    ifstream myFile("../data/put_data_here.txt");

    //gets first line and turns it to int
    string x;
    myFile >> x;
    stringstream geek(x);
    int numEdges;
    geek >> numEdges;
    Edge edge_array[numEdges];

 string prev = "prev";
    string line;
    myFile.ignore();
    std::unordered_map<string, int> name;
    std::unordered_map<int, string> inverseName;
    int mapCounter = 0;
    string tempVar;

    //loops through file to store names
    //only loops through first column of edges to minimize lookup time
    while(getline(myFile, line)){
        string delimiter = " ";
        string token = line.substr(0, line.find(delimiter));

        if(token != prev){
            name[token] = mapCounter;
            inverseName[mapCounter] = token;
            mapCounter++;
        }
        prev = token;
    }

    myFile.clear();
    myFile.seekg(0, ios::beg);
    myFile >> tempVar; //gets rid of first line of file
    myFile.ignore();

//    loops through the second column of edges and adds any vertices that weren't
//    previously added to the map
    while(getline(myFile, line)){
        string delimiter = "-";
        string token = line.substr(line.find(delimiter) + 2, string::npos);
        if(name.count(token) == 0){
            name[token] = mapCounter;
            inverseName[mapCounter] = token;
            mapCounter++;
        }
    }

    int numVertices = name.size();
    cout << numVertices;

    //now that all the names are collected we can read in the edge array
    //and store it as the integer mapped to that name in the map

    myFile.clear();
    myFile.seekg(0, ios::beg);
    myFile >> tempVar; //gets rid of first line of file
    myFile.ignore();

        for(int i = 0; i < numEdges; i++){
        string hyphen; //gets rid of hyphen
        myFile >> tempVar;
        edge_array[i].first = name.find(tempVar)->second;
        myFile >> hyphen;
        myFile >> tempVar;
        edge_array[i].second = name.find(tempVar)->second;
    }

 float transmission_delay[] = { 1 }; //no edge weights
    Graph_type newGraph(edge_array, edge_array + numEdges, transmission_delay, numVertices);
    std::for_each(vertices(newGraph).first, vertices(newGraph).second, exercise_vertex< Graph_type >(newGraph, inverseName));

在我讀入所有數據后,我創建了我的圖表 g,然后調用 boost 圖形庫使用的練習頂點 function。 在他們的實現中,他們使用一個char* name = "ABCDE" ,他們可以使用它來為每個 get in exercise 頂點獲取不同的輸出。 我想用我的 map 執行此操作,但它不起作用。

template < class Graph > struct exercise_vertex
{
    //state vars
    Graph& g;
    //const char* name; this is the from the original code
    std::unordered_map<int, string> inverseName;

    //Constructor
    exercise_vertex(Graph& g_, std::unordered_map<int, string> name_) : g(g_), inverseName(name_) {}
    //exercise_vertex(Graph& g_, const char name_[]) : g(g_), name(name_) {} from the original code

    //vertex descriptor
    typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
    void operator()(const Vertex& v) const
    {
        typename property_map< Graph, vertex_index_t >::type vertex_id
                = get(vertex_index, g);
        std::cout << "vertex: " << get(vertex_id, v) << std::endl;
//std::cout << "vertex: " << name[get(vertex_id, v)] << std::endl; this is from the original code
//std::cout << "vertex: " << inverseName.find(get(vertex_id, v))->second << std::endl; this is what I would want to do but it doesn't work
        // Write out the outgoing edges
        std::cout << "\tout-edges: ";
        typename graph_traits< Graph >::out_edge_iterator out_i, out_end;
        typename graph_traits< Graph >::edge_descriptor e;
        for (boost::tie(out_i, out_end) = out_edges(v, g); out_i != out_end; ++out_i)
        {
            e = *out_i;
            Vertex src = source(e, g), targ = target(e, g);
            std::cout << "(" << get(vertex_id, src) << ","
                      << get(vertex_id, targ) << ") ";
        }
        std::cout << std::endl;

        // Write out the incoming edges
        std::cout << "\tin-edges: ";
        typename graph_traits< Graph >::in_edge_iterator in_i, in_end;
        for (boost::tie(in_i, in_end) = in_edges(v, g); in_i != in_end; ++in_i)
        {
            e = *in_i;
            Vertex src = source(e, g), targ = target(e, g);
            std::cout << "(" << get(vertex_id, src) << ","
                      << get(vertex_id, targ) << ") ";
        }
        std::cout << std::endl;

        // Write out all adjacent vertices
        std::cout << "\tadjacent vertices: ";
        typename graph_traits< Graph >::adjacency_iterator ai, ai_end;
        for (boost::tie(ai, ai_end) = adjacent_vertices(v, g); ai != ai_end;
             ++ai)
            std::cout << get(vertex_id, *ai) << " ";
        std::cout << std::endl;
    }

};

我一直試圖讓這個工作一整天,我不確定還有什么可以嘗試的。 我認為問題出在練習頂點 function 上,因為我在 readInGraph function 中進行了一些測試,並且能夠列出所有邊緣及其相應的名稱。 我認為這可能與我訪問 map 的方式有關。 在原始代碼中,在構造函數中,我必須刪除這些括號才能使其編譯,但我不知道為什么。 我認為這可能與我的問題有關,也許它實際上沒有將名稱識別為 map,因此.find function 正在工作。 我的另一個想法是get(vertex_id, v)沒有返回 map 中的內容,但如果該值以前可以用作char* name中的索引,那么我認為搜索我的 map 應該沒問題。

這是我的輸入文件的縮短版本,僅供參考:

78

C-B

D B

D - C

乙 - 乙

E-C

E - D

您的初始邊權重

 transmission_delay[] = {1}; // no edge weights

是單個元素,因此圖形構造調用Undefined Behavior

您需要一個對邊數有效的迭代器。 這些構造函數有點“不安全”,因為它們使用原始迭代器,因此不會被檢查。 BGL 在那里顯示出一些年齡。

修復該問題(以及 C99 可變長度數組的使用):¹

std::vector<float> transmission_delay(edge_array.size(),
                                      1.f); // no edge weights

int const numVertices = mappings.size();
return Graph_type(edge_array.data(), edge_array.data() + edge_array.size(),
                  transmission_delay.data(), numVertices);

¹ 好吧,由於問題被刪除了一段時間,我做了更多的審查/重構。

您不需要過於籠統的“exercise_vertex”——這是針對非vecS情況的。

下面簡化了readInGraph以使用單個 Bimap 作為名稱,並通過文件單次傳遞來解析、索引和創建邊:

using Graph_type =
    boost::adjacency_list<boost::setS, boost::vecS, boost::bidirectionalS,
                          boost::no_property,
                          boost::property<boost::edge_weight_t, float>>;

using Vertex = typename boost::graph_traits<Graph_type>::vertex_descriptor;
using Edge   = std::pair<Vertex, Vertex>;

Graph_type readInGraph(std::string const& fname, Mappings& mappings) {
    std::ifstream myFile(fname);

    // gets first line and turns it to int
    unsigned numEdges = 0;
    myFile >> numEdges;

    std::vector<Edge> edge_array;

    for (std::string src, hyphen, tgt;
         edge_array.size() < numEdges && myFile >> src >> hyphen >> tgt;) {
        // combined lookup/insert:
        auto s = mappings.insert(Mappings::value_type(src, mappings.size()))
                     .first->get_right();
        auto t = mappings.insert(Mappings::value_type(tgt, mappings.size()))
                     .first->get_right();

        // now that all the names are collected we can read in the edge array
        // and store it as the integer mapped to that name in the map
        edge_array.emplace_back(s, t);
    }

    std::vector<float> transmission_delay(edge_array.size(),
                                          1.f); // no edge weights

    int const numVertices = mappings.size();
    return Graph_type(edge_array.data(), edge_array.data() + edge_array.size(),
                      transmission_delay.data(), numVertices);
}

請注意,我們現在返回圖形,所以主程序可以像

Mappings mappings;
auto g = readInGraph("put_data_here.txt", mappings);

auto& invmap = mappings.right;

for (Vertex v : boost::make_iterator_range(vertices(g))) {
    std::cout << "Vertex " << v << " name '" << invmap.at(v) << "':\n";

    for (auto e : boost::make_iterator_range(out_edges(v, g))) {
        auto t = target(e, g);
        std::cout << " - adjacent to " << t << " (" << invmap.at(t) << ")\n";
    }
}

現場演示

住在科利魯

印刷

Vertex 0 name 'C':
 - adjacent to 1 (B)
Vertex 1 name 'B':
Vertex 2 name 'D':
 - adjacent to 1 (B)
 - adjacent to 0 (C)
Vertex 3 name 'E':
 - adjacent to 1 (B)
 - adjacent to 0 (C)
 - adjacent to 2 (D)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM