我正在尋找C++中圖形的簡潔和精確的鄰接列表表示。我的節點只是節點ID。這是我如何做到的。只是想知道專家是怎麼想的。有沒有更好的辦法?C++中的鄰接列表實現
這是類實現(沒有什麼幻想,現在不關心公共/私有方法)
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;
class adjList {
public:
int head;
vector<int> listOfNodes;
void print();
};
void adjList :: print() {
for (int i=0; i<listOfNodes.size(); ++i) {
cout << head << "-->" << listOfNodes.at(i) << endl;
}
}
class graph {
public:
vector<adjList> list;
void print();
};
void graph :: print() {
for (int i=0; i<list.size(); ++i) {
list.at(i).print();
cout << endl;
}
}
我的主要函數解析一行輸入文件行。每一行是解釋如下:
<source_node> <node1_connected_to_source_node> <node2_connected_to_source_node <node3_connected_to_source_node> <...>
這裏是主要的:
int main()
{
fstream file("graph.txt", ios::in);
string line;
graph g;
while (getline(file, line)) {
int source;
stringstream str(line);
str >> source;
int node2;
adjList l;
l.head = source;
while (str >> node2) {
l.listOfNodes.push_back(node2);
}
g.list.push_back(l);
}
file.close();
g.print();
getchar();
return 0;
}
我知道我應該補充addEdge()函數adjList類中,而不是從主直接修改它的變量(),但是,現在我只是想知道最好的結構。
編輯: 我的方法有一個缺點。對於具有大量節點的複雜圖形,節點確實是一個結構/類,在這種情況下,我將通過存儲整個對象來複制值。在那種情況下,我想我應該使用指針。例如,對於無向圖,我將在adjList中存儲節點對象的副本(節點1和2之間的連接意味着1的鄰接列表將有2個,反之亦然)。我可以通過將節點對象的指針存儲在adjList而不是整個對象中來避免這種情況。檢查通過這種方法獲益的dfs實現。我需要確保每個節點只被訪問一次。擁有同一節點的多個副本將會使我的生活更加艱難。沒有?
在這種情況下,我的類定義將改變這樣的:
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <map>
using namespace std;
class node {
public:
node() {}
node(int id, bool _dirty): node_id(id), dirty(_dirty) {}
int node_id;
bool dirty;
};
class adjList {
public:
node *head;
vector<node*> listOfNodes;
void print();
~adjList() { delete head;}
};
void adjList :: print() {
for (int i=0; i<listOfNodes.size(); ++i) {
cout << head->node_id << "-->" << listOfNodes.at(i)->node_id << endl;
}
}
class graph {
public:
vector<adjList> list;
void print();
void dfs(node *startNode);
};
void graph::dfs(node *startNode) {
startNode->dirty = true;
for(int i=0; i<list.size(); ++i) {
node *stNode = list.at(i).head;
if (stNode->node_id != startNode->node_id) { continue;}
for (int j=0; j<list.at(i).listOfNodes.size(); ++j) {
if (!list.at(i).listOfNodes.at(j)->dirty) {
dfs(list.at(i).listOfNodes.at(j));
}
}
}
cout << "Node: "<<startNode->node_id << endl;
}
void graph :: print() {
for (int i=0; i<list.size(); ++i) {
list.at(i).print();
cout << endl;
}
}
這是我如何實現main()函數。我正在使用地圖<>以避免重複對象。只有在前面沒有定義的時候才創建一個新對象。通過其ID檢查對象的存在。
int main()
{
fstream file("graph.txt", ios::in);
string line;
graph g;
node *startNode;
map<int, node*> nodeMap;
while (getline(file, line)) {
int source;
stringstream str(line);
str >> source;
int node2;
node *sourceNode;
// Create new node only if a node does not already exist
if (nodeMap.find(source) == nodeMap.end()) {
sourceNode = new node(source, false);
nodeMap[source] = sourceNode;
} else {
sourceNode = nodeMap[source];
}
adjList l;
l.head = sourceNode;
nodeMap[source] = sourceNode;
while (str >> node2) {
// Create new node only if a node does not already exist
node *secNode;
if (nodeMap.find(node2) == nodeMap.end()) {
secNode = new node(node2, false);
nodeMap[node2] = secNode;
} else {
secNode = nodeMap[node2];
}
l.listOfNodes.push_back(secNode);
}
g.list.push_back(l);
startNode = sourceNode;
}
file.close();
g.print();
g.dfs(startNode);
getchar();
return 0;
}
第二個編輯 後烏爾裏希·埃克哈特建議把在節點類鄰接表,這裏是我認爲這是一個更好的數據結構來存儲圖形並進行DFS(),Dijkstra算法()種的操作。請注意,鄰接表在節點類中被合併。
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <map>
using namespace std;
class node {
public:
node() {
}
node(int id, bool _dirty): node_id(id), dirty(_dirty) {
//cout << "In overloaded const\n";
}
int node_id;
bool dirty;
vector<node*> listOfNodes;
};
class graph {
public:
vector<node*> myGraph;
void dfs(node* startNode);
};
void graph::dfs(node* startNode) {
startNode->dirty = true;
for (int j=0; j<startNode->listOfNodes.size(); ++j) {
if (!startNode->listOfNodes.at(j)->dirty) {
dfs(startNode->listOfNodes.at(j));
}
}
cout << "Node: "<<startNode->node_id << endl;
}
我們可以做得比這更好嗎?
最終它取決於你需要用這個圖表做什麼,但你看起來相當合理和簡單。 –
true ...但是有一個問題,儘管...對於無向圖,我將在adjList中存儲節點對象的副本(節點1和2之間的連接意味着1的鄰接列表將有2個,反之亦然)。我可以通過將節點對象的指針存儲在adjList而不是整個對象中來避免這種情況。但是這導致了對堆堆棧的另一次討論。因此想知道人們通常使用什麼。 – Richeek
不是'adjList'只存儲節點索引嗎?你不需要在某處順便定義一個節點類嗎? – didierc