先貼代碼, 先貼簡要的解釋,週末更新.
- 鄰接表的實現
#ifndef __ADJ_GRAPH__
#define __ADJ_GRAPH__
#include <iostream>
#include <vector>
struct ArchNode {
int adj_vertex;
ArchNode* next;
};
struct VertexNode {
int vertex_id;
ArchNode* first;
ArchNode* tail;
};
struct Arch {
int beg_vnode_idx, end_vnode_idx;
int weight;
Arch(int i, int j, int w):
beg_vnode_idx(i), end_vnode_idx(j),
weight(w) {}
Arch(const Arch& other) {
if (this != &other) {
beg_vnode_idx = other.beg_vnode_idx;
end_vnode_idx = other.end_vnode_idx;
weight = other.weight;
}
}
std::pair<int, int> GetPair() {
return std::make_pair(beg_vnode_idx, end_vnode_idx);
}
int GetWeight() {
return weight;
}
};
enum GraphType {
UDG, // 無向圖;
DG // 有向圖;
};
template <unsigned T>
class AdjacentListGraph {
public:
AdjacentListGraph(GraphType graph_type, int e, int n = T);
AdjacentListGraph(GraphType graph_type, int e, const std::vector<Arch>& arch_list);
void CreateAdjacentList(GraphType g);
void AddToArchList(Arch* arch) {
arch_list_.push_back(arch);
}
void InsertArch(int vertex_idx, int adjacent_node_idx);
void MakeArchList(const std::vector<Arch>& arch_list);
void MakeArchList(const std::pair<int, int>*, size_t);
void TopologicalSort();
private:
VertexNode* vertex_nodes_;
std::vector<Arch*> arch_list_;
int vertex_num_;
int arch_num_;
GraphType graph_type_;
};
////////////////////////////////////////////////////////////////////////////////
template <unsigned T>
AdjacentListGraph<T>::AdjacentListGraph(GraphType graph_type, int e, int n) :
vertex_num_(n),
arch_num_(e),
graph_type_(graph_type) {
vertex_nodes_ = new VertexNode[vertex_num_];
for (int i = 0; i < vertex_num_; ++i) {
vertex_nodes_[i].vertex_id = i + 1;
vertex_nodes_[i].first = nullptr;
vertex_nodes_[i].tail = nullptr;
}
if (arch_num_ <= 0) return;
std::cout << "input the arch data: (v1, v2, weight)" << std::endl;
int i, j, w;
int count = 0;
while (count++ < arch_num_) {
std::cin >> i >> j >> w;
Arch* arch = new Arch(i, j, w);
AddToArchList(arch);
}
CreateAdjacentList(graph_type_);
}
template <unsigned T>
AdjacentListGraph<T>::AdjacentListGraph(GraphType graph_type, int e, const std::vector<Arch>& arch_list) :
vertex_num_(T),
arch_num_(e),
graph_type_(graph_type) {
vertex_nodes_ = new VertexNode[vertex_num_];
for (int i = 0; i < vertex_num_; ++i) {
vertex_nodes_[i].vertex_id = i + 1;
vertex_nodes_[i].first = nullptr;
vertex_nodes_[i].tail = nullptr;
}
if (arch_num_ <= 0) return;
MakeArchList(arch_list);
CreateAdjacentList(graph_type_);
}
template <unsigned T>
void AdjacentListGraph<T>::MakeArchList(const std::vector<Arch>& arch_list) {
for (auto archItem : arch_list) {
auto arch = new Arch(archItem);
AddToArchList(arch);
}
}
template <unsigned T>
void AdjacentListGraph<T>::MakeArchList(const std::pair<int, int>* arch_list, size_t size) {
for (unsigned int i = 0; i < size; ++i) {
auto arch = new Arch(arch_list[i].first, arch_list[i].second, 0);
AddToArchList(arch);
}
}
template <unsigned T>
void AdjacentListGraph<T>::CreateAdjacentList(GraphType t) {
for (auto arch : arch_list_) {
auto pair = arch->GetPair();
// std::cout << "pair.first=" << pair.first << ", pair.second=" << pair.second;
int head = pair.first, end = pair.second;
InsertArch(head, end);
if (t == UDG) {
InsertArch(end, head);
}
}
}
template <unsigned T>
void AdjacentListGraph<T>::InsertArch(int vertex_idx, int adjacent_node_idx) {
ArchNode* a = new ArchNode{adjacent_node_idx, nullptr};
VertexNode& v = vertex_nodes_[vertex_idx - 1];
v.tail == nullptr ? v.first = a : v.tail->next = a;
v.tail = a;
}
template <unsigned T>
void AdjacentListGraph<T>::TopologicalSort() {
const size_t n = vertex_num_;
int in_degree[n] = {0};
std::vector<int> result;
// initialize in_degree array, set up the in_degree array
for (int i = 0; i < vertex_num_; ++i) {
auto& m = vertex_nodes_[i];
ArchNode* x = m.first;
if (x == nullptr)
continue;
int j = x->adj_vertex;
++in_degree[j - 1];
while ((x = x->next)) {
j = x->adj_vertex;
++in_degree[j - 1];
}
}
int count = 0;
while (count++ < vertex_num_) {
// find the node that its in-degree is 0;
int start_idx = -1;
for (int j = 0; j < vertex_num_; ++j) {
if (in_degree[j] == 0) {
start_idx = j;
break;
}
}
// when execute to some point, there is no node whose in-degree
// is 0, we quit from the loop;
if (start_idx == -1)
break;
result.push_back(start_idx);
ArchNode* a = vertex_nodes_[start_idx].first;
while (a) {
in_degree[a->adj_vertex - 1]--;
a = a->next;
}
in_degree[start_idx] = -1;
}
if (count < vertex_num_)
std::cout << "not fully resolved DAG" << std::endl;
std::cout << "Topological sort result is:";
for (auto it : result) {
int k = it;
std::cout << k + 1 << " ";
}
std::cout << std::endl;
}
#endif
測試:
#include <iostream>
#include <vector>
#include "adj_graph.h"
int main() {
Arch dag_arches[] = {
{1, 2, 0}, {1, 4, 0}, {2, 4, 0}, {2, 3, 0},
{3, 5, 0}, {4, 3, 0}, {4, 5, 0}
};
AdjacentListGraph<5> dag(DG, sizeof(dag_arches), std::vector<Arch>(std::begin(dag_arches), std::end(dag_arches)));
dag.TopologicalSort();
return 0;
}
-
鄰接矩陣的實現
- matrix_graph.h 頭文件
#include <iostream>
#include <unordered_map>
enum GraphType {
DG, // 有向圖
UDG // 無向圖
};
struct Arch {
int beg_vertex_idx;
int end_vertex_idx;
int weight;
Arch(int i, int j, int w):
beg_vertex_idx(i), end_vertex_idx(j),
weight(w) {}
Arch(const Arch& other) {
if (this != &other) {
beg_vertex_idx = other.beg_vertex_idx;
end_vertex_idx = other.end_vertex_idx;
weight = other.weight;
}
}
std::pair<int, int> GetPair() {
return std::make_pair(beg_vertex_idx, end_vertex_idx);
}
int GetWeight() {
return weight;
}
};
struct VertexNode {
int vertex_id;
};
class ADJMatrixGraph {
public:
ADJMatrixGraph(GraphType type, const int vertex_num, struct Arch arch_list[], const int arch_num);
void print_matrix();
void TopologicalSort();
private:
void AddToArchList(Arch arch) {
std::pair<int, int> arch_pair = arch.GetPair();
std::string s = std::to_string(arch_pair.first - 1) + "_" + std::to_string(arch_pair.second - 1);
arch_list_.insert(std::make_pair(s, arch));
}
void MakeArchList(struct Arch arch_list[], size_t arch_num);
void CreateADJMatrixGraph(GraphType);
GraphType graph_type_;
int vertex_num_;
int arch_num_;
VertexNode* vertex_nodes_;
std::unordered_map<std::string, Arch> arch_list_;
void* matrix_;
};
matrix_graph.cc
#include <stdio.h>
#include <vector>
#include "matrix_graph.h"
ADJMatrixGraph::ADJMatrixGraph(GraphType type, const int vertex_num, struct Arch arch_list[], const int arch_num):
graph_type_(type),
vertex_num_(vertex_num),
arch_num_(arch_num),
vertex_nodes_(new VertexNode[vertex_num]) {
MakeArchList(arch_list, arch_num);
CreateADJMatrixGraph(type);
}
void ADJMatrixGraph::MakeArchList(struct Arch arch_list[], size_t arch_num) {
for (unsigned int i = 0; i < arch_num; ++i) {
auto arch = arch_list[i];
AddToArchList(arch);
// auto p = arch.GetPair();
// int z = p.first, y = p.second;
if (graph_type_ == UDG) {
// TODO(cangpeng): to handle symmetrics arch for UDG
}
}
}
void ADJMatrixGraph::print_matrix() {
int n = vertex_num_;
int (*matrix_arr)[n][n] = static_cast<int (*)[n][n]>(matrix_);
for (int i = 0; i < n; ++i) {
std::cout << "\ni=" << i << ":";
for (int j = 0; j < n; ++j) {
std::cout << *(*(*matrix_arr + i) + j) << " ";
}
}
std::cout << std::endl;
}
void ADJMatrixGraph::CreateADJMatrixGraph(GraphType type) {
int n = vertex_num_;
void* matrix = malloc(sizeof(int) * n * n);
int (*matrix_arr)[n][n] = static_cast<int (*)[n][n]>(matrix);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
std::string s = std::to_string(i) + "_" + std::to_string(j);
auto archIt = arch_list_.find(s);
if (archIt != arch_list_.end()) {
*(*(*matrix_arr + i) + j) = (archIt->second).GetWeight();
} else {
*(*(*matrix_arr + i) + j) = 0;
}
}
}
matrix_ = matrix;
}
void ADJMatrixGraph::TopologicalSort() {
const size_t n = vertex_num_;
// using matrix_arr = int[n][n];
int in_degree[n] = {0};
std::vector<int> result;
// matrix_arr* matrix = static_cast<matrix_arr*>(matrix_);
int (*matrix)[n][n] = static_cast<int (*)[n][n]>(matrix_);
// initialize in_degree array, set up the in_degree array;
for (unsigned int i = 0; i < n; ++i) {
for (unsigned int j = 0; j < n; ++j) {
// std::cout << "matrix:" << i << ", " << j << ":"
// << *(*(*matrix + i) + j) << ", " << matrix[i][j] << std::endl;
if (*(*(*matrix + i) + j) > 0) {
in_degree[j]++;
}
}
}
unsigned int count = 0;
while (count++ < n) {
int start_idx = -1;
for (unsigned int j = 0; j < n; ++j) {
if (in_degree[j] == 0) {
start_idx = j;
break;
}
}
// when execute to some point, there is no node whose in-degree
// is 0, we quit from the loop;
if (start_idx == -1)
break;
result.push_back(start_idx);
for (unsigned int k = 0; k < n; ++k) {
// if (matrix[start_idx][k] > 0) {
if (*(*(*matrix + start_idx) + k) > 0) {
in_degree[k]--;
}
}
in_degree[start_idx] = -1;
}
if (count < n)
std::cout << "not fully resolved DAG" << std::endl;
std::cout << "Topological sort result is:";
for (auto it : result) {
int k = it;
std::cout << k + 1 << " ";
}
std::cout << std::endl;
}
測試
#include "matrix_graph.h"
int main() {
struct Arch dag_arches[] = {
{1, 2, 1}, {1, 4, 1}, {2, 4, 1}, {2, 3, 1},
{3, 5, 1}, {4, 3, 1}, {4, 5, 1}
};
ADJMatrixGraph matrix_graph(DG, 5, dag_arches, 7);
matrix_graph.print_matrix();
matrix_graph.TopologicalSort();
return 0;
}
踩坑
- 用nontype template實現鄰接表。 注意template的類實現,在真正出創建template實例的對象之前,不會真正實例化template類, 也就沒有符號表中某些元素, 如template類的構造函數; 只有在創建template類的定義時, 纔會在.o文件中出現該符號; 忽略此點, 很容易出現不理解的undefined reference to xxx錯誤;
- 由於以上此點約束, 使用template類常常只有把全部實現寫在.h文件中; 這樣不利於模塊化代碼;
- 鄰接矩陣實現使用malloc; 在gdb中輸出using過的type是有問題的; 需要使用原始的指針定義;