Я рассматривал некоторые примеры того, как создать правильный конструктор для векторов, и им все еще путают, как его реализовать. Используя данный класс...
class Graph
{
private:
class Edge
{
public:
Edge(string vertex, int weight)
{
m_vertex = vertex;
m_weight = weight;
}
~Edge(){}
string m_vertex;
int m_weight;
};
vector< list<Edge> > adjList; //vector of lists
public:
Graph();
~Graph();
vector < list < Edge > > get_adjList(){return adjList;}
//Other functions....
};
Я все еще не уверен, что добавить в конструктор Graph::Graph()
Я попытался сделать несколько вещей, таких как
Graph::Graph()
{
new vector < list < Edge > >;
}
Но мне сказали, что это вызывает утечку памяти. Ive только когда-либо делал конструкторы для связанных списков раньше и никогда не нуждался в одном для векторов до сих пор. Я мог бы использовать некоторую ясность в том, как создать конструктор для вектора списков. Мне нужен конструктор, поэтому я могу получить доступ к элементу списка (списка векторов) в других файлах, чтобы его скопировать.
В вашем Graph
уже есть элемент-член vector< list< Edge > > adjList
который выделяется и конструируется для вас при построении Graph
. Вам не нужно писать какой-либо конструктор.
Вызов new
здесь можно полностью удалить:
Graph::Graph()
{
new vector < list < Edge > >; // DELETE THIS LINE
}
Как бы то ни было, он выделяет полностью отдельный vector< list< Edge > >
и затем отбрасывает указатель, возвращенный new
. Но, судя по всему, вы все равно не нуждались в этом. Ваш член adjList
уже существует, пуст и ждет данных. Вам не нужно было вызывать new
или что-то еще.
То, что вам нужно, - это некоторый способ заполнить член adjList
. Вы можете сделать это в Graph::Graph()
или вне кода.
Ваша текущая функция getter, get_adjList()
настоящее время возвращает копию adjList
, а не ссылку. Возможно, вы захотите изменить этот метод, чтобы вернуть ссылку:
vector < list < Edge > >& get_adjList() {return adjList;}
Или указатель:
vector < list < Edge > >* get_adjList() {return &adjList;}
так что код вне класса может вызвать get_adjList()
а затем манипулировать полем внутри класса.
Что-то вроде этого:
Graph my_graph;
vector< list<Edge> >& adjList = my_graph.get_adjList();
// Make a graph with two nodes, both pointing at each other, with weight 10
adjList.resize( 2 ); // make room for two nodes
adjList[0].push_back( Edge( 1, 10 ) );
adjList[1].push_back( Edge( 0, 10 ) );
Чтобы ваши пальцы не отваливались от наложения vector< list<Edge> >
снова и снова, вы можете добавить typedef
внутри class Graph
:
class Graph
{
public:
typedef vector< list< Edge > > adj_type;
// ...
};
А затем снаружи вы могли бы сказать что-то вроде:
Graph::adj_type& adjList = my_graph.get_adjList();
Это также изолирует остальную часть кода от точного определения adj_type
если вы измените его позже.
Вы должны в конечном итоге рассмотреть возможность добавления методов в Graph
для добавления вершин и ребер. Что-то вроде:
class Graph
{
//...
public:
void add_vertex( unsigned id )
{
if (id > adjList.size() )
adjList.resize( id );
}
void add_edge( unsigned from_id, unsigned to_id, int weight )
{
adjList[fromId].push_back( Edge( to_id, weight ) );
}
}
Непроверенный код, но вы получите эту идею, надеюсь.
Последняя мысль: Почему m_vertext
строка в Edge
? Я просто заметил это, и это кажется очень странным.
Если ваши вершины не являются числовыми, вам следует использовать map< string, list<Edge> >
вместо vector
для вашего adjList
. Или добавьте map<string, unsigned>
чтобы сопоставить строки с идентификаторами. В противном случае вы не сможете эффективно преследовать края до вершин.
m_vertex
который является строкой, в то, что вы можете индексировать adjList
? Вы делаете кучу строк в целочисленные преобразования?
Я согласен с @joe-z. Однако, я думаю, проблема может заключаться в том, что ему нужен вектор определенного размера.
struct Edge { // you could template this to make more generic.
int v2;
double weight;
};
class Graph {
public:
Graph(size_t size) : m_adj_list(size) {}
void AddEdge(int v1, int v2, double weight) {
m_adj_list[v1].emplace_back(v2, weight);
}
void Resize(size_t size) {
m_adj_list.resize(size, std::vector<Edge>());
}
private:
// You can use a list but in general a vector might be a better choice
std::vector<std::vector<Edge>> m_adj_list;
};
К тому же. Не просто используйте голые указатели. Используйте std :: unique_ptr или std :: shared_ptr. В общем случае вы можете использовать правило (в этом порядке):
Если ваш класс графа может читать из файла, то ваш конструктор для класса может выглядеть примерно так:
Graph::Graph(istream &iss)
{
// number of vertices in the graph
// where each vertex has a list of edges
size_t vertices;
iss >> vertices;
adjList.resize(vertices);
...
}
Помимо установки размера вектора, нет необходимости динамически выделять пространство для вектора, если вы не объявите вектор как указатель в своем классе.
Теперь, чтобы получить доступ к вектору, вы можете создать метод getter в своем классе, который возвращает копию вектора (если вы не хотите, чтобы оригинал был мутирован), или getter может вернуть ссылку/указатель на фактический объект
Я вернул класс графа некоторое время назад, а другой вариант, который вы, возможно, захотите изучить, - это конструктор, который может создать случайный объект графика, заданный для density
, maxedgeLength
и numberofvertices
.
Вам не нужно использовать new
, adjList
уже является vector
переменной в стеке, если вы создаете экземпляр Graph
(это не Java), и я думаю, что векторный конструктор по умолчанию достаточно, не нужно его явно называть. Вам нужно вызывать new
только если ваша переменная указатель.
Но вам может потребоваться изменить возвращаемый тип get_adjList
чтобы просто вернуть ссылку adjList
, а не новую копию adjList
.
class Graph
{
private:
vector<list<Edge> > adjList; //vector of lists
public:
Graph();
~Graph();
vector<list<Edge> > &get_adjList(){return adjList;}
};
Или, может быть, если вам нужен vector
элемент, лучше не возвращать vector
, просто верните элемент на основе индекса запроса, например:
list<Edge> &get_adjListElmt(int idx){return adjList[idx];}
new
оператор вызывает утечку памяти, потому что он создаетvector< list< Edge > >
но нигде не захватывает указатель на него. Это просто выбрасывает это. ЧленadjList
в вашем классе выделяется для вас, когда вы выделяетеGraph
, поэтому нет необходимости создаватьnew
отдельный в вашем конструкторе.get_adjList()
должен возвращать новую новую копиюadjList
. Похоже, что он должен возвращать ссылку на тот, что внутриGraph
. То есть, похоже, что возвращаемый тип должен бытьvector< list< Edge > >&
.