邻接矩阵
文章目录
- 邻接矩阵
-
- [1. 概述](#1. 概述)
- 2.无向图的邻接矩阵
- 3.有向图的邻接矩阵
- [4. 带权图的邻接矩阵](#4. 带权图的邻接矩阵)
- [5. 邻接表的引入](#5. 邻接表的引入)
- [6. 代码实现](#6. 代码实现)
-
- [6.1 头文件部分](#6.1 头文件部分)
- [6.2 函数实现](#6.2 函数实现)
-
- [6.2.1 初始化邻接矩阵](#6.2.1 初始化邻接矩阵)
- [6.2.2 向邻接矩阵中添加边](#6.2.2 向邻接矩阵中添加边)
- [6.2.3 访问图中顶点](#6.2.3 访问图中顶点)
- [6.2.4 深搜](#6.2.4 深搜)
- [6.2.5 广搜](#6.2.5 广搜)
- [6.3 main 函数](#6.3 main 函数)
- [6.4 输出结果](#6.4 输出结果)
1. 概述
- 图的邻接矩阵是⽤两个数组来表示,⼀个⼀位数组存储图中的顶点信息,⼀个⼆维数组(我们将这个数组称之为邻接矩阵)存储图中的边的信息
2.无向图的邻接矩阵
- 我们可以设置两个数组,顶点数组为 vertex 4 = { V0 , V1 , V2 , V3 },边数组arc4 4为对称矩阵(0表示不存在顶点间的边,1表示顶点间存在边)

- 对称矩阵
所谓对称矩阵就是n阶矩阵的元素满⾜a i j = a j i (0 <= i , j <= n) ,即从矩阵的左上⻆到右下⻆的主对⻆线为轴,右上⻆的元与左下⻆相对应的元全都是相等的
其实 普通无向图的邻接矩阵一定是对称矩阵

- 又画的另外一个例子

- 有了这个⼆维数组组成的对称矩阵,我们就可以很容易地知道图中的信息:
判定任意两顶点是否有边⽆边
可以轻松知道某个顶点的度,其实就是这个顶点 Vi 在邻接矩阵中第 i ⾏(或第 i 列)的元素之和
求顶点Vi的所有邻接点就是将矩阵中第i⾏元素扫描⼀遍,arc i j 为1就是邻接点
3.有向图的邻接矩阵
- ⽆向图的边构成了⼀个对称矩阵,貌似浪费了⼀半的空间,那如果是有向图来存放,会不会把资源都利⽤得很好呢?

- 可⻅顶点数组 vertex 4 = { V0 , V1 , V2 , V3 },弧数组arc 4 4 也是⼀个矩阵,但因为是有向图,所以这个矩阵并不对称,例如由V0到V3有弧,得到arc0 3=1,⽽V3到V0没有弧,因此arc3 0=0
- 另外有向图是有讲究的,要考虑⼊度和出度,顶点V1的⼊度为1,正好是第V1列的各数之和,顶点V1的出度为2,正好是第V1⾏的各数之和
4. 带权图的邻接矩阵
- 带权图中的每⼀条边上带有权值,邻接矩阵中的值则为权值,当两个顶点之间没有弧时,则⽤⽆穷⼤表示

这⾥"∞"表示⼀个计算机允许的、⼤于所有边上权值的值
5. 邻接表的引入
-
这个时候我们会发现⼀个问题,就是空间浪费问题,尤其是⾯对边数相对⽐较少的稀疏图来说,这种结构⽆疑是存在对存储空间的极⼤浪费
-
因此我们可以考虑另外⼀种存储结构⽅式,例如把数组与链表结合在⼀起来存储,这种⽅式在图结构也适⽤,我们称为邻接表(Adjacency List)
这个我们将下一节来写,现在去完成代码部分
6. 代码实现
6.1 头文件部分
c
#define MaxNodeNum 20
#define INF 1E4
//邻接矩阵的顶点结构 表示一个顶点的信息
typedef struct
{
int no; //顶点编号
char* show; //显示行为
} MatrixVertex;
typedef int MatrixEdge; //边里面存的内容
//图邻接矩阵表示法
typedef struct
{
MatrixVertex vex[MaxNodeNum]; //存储顶点信息,使用一维数组存储顶点
int nodeNum; //约束实际顶点数量
MatrixEdge edges[MaxNodeNum][MaxNodeNum]; //边的集合 //存储边的结构,矩阵
int edgeNum; //边的数量
int directed; //是否有向
}MGraph;
/* 1.初始化邻接矩阵
* graph :哪个图
* names[] : 顶点名称
* num :顶点数量
* directed :是否有向
* edgeValue :用来初始化边 0 ? ∞
*/
void initMGraph(MGraph* graph, char* names[], int num, int directed, int edgeValue);
/*
* 2.向邻接矩阵中添加边
* graph: 向哪个图添加边
* x : 起始顶点的编号
* y : 终点顶点的编号
* w : 边的权值
*/
void addMGraphEdge(MGraph* graph, int x, int y, int w);
//3.访问图中顶点
void visitMGraphNode(MatrixVertex *node);
void initVisited();
//4.深搜 /*v是节点的下标*/
void DFS_MGraph(MGraph* graph, int v);
//5.广搜
void BFS_MGraph(MGraph* graph, int v);
6.2 函数实现
6.2.1 初始化邻接矩阵
c
void initMGraph(MGraph* graph, char* names[], int num, int directed, int edgeValue)
{
//初始化 是否有向 顶点数量 边的数量
graph->directed = directed;
graph->nodeNum = num;
graph->edgeNum = 0;
//初始化 顶点集合 边的集合
memset(graph->vex, 0, sizeof(graph->vex));
memset(graph->edges, 0, sizeof(MatrixEdge) * MaxNodeNum * MaxNodeNum);
//初始化顶点编号 显示行为 边
for (int i = 0;i < num;i++)
{
graph->vex[i].no = i;
graph->vex[i].show = names[i];
for (int j = 0;j < num;j++)
{
graph->edges[i][j] = edgeValue;
}
}
}
6.2.2 向邻接矩阵中添加边
c
//判断两个点之间有没有边
static int isEdge(int weight)
{
if (weight > 0 && weight < INF)
{
return 1;
}
return 0;
}
void addMGraphEdge(MGraph* graph, int x, int y, int w)
{
//越界情况
if (x<0 || x>graph->nodeNum)
{
return;
}
if (y<0 || y>graph->nodeNum)
{
return;
}
//没边加边
if (!isEdge(graph->edges[x][y]))
{
graph->edges[x][y] = w;
if (graph->directed == 0)
{ //无向图 对称的 (加对称的边)
graph->edges[y][x] = w;
}
graph->edgeNum++;
}
}
6.2.3 访问图中顶点
c
void visitMGraphNode(MatrixVertex* node)
{
printf("\t%s", node->show);
}
static int MGraphVisited[MaxNodeNum];
void initVisited()
{ //因为这个MGraphVisited数组同时用于深搜和广搜
memset(MGraphVisited, 0, sizeof(MGraphVisited));
}
6.2.4 深搜
c
void DFS_MGraph(MGraph* graph, int v)
{//深搜
visitMGraphNode(&graph->vex[v]);
MGraphVisited[v] = 1; //访问过则标记一下
for (int i = 0;i < graph->nodeNum;i++)
{//有边且未访问过
if (isEdge(graph->edges[v][i] && MGraphVisited[i] == 0))
{
DFS_MGraph(graph, i);
}
}
}
6.2.5 广搜
c
void BFS_MGraph(MGraph* graph, int v)
{//广搜
//用队列 手写个简单的队列
int que[MaxNodeNum];
int rear = 0, front = 0; int cur;
//初始化该队列
rear = (rear + 1) % MaxNodeNum;
que[rear] = v;
MGraphVisited[v] = 1;
//队列中有内容就一直出队
while (front != rear)
{
//出队
front = (front + 1) % MaxNodeNum;
cur = que[front];
visitMGraphNode(&graph->vex[cur]);
for (int i = 0;i < graph->nodeNum;++i)
{//不断的放节点 入队
//有边且未访问过
if (isEdge(graph->edges[cur][i] && MGraphVisited[i] == 0))
{
rear = (rear + 1) % MaxNodeNum;
que[rear] = i;
MGraphVisited[i] = 1;
}
}
}
}
6.3 main 函数
c
void testMatruxGraph(MGraph *grap)
{
char* nodeName[] = { "v1","v2", "v3", "v4", "v5", "v6", "v7", "v8" };
// 无向图
initMGraph(grap, nodeName, sizeof(nodeName) / sizeof(nodeName[0]), 0, 0);
addMGraphEdge(grap, 0, 1, 1);
addMGraphEdge(grap, 0, 2, 1);
addMGraphEdge(grap, 1, 3, 1);
addMGraphEdge(grap, 1, 4, 1);
addMGraphEdge(grap, 2, 5, 1);
addMGraphEdge(grap, 2, 6, 1);
addMGraphEdge(grap, 3, 7, 1);
addMGraphEdge(grap, 4, 7, 1);
addMGraphEdge(grap, 5, 6, 1);
}
void test01()
{
MGraph g1;
testMatruxGraph(&g1);
printf("graph have %d edge!\n", g1.edgeNum);
//DFS
DFS_MGraph(&g1, 0); //从v1开始访问
initVisited();
printf("\n");
//BFS
BFS_MGraph(&g1, 0);
}
int main()
{
test01()
return 0;
}
6.4 输出结果
c
graph have 9 edge!
v1 v2 v4 v8 v5 v3 v6 v7
v1 v2 v3 v4 v5 v6 v7 v8
- 测试案例可参考该图

嘻嘻嘻嘻 邻接矩阵部分到此结束😆😆
邻接表 静候更新 👻👻👻😸😸😸
(有错误欢迎指出) (疑问也是)❤️❤️😍😍💖💖
持续更新中...