本文出自:Svitter的Blog 以及 Github
图论Graph
8/8/2014 9:23:16 AM
图的基本概念
图的定义 Defination
- 图是由顶点集合(Vertex)及顶点间的关系集合(边Edge)组成的一种数据结构: > Graph=( V, E )
-
顶点Vertex
V = {x | x ∈ 某个数据对象}
-
边的集合Edge
E = {(x, y) | x,y ∈ V }
E = {(x, y) | x, y ∈ V && path(x,y)
-
Path(x, y)表示从x到y的一条单向通路——说明什么?<!--(有方向)-->
- 由此我们可以得出
有向图 && 无向图 ||( Directed graph && Oriented graph)
-
在有向图中,顶点对是有序的。
-
在无向图中,顶点对( x, y )是无序的。
完全图 Complete graph
- 有n个顶点的无向图有n(n-1)/2条边,则此图为无向完全图(为什么?)<!--除了他本身,可以到达具有任何一个顶点的边 -->
- 有n个顶点的有向图有n(n-1)条边,则此图为有向完全图 (这又是为什么?)
邻接顶点 (Adjacency Vertex)
- 如果(u, v) 是 E(G) 中的一条边,则称 u 与 v 互为邻接顶点
- 两个顶点之间有一条有向边,则称两个顶点相邻
子图 Subgraph
- 设有两个图G=(V, E) 和G'=(V', E')。若V'≤ V 且E≤'E, 则称图G'是图G的子图
权 Weights
- 某些图的边具有与它相关的数, 称之为权。这种带权图叫做网络
顶点的度 (degrees of the vertices)
- 一个顶点v的度是与它相关联的边的条数。记作TD(v)。
- 在有向图中, 顶点的度等于该顶点的入度(in-degree)与出度(out-degree)之和
- 顶点 v 的入度是以 v 为终点的有向边的条数, 记作 ID(v)
- 顶点 v 的出度是以 v 为始点的有向边的条数, 记作 OD(v)
路径 Path
- 在图 G=(V, E) 中, 若从顶点 vi 出发, 沿一些边经过一些顶点 vp1, vp2, …, vpm,到达顶点vj。则称顶点序列 (vi vp1 vp2 ... vpm vj) 为从顶点vi 到顶点 vj 的路径。它经过的边(vi, vp1)、(vp1, vp2)、...、(vpm, vj) 应是属于E的边。 ###路径长度
- 非带权图的路径长度是指此路径上边的条数。
- 带权图的路径长度是指路径上各边的权之和。 ###简单路径
- 若路径上各顶点 v1, v2, ..., vm 均不 互相重复, 则称这样的路径为简单路径 ###回路 loop
- 若路径上第一个顶点 v1 与最后一个顶点vm 重合, 则称这样的路径为回路或环
连通图与连通分量
- 在无向图中, 若从顶点v1到顶点v2有路径, 则称顶点v1与v2**连通**。
- 如果图中任意一对顶点都是连通的, 则称此图是连通图。
- 非连通图的极大连通子图叫做连通分量。
强连通图与强连通分量
- 在有向图中, 若对于每一对顶点vi和vj, 都存在一条从vi到vj和从vj到vi的路径, 则称此图是强连通图。(任意两个顶点相互可达)
- 非强连通图的极大强连通子图叫做强连通分量。
生成树(Spaning tree)
- 一个连通图的生成树是其极小连通子图,在 n 个顶点的情形下,有 n-1 条边。
图的基本知识就到这里了,如果有必要可以继续往下看。
特别注意的点
悬挂点
- 度数为1的点为悬挂点,与之相关联的边称为悬挂边。
握手定理
- 所有顶点的度数等于边数的两倍
- 在任何顶点中,奇度顶点的个数是偶数 (为什么?)
欧拉图
- a = 通过图中所有边有且仅有一次行遍所有顶点的通路,称为欧拉通路
- b = 通过图中所有边有且仅有一次行遍所有顶点的回路,称为欧拉回路
- a && b为欧拉图, a && ~b为半欧拉图
无向图是欧拉图当且仅当G是连通图且没有奇度顶点
- 证明比较难讲,但是想起来很好想,如果有了奇度顶点,出去怎么回来?
相关文献:哥尼斯堡七桥问题
- 有向图G是半欧拉图的条件是G是连通的且恰有两个奇度顶点
- 有向图D是欧拉图的条件是 当且仅当D是强联通的且每个顶点的入度 == 出度
哈密顿图
- a = 通过图中所有顶点一次且仅一次的通路称为哈密顿通路
- b = 通过图中所有顶点一。。。。。。。。。回路称为哈密顿回路
-
平凡图属于哈密顿图。
-
树也是图。树是什么样的图?顶点为n,边数为n-1的图
空图
- 顶点集为空的图,定义为空图
孤立点
- 没有关联边的顶点称为孤立点
图的表示方法 C语言
邻接矩阵(Adjacency Matrix)
逻辑结构
- 在图的邻接矩阵表示中,有一个记录各个顶点信息的顶点表,还有一个表示各个顶点之间关系的邻接矩阵。
- 设图 A = (V, E) 是一个有 n 个顶点的图, 图的邻接矩阵是一个二维数组 A.edge[n][n],定义
存储结构
- 最简单的形式就是使用一个二维数组来存储,由于太过简单,这里就不展示了。
邻接表
逻辑结构
- 邻接表是邻接矩阵的改进形式。为此需要把邻接矩阵的各行分别组织为一个单链表。
- 在邻接表中,同一个顶点发出的边链接在同一个边链表中,每一个链结点代表一条边(边结点),结点中有另一顶点的下标 dest 和指针 link。对于带权图,边结点中还要保存该边的权值cost。
- 顶点表的第 i 个顶点中保存该顶点的数据,以及它对应边链表的头指针adj。
- 你联想到了什么?
存储结构
- 使用vector来实现,或者使用new开辟新的数组
- code
#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
//If G is a tree
//half of n is enough;
#define MAXN 1000
// N 为节点个数
typedef vector <int> vint;
vector <vint> G(MAXN);
//遍历使用clear()函数, 清空使用的空间
void Insert(int a, int i)
{
G[a].push_back(i);
}
void DFS(int v)
{
for(int i = 0; i < G[v].size(); i++)
DFS(G[v][i]);
}
int main()
{
G.clear();
return 0;
}
存边的写法,类似于哈希表中的拉链法
struct Arc
{
int next_arc;
int point;
};
#define MAXN 1000
#define MAXE 1000
int node[MAXN];
Arc arc[E];
// 以u开始,以v结束
int EdgeCount = 0;;
void AddEdge(int u, int v)
{
arc[EdgeCount].next_arc = node[u];
arc[EdgeCount].point = v;
node[u] = EdgeCount;
EdgeCount++;
}