📚参考书:《数据结构(C语言)》–严蔚敏等编著,清华大学出版社。
📖图
图
(graph)是一种较线性表和树更为复杂的数据结构,在图型结构中,节点之间的关系可以是任意的,图中任意两个数据元素之间都可以相互关联。
在生活中最具有代表性的图就是我们所用的地图,每个城市代表着一个顶点,城市之间的关系多种多样,且图可分为有向图和无向图,如下:
图的相关术语:
♥ 顶点:图中的数据元素称为顶点;
♥ 弧:
- 有向图中V1到V2称为一条弧:<v1,v2> ;
- 无向图中V1到V2称为一条边:(v1,v2);
♥ 弧尾:称v1为弧尾(或初始点);
♥ 弧头:称v2为弧头(或终端点);
♥ 完全图:有
1
2
n
(
n
−
1
)
\bf\color{teal}\dfrac{1}{2}n\left( n-1\right)
21n(n−1) 条边的无向图称为完全图;
♥ 有向完全图:
n
(
n
−
1
)
\bf\color{teal}n\left( n-1\right)
n(n−1) 条弧的有向图称为有向完全图;
♥ 稀疏图:有很少条边或弧(如
e
<
n
log
n
\bf\color{teal}e<n\log{n}
e<nlogn)的图称为稀疏图;
♥ 稠密图:稀疏图反之为稠密图;
♥ 权:有时图的边或者弧具有与它相关的数,这种图的边或弧相关的数称为权;
♥ 网:带权
的图称为网;
♥ 顶点的度:是指和该顶点相连的边数,如上无向图顶点V1的度为:3
♥ 顶点的出度:是指以该顶点为尾的边数,如上有向图顶点V1的出度为:2
♥ 顶点的入度:是指以该顶点为头的边数,如上有向图顶点V1的入度为:1
😄 在无向图中,任意两个顶点之间都是连通的
,则称为连通图(无向图),非连通图和连通图如下区分:
♥ 连通分量:是指无向图中的极大连通子图,如下非连通图有3个连通分量:
😄 在有向图中,对于每一对vi,vj(vi != vj),从vi到vj和vj到vi都存在路劲
,则称为强连通图(有向图),有向图中的极大强连通子图称为有向图的强连通分量。
🍵 生成树:一个连通图的生成树是一个极小连通子图,它含有全部顶点,但只有足以构成一棵树的n-1条边。
🌔 重点:
🍊 一棵有n个顶点的生成树有且仅有n-1条边。
🍊 如果多于n-1条边,必构成环(回路)。
🍊 有n-1条边的图不一定是生成树。
🍊 一个图有n个顶点和小于n-1条边,则图为非连通图
📖 图的存储结构
🍋 图的数组表示法(邻接矩阵表示)
#define INFINITY INT_MAX //最大值∞
#define MAX_VERTEX_NUM 20 //最大顶点数
typedef enum {DG,DN,UDG,UDN} GraphKind; //有向图,有向网,无向图,无向网
typedef struct ArcCell {
VRType adj; //VRType是顶点关系类型,多于无权图用1或0表示,表示相邻否,对于有权图则为权值
InfoType *info; //该弧相关信息的指针
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; //顶点向量
AdjMatrix arcs; //邻接矩阵
int vexnum, arcnum; //当前顶点数和弧数
GraphKind kind; //图的种类
}MGraph;
🍋 邻接矩阵(数组)表示图的优点:
🍎 直观,简单,好理解;
🍎 方便检查任意一对顶点是否存在边;
🍎 方便找任意一顶点的所有的"邻接点";
🍎 方便计算任意顶点的度;
🍋 邻接矩阵(数组)表示图的缺点:
🍎 不方便增加和删除顶点;
🍎 浪费空间----存稀疏图有大量0元素;
🍎 浪费时间----统计稀疏图共有多少条边;
🔗 相关代码:
#include "stdio.h"
#include "stdlib.h"
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define INFINITY INT_MAX //最大值
#define MAX_VERTEX_NUM 20 //最大顶点数
typedef int Status;
typedef int VertexType;
typedef int ArcType;
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; //顶点向量
ArcType arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵
int vexnum,arcnum; //图的当前顶点数和弧数
} MGraph;
Status LocateVex(MGraph G,VertexType v);
//定位v在邻接矩阵中的位置
Status LocateVex(MGraph G,VertexType v) {
int i;
for(i=0; i<G.vexnum; i++) {
if(G.vexs[i]==v) return i;
}
return -1;
}
Status CreateUDGraph(MGraph &G);
//构造邻接矩阵表示的无向图 UDG
Status CreateUDGraph(MGraph &G) {
printf("请输入当前顶点数和弧数(空格隔开):");
scanf("%d %d",&G.vexnum,&G.arcnum);
int i,j,k;
int v1,v2; //弧尾和弧头
for(i=0; i<G.vexnum; i++) {
printf("请输入第%d个的顶点信息:",i+1);
scanf("%d",&G.vexs[i]);
}
printf("\n");
for(i=0; i<G.vexnum; i++) //初始化邻接矩阵
for(j=0; j<G.vexnum; j++) {
G.arcs[i][j]= {INFINITY};
}
for(k=0; k<G.arcnum; k++) {
printf("请输入第%d条边的起点序号和终点序号(空格隔开):",k+1);
scanf("%d %d",&v1,&v2);
i=LocateVex(G,v1);
j=LocateVex(G,v2);
if(i==-1 || j==-1) return ERROR;
else {
G.arcs[i][j]=1;
G.arcs[j][i]=1;
}
}
return OK;
}
Status PrintUDGraph(MGraph G);
//打印图
Status PrintUDGraph(MGraph G) {
int i,j;
printf("\n无向图的顶点为:\n");
for(i=0; i<G.vexnum; i++)
printf("%d ",G.vexs[i]);
printf("\n无向图的邻接矩阵为:\n");
printf("\t");
for(i=0; i<G.vexnum; ++i)
printf("%8d", G.vexs[i]);
putchar('\n');
for(i=0; i<G.vexnum; ++i) {
printf("\n%8d", G.vexs[i]);
for(j=0; j<G.vexnum; ++j) {
if(G.arcs[i][j] == INT_MAX) printf("%8s", "0");
else printf("%8d",G.arcs[i][j]);
}
printf("\n");
}
return OK;
}
Status Degree(MGraph G);
//求无向图各顶点的度
Status Degree(MGraph G) {
int i,j, deg;
for(i=0; i<G.vexnum; i++) {
deg=0; //初始为0
for(j=0; j<G.vexnum; j++) {
if(G.arcs[i][j] != INT_MAX) {
deg++;
}
}
if(deg == 0) printf("\n顶点%d没有度\n",G.vexs[i]);
else printf("\n顶点%d的度为:%d\n",G.vexs[i],deg);
}
}
int main(void) {
MGraph G;
CreateUDGraph(G);
PrintUDGraph(G);
putchar('\n');
Degree(G);
return 0;
}
实现: