多对多的结构,不能跟以前一样确定多少个数据域和指针域来进行表示。主要介绍邻接矩阵和邻接表。


尖括号表示有序的,有向图;圆括号表示无序的,无向图。有边的记作1,没有边的记为0。

特点:
有向图的邻接矩阵不一定是对称的,因为两个相连的顶点可能不是双向的。


相当于就是把权值代替成了普通的边。

以上就是网的邻接矩阵。
#define MaxInt 32767 //表示无穷大
#define MVNum 100
typedef char VerTexType;//设顶点的数据类型为字符型
typedef int ArcType; //假设边的权值类型为整型
typedef struct
{
VerTextType vex[MVNum];//顶点表
ArcType arcs[MVNum][MVNum];//邻接矩阵
int vexnum, arcnum; //图的当前点数和边数
}AMGraph;

#define MaxInt 32767 //表示无穷大
#define MVNum 100
typedef char VerTexType;//设顶点的数据类型为字符型
typedef int ArcType; //假设边的权值类型为整型
typedef struct
{
VerTextType vex[MVNum];//顶点表
ArcType arcs[MVNum][MVNum];//邻接矩阵
int vexnum, arcnum; //图的当前点数和边数
}AMGraph;//邻接矩阵表示的图
int LocateVex(AMGraph G, VertexType u)//查找顶点所在的位置
{
int i;
for (i = 0; i < G.vexnum; ++i)
{
if (u == G.vex[i])
{
return i;//找到元素在图当中的下标
}
}
return -1;
}
//构建无向网
Status CreateUDN(AMGraph &G)//G有四个成员,顶点表,边表,点数和边数
{
cin >> G.vexnum >> G.arcnum;//输入总顶点数,总边数
for (i = 0; i < G.vexnum; ++i)
{
cin >> G.vex[i];//依次输入点的信息
}
for (i = 0; i < G.vexnum; ++i) //初始化邻接矩阵
{
for (j = 0; i < G.vexnum; ++j)
{
G.arcs[i][j] = MaxInt;//边的权值均初始化为最大值
}
}
for (k = 0; k < G.arcnum; ++k)//构造邻接矩阵
{
cin >> v1 >> v2 >> w;//输入一条边所依附的顶点以及边的权值
i = LocateVex(G, v1);//确定v1和v2在G中的位置
j = LocateVex(G, v2);
G.arcs[i][j] = w;//边的权值置为w
G.arcs[j][i] = G.arcs[i][j];
}//for
return OK;
}//CreateUDN

无需向邻接矩阵双向赋值,只需要赋值单边的就行。


时间复杂度只与顶点有关,与边数无关,时间复杂度为
O
(
n
2
)
O(n^2)
O(n2)。
表示方法:

Tips:对于邻接表的表示方法,举个例子, v 1 v_1 v1之后的是3,这个3对应的是表中的下标,也就是 v 4 v_4 v4,不要直接认为3就是 v 3 v_3 v3。

边得双倍。怎么计算度?看到有几个表节点(紫色的点),就是有几个与其关联的边。所以,无向图中顶点 v i v_i vi的度为第 i i i个单链表中的结点数。

特点:
综上,找出度容易,入度难。

还有一个逆邻接表表示,这样就是找入度容易,找出度难。
练习:已知某网的邻接(出边)表,请画出该网络。

当邻接表的存储结构形成后,图便唯一确定。

#define MVNum 100 //最大顶点数
typedef struct VNode
{
VerTexType data; //顶点信息
ArcNode * firstarc; //指向第一条依附该顶点的边的指针
}VNode, AdjList[MVNum]; //AdjList为邻接表
typedef struct ArcNode //边结点
{
int adjvex; //该边所指向的顶点的位置
struct ArcNode * nextarc; //指向下一条边的指针
OtherInfo info; //和边相关的信息
}ArcNode;
typedef struct //图结构的定义
{
AdjList vertices;//vertices -- vertex的复数
int vexnum, arcnum; //图的当前顶点数与弧数
}ALGraph;

构建图G后,直接用成员变量进行赋值。

#define MVNum 100 //最大顶点数
typedef struct VNode
{
VerTexType data; //顶点信息
ArcNode * firstarc; //指向第一条依附该顶点的边的指针
}VNode, AdjList[MVNum]; //AdjList为邻接表
typedef struct ArcNode //边结点
{
int adjvex; //该边所指向的顶点的位置
struct ArcNode * nextarc; //指向下一条边的指针
OtherInfo info; //和边相关的信息
}ArcNode;
typedef struct //图结构的定义
{
AdjList vertices;//vertices -- vertex的复数
int vexnum, arcnum; //图的当前顶点数与弧数
}ALGraph;
//
Status CreateUDG(ALGraph &G) //采用邻接表表示法,创建无向图G
{
cin >> G.vexnum >> G.arcnum; //输入总项点数,总边数
for (i = 0; i < G.vexnum; ++i)//输入各点,构造表头结点表
{
cin >> G.vertices[i].data; //输入顶点值
G.ertices[i].firstarc = NULL; //初始化表头结点的指针域
}
for (k = 0; k < G.arcnum; ++k) //输入各边,构造邻接表
{
cin >> v1 >> v2; //输入一条边依附的两个顶点
i = LocateVex(G, v1);
j = LocateVex(G, v2);
p1 = new ArcNode; //生成一个新的边结点*p1
p1->adjvex = j; //邻接点序号为j
p1->nextarc = G.vertices[i].firstarc;
G.vertices[i].firstarc = p1;//将新结点*p1插入顶点vi的边表头部
p2 = new ArcNode; //生成另一个对称的新的边结点*p2
p2->adjvex = i; //邻接点序号为i
p2->nextarc = G.vertices[j].firstarc;
G.vertices[j].firstarc = p2; //将新节点*p2插入顶点vj的边表头部
}
return OK;
}
如果建立有向网,就只需要建立入度/出度的。



邻接表因为节点插入顺序不同,导致不唯一。

将邻接表与逆邻接表结合起来。


给表头结点再增加一个指针域,用来放入度边(因为有向图的邻接表算出度好算)

顶点节点:
弧节点:

以上就是十字链表,统计入度出度很方便。
解决无向图每条边存储两遍的问题。

在邻接表当中,任意一条边,都会出现两次。
现在换成邻接多重表后,就记录好这个边是哪两个顶点之间的边就行了。
邻接多重表的结构,顶点节点与边结点的表示形式:

以上便是图的存储结构,如有遗漏,欢迎评论区补充,感谢。