目录
前言
0. 声明和引用
1. 节点模板
2. 边模板
3. 图模板
本文记录了三个图算法常用类的创建模板,小伙伴们可以根据需要取用,实际使用时根据需求更改即可。本文中记录的代码模板并不一定是运行效率最高的,但个人认为可以作为基础模板进行更改。文中使用的边类型是按照有向边来设计的,使用时可以自行修改为无向边,或者使用成对使用有向边。要注意,用本文中的类实例化出的类所记录的信息可能是冗余的,比如所有节点都记录了从它们自己出发的边和临近的节点,如果边和节点以相同顺序记录那么在边类型中记录起始节点和终点节点就是冗余的。再比如节点的出度也可以从边的集合中直接算出。但这样构建代码我认为在对代码效率要求不是非常高的场合能更清晰一些。更符合面向对象编程的要求。
因为图类型用到了哈希表,所以也要提前引用unordered_map/set。并且图类前自定义的哈希函数类用到了STL给的hash函数,所以hashtable.h也要引用。typeinfo是用来提取类名称信息的。
#include
#include
#include
#include
#include
#include
#include
class Edge;
class Node;
class Graph;
using namespace std;
节点模板主要记录了节点的名字、出度、入度、相邻的节点的集合还有从该节点引出的边的集合。构造函数有两种,可以通过在实例化时初始化全部属性,也可以只输入节点名创建空节点。“==”运算符被重载用于进行可哈希化。通过“==”号的重载,我们可以避免在创建哈希表时重新定义equel函数。
相邻节点的集合还有引出的边的集合都是用顺序表来实现的,因为考虑一般对这两个参数进行遍历的时候通常为顺序遍历。但如果是需要根据节点或者边的信息进行键值查找的场合那么应该改为其他数据结构。
class Node {
public:
int name;
int od;
int id;
vector nexts;
vector edges;
// Full element create
Node(int n, int o, int i, vector ne, vector ed):name(n), od(o), id(i), nexts(ne), edges(ed) {
;
}
// None element create
Node(int n):name(n){
od = 0;
id = 0;
nexts = vector {};
edges = vector {};
}
// Over load == for hash
bool operator==(const Node &B) {
return (name == B.name);
}
};
边类型主要记录了边的权值还有边连接的两个节点。因为是有向边所以连接的节点分为起点和终点。因为边的信息主要由两个节点来定义,所以初始化必须要传入节点信息,边的权值可选,默认为1。“==”运算符被重载用于进行可哈希化。和Node类一样,我们通过“==”号的重载,我们可以避免在创建哈希表时重新定义equel函数。
class Edge {
public:
int weight;
Node from;
Node to;
// Create a weighted edge
Edge(Node f, Node t, int w):from(f), to(t), weight(w) {
;
}
// Create a unweighted edge
Edge(Node f, Node t):from(f), to(t) {
weight = 1;
}
// Over load == for hash
bool operator==(const Edge &B) {
return (from == B.from && to == B.to);
}
};
在创建图模板前先创建了一个哈希类用来将Edge类和Node类进行可哈希化,本文并未利用Node作为key建立hash表,这里只是给出示例。该哈希类重载了()运算符,这样就可以把该类的实例当作一个函数进行调用。函数中传入一个待被哈希的参数。本文中的模板里,Node名是用int型变量记录的,所以可以直接使用STL的hash类进行哈希转换,但是对于不同的Edge,分辨它们所需要的信息既需要起始节点也需要终点节点(一个节点可以引出很多边,也可以被很多边指向)。所以通过观察发现,对于一个Edge存在唯一的出入节点组合与之对应。那么我们就可以将出入节点拼接为字符串进行哈希变换。
图类主要包括了图中所含的所有边和节点。这里用哈希表存储便于按照节点对象和边对象直接查找,也可以用其他的数据结构代替。对于在图中查找节点或者边的时候,通常都是根据节点和边的信息进行键值查找的,所以这里我使用的是哈希表的结构。新建图的构造函数这里只实现了新建空图的方法,如果需要根据已有信息进行图的新建,可以自行定制化处理。
// Make edge objects hashable
template
class Graph_hash {
public:
int operator()(const T& target) {
string tn = typeid(target).name(); // get type name
// hash function for edge
if(tn == "Edge") {
return hash () (to_string(target.from.name) + to_string(target.to.name));
}
// hash function for node
if(tn == "Node") {
return hash () (target.name);
}
// return 0 if default
return 0;
}
};
class Graph {
public:
unordered_map nodes;
unordered_set> edges;
Graph():nodes(unordered_map {}), edges(unordered_set> {}) {
;
}
};