**图(Graph)**G 由两个集合 V 和 E 组成,记为 G = ( V ,E )
在有向图中,顶点对
在无向图中,顶点对 (x, y) 是无序的
用 n 表示图中顶点的数目,用 e 表示边的数目
子图:假设有 2 个图 G = ( V ,E )和 G’ = ( V’ ,E’ ),V’ ⊆ V 且 E’ ⊆ E ,G‘ 为 G 的子图
无向完全图:对于无向图,具有 n(n-1)/2 条边
有向完全图:对于有向图,具有 n(n-1) 条弧
稀疏图:有很少边或弧(如 e < nlog_2(n))的图
稠密图:有较多边或弧的图
权:每条边上具有某种含义的数值
网:带权的图
邻接点:对于无向图 G ,边(v, v’)∈ E,v 和 v’ 互为邻接点,v 和 v‘ 相邻接
度:和顶点 v 相关联的边的数目,记为 TD(v)
入度:以顶点 v 为头的弧的数目,记为 ID(v)
出度:以顶点 v 为尾的弧的数目,记为 OD(v)
路径:从顶点 v 到顶点 v’
路径长度:一条路径上经过的边或弧的数目
回路(环):第一个二顶点和最后一个顶点相同的路径
简单路径:序列中顶点不重复出现的路径
简单回路(简单环):除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路
连通:在无向图 G 中,从顶点 v 到顶点 v’ 有路径,v 和 v’ 是连通的
连通图:对于图中任意两个顶点 v_i ,v_j ∈ V ,v_i 和 v_j 都是连通的
连通分量:无向图中的极大连通子图
强连通图:在有向图 G 中,对于每一对 v_i ,v_j ∈ V,v_i ≠ v_j ,从 v_i 到 v_j 和 v_j 到 v_i 都存在路径
强连通分量:有向图中的极大强连通子图
连通图的生成树:一个极小连通子图,其含有图中全部顶点,但只有足以构成一棵树的 n-1 条边
有向树:有一个顶点的入度为 0 ,其余顶点的入度均为 1 的有向图
生成森林:由若干棵有向树组成,含有图中全部顶点,但只有足以构成若干棵不相交的有向树的弧
邻接矩阵(Adjacency Matrix):表示顶点之间相邻关系的矩阵
G( V ,E )是具有 n 个顶点的图,G 的邻接矩阵是具有如下性质的 n 阶方阵
A [ i ] [ j ] = { 1 若 < v i , v j > 或 ( v i , v j ) ∈ E 0 反 之 A[i][j]=\begin{cases} 1 \quad 若
G 是网,则其邻接矩阵为
A [ i ] [ j ] = { w i , j 若 < v i , v j > 或 ( v i , v j ) ∈ E ∞ 反 之 A[i][j]=\begin{cases} w_{i,j} \quad 若
图的邻接矩阵存储表示
#define MAXSIZE 10
typedef struct {
int vexs[MAXSIZE]; // 顶点表
int arcs[MAXSIZE][MAXSIZE]; // 邻接矩阵
int vexnum; // 图的当前点数
int arcnum; // 图的当前边数
} AMGraph;
void CreateUDN(AMGraph* G) {
printf("Enter vexnum , arcnum: ");
scanf("%d,%d", &(G->vexnum), &(G->arcnum)); // 输入总定点数,总边数
for (int i = 0; i < G->vexnum; i++) // 输入点的信息
{
printf("Enter vex: ");
scanf("%d", &(G->vexs[i]));
}
for (int i = 0; i < G->vexnum; i++) // 初始化邻接矩阵,边的权值置为最大值
{
for (int j = 0; j < G->vexnum; j++)
{
G->arcs[i][j] = INT_MAX;
}
}
for (int i = 0; i < G->arcnum; i++) // 构造邻接矩阵
{
int vex1, vex2, value;
printf("Enter vex1, vex2, value: ");
scanf("%d,%d,%d", &vex1, &vex2, &value); // 输入一条边依附的顶点和权值
int i = LocateVex(G, vex1); // 获取 vex1 在 G 中的位置(下标)
int j = LocateVex(G, vex2); // 获取 vex2 在 G 中的位置(下标)
G->arcs[i][j] = G->arcs[j][i] = value; // 边 和对称边 的权值置为 value
}
printf("Create Success\n");
}
int LocateVex(AMGraph* G, char vex) {
int i = 0;
for (; i < G->vexnum; i++) {
if (G->vexs[i] == vex) {
break;
}
}
return i;
}
优点
缺点
#include
#include
#define MAXSIZE 10
void CreateUDN(AMGraph);
int LocateVex(AMGraph);
void PrintGraph(AMGraph);
typedef struct {
int vexs[MAXSIZE];
int arcs[MAXSIZE][MAXSIZE];
int vexnum;
int arcnum;
} AMGraph;
int main() {
AMGraph G;
CreateUDN(&G);
printf("****************\n");
PrintGraph(G);
printf("****************\n");
}
void CreateUDN(AMGraph* G) {
printf("Enter vexnum , arcnum: ");
scanf("%d,%d", &(G->vexnum), &(G->arcnum));
for (int i = 0; i < G->vexnum; i++)
{
printf("Enter vex: ");
scanf("%d", &(G->vexs[i]));
}
for (int i = 0; i < G->vexnum; i++)
{
for (int j = 0; j < G->vexnum; j++)
{
G->arcs[i][j] = INT_MAX;
}
}
for (int i = 0; i < G->arcnum; i++)
{
int vex1, vex2, value;
printf("Enter vex1, vex2, value: ");
scanf("%d,%d,%d", &vex1, &vex2, &value);
int i = LocateVex(G, vex1);
int j = LocateVex(G, vex2);
G->arcs[i][j] = G->arcs[j][i] = value;
}
printf("Create Success\n");
}
int LocateVex(AMGraph* G, char vex) {
int i = 0;
for (; i < G->vexnum; i++) {
if (G->vexs[i] == vex) {
break;
}
}
return i;
}
void PrintGraph(AMGraph G) {
for (int i = 0; i < G.vexnum; i++)
{
for (int j = 0; j < G.arcnum; j++)
{
printf("%10d ", G.arcs[i][j]);
}
printf("\n");
}
printf("Print Success\n");
}
#define MAXSIZE 10 // 最大顶点数
typedef struct ArcNode { // 边结点
int adjvex; // 该边所指向的顶点的位置
struct ArcNode* nextarc; // 指向下一条边的指针
char info; // 和边相关的信息
} ArcNode;
typedef struct VNode { // 顶点信息
int data;
ArcNode* firstarc; // 指向第一条依附该顶点的边的指针
} VNode, AdjList[MAXSIZE]; // AdjList 表示邻接表类型
typedef struct { // 邻接表
AdjList vertices;
int vexnum, arcnum; // 图的当前顶点数和边数
} ALGraph;
void CreateUDG(ALGraph* G) {
printf("Enter vexnum , arcnum: ");
scanf("%d,%d", &(G->vexnum), &(G->arcnum)); // 输入总定点数,总边数
for (int i = 0; i < G->vexnum; i++) // 输入各点,构造表头结点表
{
printf("Enter vex: ");
scanf("%d", &(G->vertices[i].data)); // 输入顶点值
G->vertices[i].firstarc = NULL; // 初始化表头结点的指针域为 NULL
}
for (int i = 0; i < G->arcnum; i++) // 输入各边,构造邻接表
{
int vex1, vex2;
printf("Enter vex1, vex2: ");
scanf("%d,%d", &vex1, &vex2); // 输入一条边依附的两个顶点
int i = LocateVex(G, vex1); // 获取 vex1 在 G 中的序号(从 0 开始)
int j = LocateVex(G, vex2); // 获取 vex2 在 G 中的序号(从 0 开始)
ArcNode* p1 = (ArcNode*)malloc(sizeof(ArcNode)); // 生成新的边结点 p1
p1->adjvex = j; // 邻接点序号为 j
p1->nextarc = G->vertices[i].firstarc;
G->vertices[i].firstarc = p1; // 将新结点 p1 插入顶点 v_i 的边表头部
ArcNode* p2 = (ArcNode*)malloc(sizeof(ArcNode)); // 生成新的边结点 p2
p2->adjvex = i; // 邻接点序号为 i
p2->nextarc = G->vertices[j].firstarc;
G->vertices[j].firstarc = p2; // 将新结点 p2 插入顶点 v_j 的边表头部
}
printf("Create Success\n");
}
int LocateVex(ALGraph* G, int vex) {
for (int i = 0; i < G->vexnum; i++) {
if (G->vertices[i].data == vex)
return i;
}
}
优点
缺点
#include
#include
#define MAXSIZE 10
void CreateUDG(ALGraph);
int LocateVex(ALGraph);
void PrintGraph(ALGraph);
typedef struct ArcNode {
int adjvex;
struct ArcNode* nextarc;
char info;
} ArcNode;
typedef struct VNode {
int data;
ArcNode* firstarc;
} VNode, AdjList[MAXSIZE];
typedef struct {
AdjList vertices;
int vexnum, arcnum;
} ALGraph;
int main() {
ALGraph G;
CreateUDG(&G);
printf("****************\n");
PrintGraph(G);
printf("****************\n");
}
void CreateUDG(ALGraph* G) {
printf("Enter vexnum , arcnum: ");
scanf("%d,%d", &(G->vexnum), &(G->arcnum));
for (int i = 0; i < G->vexnum; i++)
{
printf("Enter vex: ");
scanf("%d", &(G->vertices[i].data));
G->vertices[i].firstarc = NULL;
}
for (int i = 0; i < G->arcnum; i++)
{
int vex1, vex2;
printf("Enter vex1, vex2: ");
scanf("%d,%d", &vex1, &vex2);
int i = LocateVex(G, vex1);
int j = LocateVex(G, vex2);
ArcNode* p1 = (ArcNode*)malloc(sizeof(ArcNode));
p1->adjvex = j;
p1->nextarc = G->vertices[i].firstarc;
G->vertices[i].firstarc = p1;
ArcNode* p2 = (ArcNode*)malloc(sizeof(ArcNode));
p2->adjvex = i;
p2->nextarc = G->vertices[j].firstarc;
G->vertices[j].firstarc = p2;
}
printf("Create Success\n");
}
int LocateVex(ALGraph* G, int vex) {
for (int i = 0; i < G->vexnum; i++) {
if (G->vertices[i].data == vex)
return i;
}
}
void PrintGraph(ALGraph G) {
for (int i = 0; i < G.vexnum; i++)
{
ArcNode* p = G.vertices[i].firstarc;
printf("%d", G.vertices[i].data);
while (p)
{
printf("->%d", p->adjvex);
p = p->nextarc;
}
printf("\n");
}
printf("Print Success\n");
}
#define MAXSIZE 10
typedef struct ArcBox {
int tailvex, headvex; // 该弧的尾和头顶点的位置
struct ArcBox* hlik, * tlink; // 分别为弧头相同和弧尾相同的弧的链域
int info; // 存储弧相关的信息
} ArcBox;
typedef struct VexNode {
int data;
ArcBox* firstin, * firstout; // 分别指向该顶点第一条入弧和出弧
} VexNode;
typedef struct {
VexNode xlist[MAXSIZE]; // 表头向量
int vexnum, arcnum; // 有向图的当前顶点数和弧数
} OLGraph;
#define MAXSIZE 10
typedef enum { unvisited, visited } VisitIf;
typedef struct EBox {
VisitIf mark; // 访问标记
int ivex, jvex; // 该边依附的两个顶点的位置
struct EBox* ilink, * jlink; // 分别指向依附这两个顶点的下一个边
int info; // 该边的信息
} EBox;
typedef struct VexBox {
int data;
EBox* firstedge; // 指向第一条依附该顶点的边
} VexBox;
typedef struct {
VexBox adjmulist[MAXSIZE];
int vexnum, degenum; // 无向图的当前顶点数和边数
} AMLGraph;
过程
假设 N = { V ,E } 是连通网,TE 是 N 上最小生成树中边的集合
过程
假设 N = { V ,E } 是连通网,将 N 中的边按权值从小到大的顺序排列
迪杰斯特拉(Dijkstra) 算法:按路径长度递增的次序产生最短路径的算法
过程
对于网 N = { V ,E } ,将 N 中的顶点分成两组
按各顶点与 v_0 间最短路径长度递增的次序,逐个将集合 V-S 中的顶点加入到集合 S 中去;在这个过程中,始终保持从 v_0 到集合 S 中各顶点的路径长度始终不大于到集合 V-S 中各顶点的路径长度
边表示活动的网(Activity On Edge Network,AOV-网):用边表示活动,带权的有向无环图
源点:网中只有一个入度为 0 的点
汇点:网中只有一个出度为 0 的点
带权路径长度(路径长度):一条路径各弧上的权值之和
关键路径(Critical Path):一条从源点到汇点的带权路径长度最长得到路径
关键活动:关键路径上的活动