Как вы используете итератор stl и очередь для реализации обхода графа в ширину?

#c #data-structures #graph #stl #breadth-first-search

#c #структуры данных #График #stl #поиск в ширину

Вопрос:

хотя я концептуально понимаю BFS, я не понял, как использовать итератор и очередь для реализации BFS. Я был бы очень признателен, если бы кто-нибудь мог дать мне некоторое представление о том, как правильно использовать итератор в моем коде. Спасибо.

Я даже не уверен, что итератор здесь хорошая идея, я тоже пытался изучить тип auto, но я не уверен, как это использовать.

 #ifndef GRAPH_H
#define GRAPH_H
#include<vector>
#include<iostream>
using namespace std;

struct vertex;

struct adjVertex{
    vertex *v;
};

struct vertex{

    string name;
    bool visited = false;
    int distance = 0;
    vector<adjVertex> adj;
};

class Graph
{
    public:
        void addEdge(string v1, string v2);
        void addVertex(string name);
        void displayEdges();
        void breadthFirstTraverse(string sourceVertex);
        int getConnectedBuildings();


    private:
        vector<vertex*> vertices;
};

#endif // GRAPH_H
  
 void Graph::breadthFirstTraverse(string sourceVertex){
    
    //first initialize everything as not found
    for(int i = 0; i < vertices.size(); i  )
    {
        vertices[i]->visited = false;
    }

    //pointer to sourceVertex
    vertex *vStart;

    for(int i=0; i < vertices.size(); i  )
    {
        if(vertices[i]->name == sourceVertex){
            vStart = vertices[i];
            cout << "Starting vertex (root): " << vStart->name << " -> " << endl;
        }
    }
    queue<vertex*> q;
    vStart->visited = true;
    q.push(vStart);
    vertex *n;
    vector<int>:: iterator i;
    
    while(!q.empty()){
        n = q.front();

        q.pop();

        for(i = n->adj.begin(); i != n->adj.end();   i){ // error: no viable overloaded '='

            cout << n->adj[*i].v->name <<"(" << n->adj[*i].v->distance << ")" << " ";

            if(!n->adj[*i].v->visited){
                n->adj[*i].v->visited = true;
                q.push(*i); //no matching member function for call to 'push'
            }
        }
    }
}

  

Примечание: я решил свой собственный вопрос в комментариях.

Комментарии:

1. Извините, просто отредактировал это

2. В этом коде требуется меньше вертикальных пробелов. В чем реальная проблема с вашим кодом? Есть ли вообще проблема? Похоже, здесь вы внедрили BFS с очередью. Основная проблема, которую я вижу, — это неопределенное поведение, если sourceVertex оно не найдено, что, вероятно, приведет к сбою.

3. Компилятору не нравится мой цикл for .

4. Да, я вижу, вы отредактировали это сейчас, чтобы добавить фактические сообщения об ошибках. Это должно было быть намного понятнее в вашем вопросе. Ответить на этот вопрос будет просто. Один момент.

5. На будущее, когда вы пишете какой-то код и у вас возникают ошибки компилятора, которые вы не понимаете, пожалуйста, не публикуйте свою программу и не говорите: «Мне нужно сделать <все, что должна делать программа> — help». Вместо этого вы должны опубликовать фактическое сообщение об ошибке и показать код, к которому оно относится. Сделайте это предметом вашего вопроса. Вы также можете попробовать поискать ошибки такого рода в Интернете, поскольку вы определенно не первый человек, столкнувшийся с трудностями с типами в C .

Ответ №1:

Ваше первое сообщение об ошибке:

ошибка: нет жизнеспособной перегруженной ‘=’

Это связано со следующим:

 vector<int>:: iterator i;
for(i = n->adj.begin(); i != n->adj.end();   i) {
  

Обратите внимание, что тип n->adj.begin() is vector<adjVertex>::iterator . Однако переменная i имеет тип vector<int>::iterator . Ошибка компилятора содержала бы в себе гораздо больше, чем то, что вы показали. Это прекрасно объяснило бы проблему.

Это должно исправить ошибку:

 for(vector<adjVertex>::iterator i = n->adj.begin(); i != n->adj.end();   i) {
  

Поскольку вы спрашивали об auto этом, это также приемлемо:

 for(auto i = n->adj.begin(); i != n->adj.end();   i) {
  

В этом случае тип i будет vector<adjVertex>::iterator .

Вторая ошибка связана:

нет соответствующей функции-члена для вызова ‘push’

Это для этого:

 q.push(*i);
  

Здесь тип q is queue<vertex*> и тип *i is int . Если вы примените мое исправление выше, то тип *i будет adjVertex таким, который приведет к той же проблеме. Итак, вам понадобится:

 q.push(i->v);
  

Возвращаясь к первой ошибке, существует более современный способ итерации (начиная с C 11), использующий цикл на основе диапазона:

 for (autoamp; elem : n->adj) {
  

Выше это будет повторяться по вашему adj вектору, предоставляя вам доступ к его элементам через значение elem , которое будет иметь тип adjVertexamp; . Таким образом, вы сможете получить доступ vertex* к этому элементу с elem.v помощью .

Ответ №2:

Я внес небольшие изменения в свой код, чтобы исправить это. Я не использовал итератор (переменная int в цикле for была в порядке), и мне не нужно было разыменовывать подобное

 n->adj[*i].v->name
  

Вот что в итоге сработало

 void getConnectedComponents(string buildingName, vertex *amp; node){
    //pointer to sourceVertex
    vertex *vStart;
    vStart = node;

    queue<vertex*> q; 
    
    
    vStart->visited = true;
    q.push(vStart); 
    vertex *n; //pointer to elements in queue
    while(!q.empty()){
       
        n = q.front();
       
        q.pop();
        
        for(int i = 0; i  < n->adj.size(); i  ){
               if(!n->adj[i].v->visited){
                 
                   //cout << n->adj[i].v->name <<"(" << n->adj[i].v->distance << ")" << " ";
               
                n->adj[i].v->visited = true;
                q.push(n->adj[i].v);
               }
        }
    }
    cout << endl;
}