图的基本性质
顶点(vertex)
上图中黑色的带数字的点就是顶点,表示某个事物或对象。由于图的术语没有标准化,因此,称顶点为点、节点、结点、端点等都是可以的。叫什么无所谓,理解是什么才是关键。
边(edge)
上图中顶点之间蓝色的线条就是边,表示事物与事物之间的关系。需要注意的是边表示的是顶点之间的逻辑关系,粗细长短都无所谓的。包括上面的顶点也一样,表示逻辑事物或对象,画的时候大小形状都无所谓。
有向/无向图(Directed Graph/ Undirected Graph)
有向图和无向图,两者的区别在于,有向图中的边是有方向性的。(可以把无向图视为“双向”的有向图,构造无向图用的就是这种方法)
一般到底是有向图还是无向图要根据实际情况判断,比如在A、B两点之间的一条路,那一定是个无向图。
权重(weight)
边的权重(或者称为权值、开销、长度等),即每条边都有与之对应的值。例如当顶点代表某些地点时,两个顶点间边的权重可以为两点的距离。
连通图/连通分量(connected graph/connected component)
如果在图G中,任意2个顶点之间都存在路径,那么称G为连通图(注意是任意2顶点)。如果把下图看为两个图,就是两个连通图。
连通分量也叫最(极)大连通子图,把上图看为一个整体,它不是一个连通图,但它有多个连通子图,0,1,2,3,4顶点构成的子图就是该图的最大连通子图。
注意:对于连通图来说,它的最大连通子图就是其本身。
图的表示
邻接矩阵
用二维数组直接存储。
邻接矩阵非常好写,只需要开一个二维数组,但顶点数目太大会超内存(一般不大于1000),用到的情况比较少。
邻接表
存储示意图:
可理解看做是多条单链表,结构体定义如下:
struct ENode { int dis, to;//权重、指向 ENode* next = NULL; void push(int to, int dis) { ENode* p = new ENode; p->to = to; p->dis = dis; p->next = next; next = p; } }head[100];
完整测试:
#include <iostream> #include <fstream> using namespace std; typedef long long LL; struct ENode { int dis, to;//权重、指向 ENode* next = NULL; void push(int to, int dis) { ENode* p = new ENode; p->to = to; p->dis = dis; p->next = next; next = p; } }*head; int main() { #ifdef LOCAL fstream cin("data.in"); #endif // LOCAL /* 5 8 1 3 4 2 4 3 4 5 6 1 5 7 3 5 4 3 4 3 2 5 6 4 1 7 */ int n, m; //n个定点,m条边 cin >> n >> m; head = new ENode[n + 1]; for (int i = 0; i < m; i++) { int from, to, dis; cin >> from >> to >> dis; head[from].push(to, dis); } for (int i = 1; i <= n; i++) { cout << i; ENode* p = head[i].next; while (p) { if (p)cout << "-->"; cout << p->to; p = p->next; } cout << endl; } return 0; }
其他一些术语
关节点
也叫重连通分量,在连通图 G 中,如果删除顶点 u 及从 u 出发的所有边后所得的子图不连通,我们就称顶点 u 为图 G 的关节点或连接点。
生成树
树(Tree):如果一个无向连通图中不存在回路,则这种图称为树。
生成树 (Spanning Tree):无向连通图G的一个子图如果是一颗包含G的所有顶点的树,则该子图称为G的生成树。
生成树是连通图的极小连通子图。这里所谓极小是指:若在树中任意增加一条边,则将出现一条回路;若去掉一条边,将会使之变成非连通图。