一、概念
1. 数据结构
一般情况下,我们会将数据结构分为逻辑结构和物理结构,其中逻辑结构是我们的逻辑下存储的结构,而物理结构是计算机的逻辑下存储的结构。数据结构的分类可以参见下表:
2. 图
图(graph)是一种点和点之间多对多关系所组成的数据结构。图也是由顶点的非空集合 V V V 和边的集合 E E E 组成的,表示为 G = ( V , E ) G=(V,E) G=(V,E)。一般地,我们用 V ( G ) V(G) V(G) 表示图 G G G 的顶点集,用 E ( G ) E(G) E(G) 表示图 G G G 的边集。
3. 图的术语
图中的点称为 顶点。
图中的点与点所具有的练习称为 边。
点和点的关系称为 邻接。
点与边的关系称为 关联。
有些图点和点之间的关系是相互的,这种图被称为 无向图,无向图的边一般用 ( x , y ) (x, y) (x,y) 来表示,也可以写作 ( y , x ) (y, x) (y,x)。
有些图点和点之间的关系是单向的,这种图被称为 有向图,无向图中由顶点出发的边称为 出边,指向顶点的边称为 入边。有向图的边一般用 < x , y > <x, y> <x,y> 来表示,不可以写作 < y , x > <y, x> <y,x>,因为方向不一样。
图中的边带有某种与之相关的数值,我们称之为 权值,边带有权值的图通常称为 网(加权图)。
如果图是有向的,称为 加权有向图。
如果图是无向的,称为 加权无向图。
没有自环和重边的图就属于 简单图。
对于有很少条边的图(
e
<
n
log
2
n
e<n \log_2n
e<nlog2n)称为 稀疏图,反之称为 稠密图。
一个图从任意一个顶点可以到另外任意一个顶点(不一定直接联通),则称为 连通图。
一个图从任意两个顶点可以互相到达(不一定直接联通),则称为 强连通图。
从图中提取出的图(可以是空图、一个顶点、图本身)称作 子图。
没有重复顶点的一条路径称为 简单路径。
起点和终点相同的路径称为 回路(环)。
4. 图的公式
如果在无向图中,任意两个顶点都有一条边直接相连,这时就称该图为 无向完全图。具有 n n n 个顶点的无向完全图具有 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n−1) 条边。
如果在有向图中,任意两个顶点都有两条边(双向)直接相连,这时就称该图为 有向完全图。具有 n n n 个顶点的无向完全图具有 n ( n − 1 ) n(n-1) n(n−1) 条边。
无向图中,顶点
v
v
v 的 度 指的是与该顶点相关联的边的数目。
有向图中,顶点
v
v
v 的 度 分别是 入度 和 出度。
一个具有
n
n
n 个顶点,
e
e
e 条边的图,其所有顶点的度数之和等于边数的
2
2
2 倍。
一个简单无向图中有
x
x
x 条边,每个顶点的度数都是
y
y
y,则这个图有
2
x
y
\frac{2x}{y}
y2x 个顶点。
二、例题
1. 绘制图
{ V ( G ) = 1 , 2 , 3 , 4 , 5 E ( G ) = ( 1 , 3 ) , ( 1 , 4 ) , ( 2 , 4 ) , ( 3 , 5 ) , ( 5 , 2 ) \begin{cases} V(G) &= {1,2,3,4,5} \\ E(G) &= {(1,3),(1,4),(2,4),(3,5),(5,2)} \end{cases} {V(G)E(G)=1,2,3,4,5=(1,3),(1,4),(2,4),(3,5),(5,2)
这种题目是没有固定画法的。我们首先根据小括号确定这是一个无向图。这个图可以画成五边形、五角星等等。
{ V ( G ) = 1 , 2 , 3 , 4 E ( G ) = < 1 , 2 > , < 2 , 3 > , < 3 , 4 > , < 4 , 1 > \begin{cases} V(G) &= {1,2,3,4} \\ E(G) &= {<1,2>,<2,3>,<3,4>,<4,1>} \end{cases} {V(G)E(G)=1,2,3,4=<1,2>,<2,3>,<3,4>,<4,1>
根据尖括号确定这是一个有向图。可以画成正方形、漏斗形等等。
2. 带权邻接矩阵
#include <iostream>
#include <cstring>
using namespace std;
int n, m;
int a, b, c;
int adj[105][105];
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
cin >> a >> b >> c;
adj[a][b] = c;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (adj[i][j] == 0) cout << "* ";
else cout << adj[i][j] << " ";
}
cout << endl;
}
return 0;
}
3. 优化带权邻接矩阵
我们可以考虑优化,用二维动态结构体数组来存储这一系列的内容。
#include <iostream>
#include <vector>
using namespace std;
struct Node
{
int v, w; // v: 点 w: 权值
};
int n, m;
int a, b, c;
vector <Node> adj[105];
int main()
{
cin >> n >> m;
while (m--)
{
cin >> a >> b >> c;
adj[a].push_back({b, c});
}
for (int i = 1; i <= n; i++)
{
cout << i << ":";
for (int j = 0; j < adj[i].size(); j++)
cout << adj[i][j].v << " ";
cout << endl;
}
return 0;
}