#c
#c
Вопрос:
Я хочу спросить, почему он рассматривает list<int> *adj
как массив списков смежности. Я думаю, что это всего лишь динамический массив, но не массив списков? Кто-нибудь может мне объяснить, пожалуйста?
// Program to print BFS traversal from a given
// source vertex. BFS(int s) traverses vertices
// reachable from s.
#include<iostream>
#include <list>
using namespace std;
// This class represents a directed graph using
// adjacency list representation
class Graph
{
int V; // No. of vertices
// Pointer to an array containing adjacency
// lists
list<int> *adj;
public:
Graph(int V); // Constructor
// function to add an edge to graph
void addEdge(int v, int w);
// prints BFS traversal from a given source s
void BFS(int s);
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w); // Add w to v’s list.
}
Комментарии:
1. Этот код с веб-сайта Geeks for Geeks о BFS — код из места, в котором есть история плохих примеров кода.
list<int> *adj;
— Это не массив, это указатель. Там нет массива. Это:std::vector<std::list<int>> adj;
представляет собой динамический массивstd::list<int>
. Тогда вместоnew[]
,Graph::Graph(int V):adj(V) {}
. Вам даже больше не понадобитсяV
участник.2.
new list<int>[V]
эффективно создает «массив»V
элементов в памяти, где каждый элемент являетсяlist<int>
объектом. Присвоениеadj
делаетadj
указание на первый элемент.
Ответ №1:
Я хочу спросить, почему он считает, что
list<int> *adj;
это массив списков смежности ….
Это не массив, это указатель на list<int>
. Указатели не являются массивами.
Я думаю, что это всего лишь динамический массив, но не массив списков?
Это не динамический массив.
Что автор пытается сказать, но очень неуклюже, так это то, что указатель в конечном итоге укажет на область в памяти, которая будет содержать непрерывный буфер std::list<int>
объектов, отсюда и использование термина «динамический массив».
В примере буфер создается с помощью строки:
adj = new list<int>[V];
в Graph
конструкторе. Это создает V
std::list<int>
объекты в непрерывной памяти и adj
будет указывать на первый в списке.
Проблема с кодом заключается в том, что автор мог бы использовать лучший инструмент для этой работы: std::vector<std::list<int>>
.
Использование std::vector
приведет
- Избавьтесь от использования необработанных указателей.
- Значительно упрощает обработку динамических массивов.
- Делает код, который вы пишете, меньше и менее подвержен ошибкам.
- Устраняя необходимость в
new[]
иdelete[]
Прямо сейчас в этом Graph
классе происходят утечки памяти. Если вы используете его где угодно, кроме как в игрушечной программе, он быстро становится непригодным для использования, пока не будет введена надлежащая семантика копирования путем написания определяемого пользователем конструктора копирования, определяемого пользователем оператора присваивания и деструктора.
Вот перезапись Graph
класса:
#include <iostream>
#include <list>
#include <vector>
class Graph
{
std::vector<std::list<int>> adj;
public:
Graph(int V);
void addEdge(int v, int w);
void BFS(int s);
};
Graph::Graph(int V) : adj(V) {}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w);
// and if you want to add some debugging for boundary conditions,
// replace previous line with
// adj.at(v).push_back(w);
}
Весь этот класс можно безопасно использовать в любом контексте. Обратите внимание, что в V
переменной-члене нет необходимости, поскольку adj.size()
известно, что V
такое.