邻接矩阵法
-
图的邻接矩阵(adjacency matrix)是一种采用邻接矩阵数组表示顶点之间相邻关系的存储结构。设G=(V,E)是含有n(n>0)个顶点的图,各顶点的编号为0~(n-1),则G的邻接矩阵数组A是n阶方阵,其定义如下:
-
如果G是不带权无向图,则:
A [ i ] [ j ] = { 1 若 ( i , j ) ∈ E ( G ) 0 其 他 A[i][j]=\begin{cases} 1\;\;\;\;若(i,j)∈E(G) \\ 0\;\;\;\;其他 \\ \end{cases} A[i][j]={1若(i,j)∈E(G)0其他
-
如果G是不带权有向图,则:
A [ i ] [ j ] = { 1 若 < i , j > ∈ E ( G ) 0 其 他 A[i][j]=\begin{cases} 1\;\;\;\;若<i,j>∈E(G) \\ 0\;\;\;\;其他 \\ \end{cases} A[i][j]={1若<i,j>∈E(G)0其他
-
如果G是带权无向图,则:
A [ i ] [ j ] = { w i j 若 i ≠ j 且 ( i , j ) ∈ E ( G ) , 该 边 的 权 为 w i j 0 i = j ∞ 其 他 A[i][j]=\begin{cases} w_{ij}\;\;\;\;若i≠j且(i,j)∈E(G),该边的权为w_{ij} \\ 0\;\;\;\;i=j \\ ∞\;\;\;\;其他 \\ \end{cases} A[i][j]=⎩⎪⎨⎪⎧wij若i=j且(i,j)∈E(G),该边的权为wij0i=j∞其他
-
如果G是带权有向图,则:
A [ i ] [ j ] = { w i j 若 i ≠ j 且 < i , j > ∈ E ( G ) , 该 边 的 权 为 w i j 0 i = j ∞ 其 他 A[i][j]=\begin{cases} w_{ij}\;\;\;\;若i≠j且<i,j>∈E(G),该边的权为w_{ij} \\ 0\;\;\;\;i=j \\ ∞\;\;\;\;其他 \\ \end{cases} A[i][j]=⎩⎪⎨⎪⎧wij若i=j且<i,j>∈E(G),该边的权为wij0i=j∞其他
邻接矩阵类型的声明
#define MaxVertenNum 100 //顶点数目的最大值
typedef char VertexType; //顶点的数据类型
typedef int EdgeType; //存放顶点信息
typedef struct
{
VertexType Vex[MaxVertenNum]; //顶点表
EdgeType Edge[MaxVertenNum][MaxVertenNum]; //邻接矩阵
int vexnum, arcnum; //图的当前顶点数和弧数
}MGraph;
邻接矩阵类型的特点
- 图的邻接矩阵表示是唯一的。
- 对于含有n个顶点的图,当采用邻接矩阵存储时,无论是有向图还是无向图,也无论边的数目是多少,其存储空间都为 O ( n 2 ) O(n^2) O(n2),所以邻接矩阵适合于存储边的数目较多的稠密图。
- 无向图的邻接矩阵数组一定是一个对称矩阵,因此可以采用压缩存储的思想,在存放邻接矩阵数组时只需存放上(或下)三角部分的元素即可。
- 对于无向图,邻接矩阵数组的第i行或第j列非零元素、非∞元素的个数正好是顶点i的度。
- 对于有向图,邻接矩阵数组的第i行(或第i列)非零元素、非∞元素的个数正好是顶点i的出度(或入度)。
- 在邻接矩阵中,判断图中两个顶点之间是否有边或者求两个顶点之间边的权的执行时间为O(1)。所以在需要提取边权值的算法中通常采用邻接矩阵存储结构。
不带权无向图基本操作的代码实现
#include<stdio.h>
#define MaxVertenNum 100 //顶点数目的最大值
#define NodeNum 6 //顶点个数
typedef char VertexType; //顶点的数据类型
typedef int EdgeType; //存放顶点信息
typedef struct
{
VertexType Vex[MaxVertenNum]; //顶点表
EdgeType Edge[MaxVertenNum][MaxVertenNum]; //邻接矩阵
int vexnum, edgenum; //图的当前顶点数和边数
}MGraph;
void InitG(MGraph& g) //初始化
{
int i, j;
for (i = 0; i < MaxVertenNum; i++) g.Vex[i] = '\0';
for (i = 0; i < MaxVertenNum; i++)
for (j = 0; j < MaxVertenNum; j++)
g.Edge[i][j] = 0;
g.vexnum = 0;
g.edgenum = 0;
}
void CreateVex(MGraph& g) //创建顶点信息
{
int i = 0, count = 0;
printf("输入图的顶点:");
VertexType ch= getchar();
while (ch != '#')
{
g.Vex[i++] = ch;
ch = getchar();
count++; //统计顶点个数
}
g.vexnum = count;
}
void CreateEdge(MGraph& g) //创建邻接矩阵信息
{
EdgeType b;
printf("输入邻接矩阵信息:\n");
for (int i = 0; i < g.vexnum; i++)
for (int j = 0; j < g.vexnum; j++)
{
scanf("%d", &b);
g.Edge[i][j] = b;
}
}
void Info(MGraph& g) //图的顶点数和边数
{
int count = 0;
for (int i = 0; i < g.vexnum; i++)
for (int j = 0; j < g.vexnum; j++)
if (g.Edge[i][j] == 1) count++;
g.edgenum = count / 2;
}
int CountDegree(MGraph g, VertexType point) //统计每个顶点的度
{
int j, count = 0;
for (int i = 0; i < g.vexnum; i++)
if (g.Vex[i] == point) j = i;
for (int k = 0; k < g.vexnum; k++) if (g.Edge[j][k] == 1) count++;
return count;
}
void PrintG(MGraph g) //输出各顶点的连接情况
{
int i, j;
for (i = 0; i < g.vexnum; i++)
{
for (j = 0; j < g.vexnum; j++)
if (g.Edge[i][j] == 1) printf("%c->%c ", g.Vex[i], g.Vex[j]);
printf("\n");
}
}
bool Adjacent(MGraph g, VertexType x, VertexType y) //判断图G是否存在边(x,y)
{
int i, j, k;
for (i = 0; i < g.vexnum; i++)
{
if (g.Vex[i] == x) j = i;
if (g.Vex[i] == y) k = i;
}
if (g.Edge[j][k] == 1) return true;
else return false;
}
void Neighbors(MGraph g, VertexType x) //列出图G中与结点x邻接的边
{
int i, j;
for (i = 0; i < g.vexnum; i++)
if (g.Vex[i] == x) j = i;
for (i = 0; i < g.vexnum; i++)
if (g.Edge[j][i] == 1)
printf("%c ", g.Vex[i]);
}
bool InsertVertex(MGraph& g, VertexType x) //在图G中插入顶点x
{
for (int i = 0; i < g.vexnum; i++)
if (x == g.Vex[i]) return false; //与图G中原有顶点值相同
g.Vex[g.vexnum] = x;
g.vexnum++;
return true;
}
bool DeleteVertex(MGraph& g, VertexType x) //从图G中删除顶点x
{
int i, j, k;
for (i = 0; i < g.vexnum; i++)
if (x == g.Vex[i]) k = i;
if (k < g.vexnum)
{
for (j = k; j < g.vexnum - 1; j++) //处理顶点表中的值
g.Vex[j] = g.Vex[j + 1];
//处理邻接矩阵中的值
for (i = 0; i < k; i++) //处理矩阵右上元素
for (j = k; j < g.vexnum - 1; j++)
g.Edge[i][j] = g.Edge[i][j + 1];
for (i = k; i < g.vexnum - 1; i++) //处理矩阵左上元素
for (j = 0; j < k; j++)
g.Edge[i][j] = g.Edge[i + 1][j];
for (i = k; i < g.vexnum - 1; i++) //处理矩阵右下元素
for (j = k; j < g.vexnum - 1; j++)
g.Edge[i][j] = g.Edge[i + 1][j + 1];
g.vexnum--;
return true;
}
return false;
}
void PrintMatrix(MGraph g) //输出邻接矩阵
{
int i, j;
printf("输出邻接矩阵:\n");
for (i = 0; i < g.vexnum; i++)
printf("\t%c", g.Vex[i]);
printf("\n");
for (i = 0; i < g.vexnum; i++)
{
printf("%c", g.Vex[i]);
for (j = 0; j < g.vexnum; j++)
printf("\t%d", g.Edge[i][j]);
printf("\n");
}
printf("\n");
}
bool AddEdge(MGraph& g, VertexType x, VertexType y) //若无向边(x, y)不存在,则向图G中添加该边
{
int i, j, k;
for (i = 0; i < g.vexnum; i++)
{
if (g.Vex[i] == x) j = i;
if (g.Vex[i] == y) k = i;
}
if (j >= g.vexnum || k >= g.vexnum) return false; //不存在顶点x或顶点y
else
{
if (g.Edge[j][k] == 0)
{
g.Edge[j][k] = 1;
g.Edge[k][j] = 1;
return true;
}
else return false; //该边已存在
}
}
bool RemoveEdge(MGraph& g, VertexType x, VertexType y) //若无向边(x, y)存在,则在图G中删除该边
{
int i, j, k;
for (i = 0; i < g.vexnum; i++)
{
if (g.Vex[i] == x) j = i;
if (g.Vex[i] == y) k = i;
}
if (j >= g.vexnum || k >= g.vexnum) return false; //不存在顶点x或顶点y
else
{
if (g.Edge[j][k] == 1)
{
g.Edge[j][k] = 0;
g.Edge[k][j] = 0;
return true;
}
else return false; //该边不存在
}
}
int FirstNeighbor(MGraph g, VertexType x) //求图G中顶点x的第一个邻接点,若有则返回顶点号。若x没有邻接点或图中不存在x,则返回-1。
{
int i, j;
for (i = 0; i < g.vexnum; i++)
if (x == g.Vex[i]) j = i;
if (j >= g.vexnum) return -1; //图中不存在值为x的顶点
else
{
for (i = 0; i < g.vexnum; i++)
if (g.Edge[j][i] == 1) return i; //返回顶点号
if (i >= g.vexnum) return -1; //x没有邻接点
}
}
int NextNeighbor(MGraph g, VertexType x, VertexType y)
//假设图G中顶点y是顶点x的一个邻接点,返回除y外顶点x的下一个邻接点的顶点号,若y是x的最后一个邻接点,则返回-1
{
int i, j, k;
for (i = 0; i < g.vexnum; i++)
{
if (g.Vex[i] == x) j = i;
if (g.Vex[i] == y) k = i;
}
if (j >= g.vexnum || k >= g.vexnum) return false; //不存在顶点x或顶点y
else
{
for (i = k + 1; i < g.vexnum; i++)
{
if (g.Edge[j][i] == 1) return i; //返回顶点号
}
if (i >= g.vexnum) return -1; //x没有邻接点
}
}
int main()
{
MGraph g;
VertexType Vex[MaxVertenNum];
EdgeType Edge[MaxVertenNum][MaxVertenNum];
InitG(g);
CreateVex(g);
CreateEdge(g);
Info(g);
printf("\n无向图G中共有:%d个顶点,%d条边\n", g.vexnum, g.edgenum);
PrintMatrix(g);
printf("输出无向图G中各顶点的连接情况:\n");
PrintG(g);
int sumdegree = 0, i;
for (i = 0; i < g.vexnum; i++)
{
int degree;
degree = CountDegree(g, g.Vex[i]);
printf("顶点%c的度为:%d\n", g.Vex[i], degree);
sumdegree = sumdegree + degree;
}
printf("无向图G中所有顶点的度之和为:%d\n", sumdegree);
/*VertexType x, y;
printf("\n-----判断图G是否存在边(x,y)-----\n");
x = 'C', y = 'F';
printf("顶点%c和顶点%c之间存在边吗?(1表示存在,0表示不存在)— %d", x, y, Adjacent(g, x, y));
x = 'A', y = 'D';
printf("\n顶点%c和顶点%c之间存在边吗?(1表示存在,0表示不存在)— %d\n", x, y, Adjacent(g, x, y));*/
/*printf("\n-----列出图G中与结点x邻接的边-----\n");
x = 'B';
printf("与顶点%c连接的边有:", x);
Neighbors(g, x);
printf("\n");*/
/*printf("\n-----在图G中插入顶点x-----\n");
x = 'G';
printf("插入顶点%c", x);
printf("插入成功了吗?— %d(1表示成功,0表示失败)\n", InsertVertex(g, x));
PrintG(g);
Info(g);
printf("无向图G中共有:%d个顶点,%d条边\n", g.vexnum, g.edgenum);
PrintMatrix(g);*/
/*printf("\n-----在图G中删除顶点x-----\n");
x = 'C';
printf("删除顶点%c\n", x);
printf("删除成功了吗?(1表示成功,0表示失败)— %d\n", DeleteVertex(g, x));
printf("输出无向图G中各顶点的连接情况:\n");
PrintG(g);
printf("\n");
Info(g);
printf("\n无向图G中共有:%d个顶点,%d条边\n", g.vexnum, g.edgenum);
PrintMatrix(g);*/
/*printf("\n-----图G中添加无向边(x, y)-----\n");
x = 'E', y = 'F';
printf("在顶点%c与顶点%c之间添加一条无向边\n", x, y);
printf("添加成功了吗?— %d(1代表成功,原图中没有边(x, y),0代表失败,原图中已存在该边或者顶点x/顶点y不存在)\n", AddEdge(g, x, y));
printf("\n");
PrintMatrix(g);
printf("输出无向图G中各顶点的连接情况:\n");
PrintG(g);
printf("\n");*/
/*printf("\n-----删除图G中无向边(x, y)-----\n");
x = 'B', y = 'F';
printf("删除(若存在)顶点%c与顶点%c之间的一条无向边\n", x, y);
printf("删除成功了吗?— %d(1代表成功,原图中有边(x, y),0代表失败,原图中不存在该边或者顶点x/顶点y不存在)\n", RemoveEdge(g, x, y));
printf("\n");
PrintMatrix(g);
printf("输出无向图G中各顶点的连接情况:\n");
PrintG(g);
printf("\n");*/
/*printf("\n-----求图G中顶点x的第一个邻接点-----\n");
x = 'E';
printf("图G中顶点%c的第一个邻接点的顶点号为:%d(-1代表x没有邻接点或图中不存在x)\n", x,FirstNeighbor(g,x));*/
/*printf("\n-----求图G中除y之外顶点x的下一个邻接点的顶点号-----\n");
x = 'B', y = 'E';
printf("图G中除顶点%c之外顶点%c的下一个邻接点的顶点号为:%d(-1代表x没有邻接点或图中不存在x)\n", x, y, NextNeighbor(g, x, y));*/
return 0;
}
- ①Adjacent(G,x,y):判断图G是否存在边(x,y)。
- ②Neighbors(G,x):列出图G中与结点x邻接的边。
- ③InsertVertex(G,x):在图G中插入顶点x。
- ④DeleteVertex(G,x):从图G中删除顶点x。
- ⑤Addedge(G,x,y):若无向边(x,y)不存在,则向图G中添加该边。
- ⑥RemoveEdge(G,x,y):若无向边(x,y)存在,则从图G中删除该边。
- ⑦FirstNeighbor(G,x):求图G中顶点x的第一个邻接点,若有则返回顶点号。若x没有邻接点或图中不存在x,则返回-1。
- ⑧NextNeighbor(G,x,y):假设图G中顶点y是顶点x的一个邻接点,返回除y外顶点x的下一个邻接点的顶点号,若y是x的最后一个邻接点,则返回-1。
邻接矩阵法的性质
- 设图G的邻接矩阵为A(矩阵元素为0/1),则
A
n
A^n
An的元素
A
n
[
i
]
[
j
]
A^n[i][j]
An[i][j]等于由顶点i到顶点j的长度为n的路径的数目。
A 2 [ 1 ] [ 1 ] = 1 A^2[1][1]=1 A2[1][1]=1:表示A-A长度为2的路径有1条, A 2 [ 2 ] [ 2 ] = 3 A^2[2][2]=3 A2[2][2]=3:表示B-B长度为2的路径有3条, A 2 [ 3 ] [ 3 ] = 2 A^2[3][3]=2 A2[3][3]=2:表示C-C长度为2的路径有2条…
A 3 [ 1 ] [ 2 ] = 3 A^3[1][2]=3 A3[1][2]=3:表示A-B长度为3的路径有3条, A 3 [ 2 ] [ 4 ] = 4 A^3[2][4]=4 A3[2][4]=4表示B-D长度为2的路径有4条, A 3 [ 3 ] [ 1 ] = 1 A^3[3][1]=1 A3[3][1]=1表示C-A长度为3的路径有1条, A 3 [ 4 ] [ 4 ] = 2 A^3[4][4]=2 A3[4][4]=2表示D-D长度为2的路径有2条…