三。图的存储结构

1.邻接矩阵(数组)表示法

建立一个顶点表(记录各个顶点信息)和一个邻接矩阵(表示各个顶点之间关系)

  • 设图A=(%月有n个顶点,则

数据结构 - 图2_i++

  • 图的邻接矩阵是一 个二维数组A. arcs[n][n], 定义为:

数据结构 - 图2_结点_02


数据结构 - 图2_邻接矩阵_03

分析1:无向图的邻接矩阵是对称的;

分析2:顶点i的度=第i行(列)中1的个数;

特别:完全图的邻接矩阵中,对角元素为0,其余1。

数据结构 - 图2_i++_04

注:在有向图的邻接矩阵中,

第i行含义:以结点vi为尾的弧(即出度边) ;

第列含义:以结点vi为头的弧(即入度边)。

分析1:有向图的邻接矩阵可能是不对称的。

分析2:顶点的出度=第i行元素之和

顶点的入度=第列元素之和

顶点的度=第i行元素之和+第列元素之和


数据结构 - 图2_邻接矩阵_05

数据结构 - 图2_i++_06

2.邻接矩阵的(数组)存储表示:

(用两个数组分别存储顶点表和邻接矩阵)

采用邻接矩阵表示法创建无向网

算法思路:

(1)输入总顶点数和总边数。

(2)依次输入点的信息存入顶点表中。

(3)初始化邻接矩阵,使每个权值初始化为极大值。

(4)构造邻接矩阵。

AMGraph.h:

#include <stdio.h>
#define MAX_VERtEX_NUM 20 //顶点的最大个数
#define VRType int //表示顶点之间的关系的变量类型
#define InfoType char //存储弧或者边额外信息的指针变量类型
#define VertexType int //图中顶点的数据类型
typedef enum{ DG, DN, UDG, UDN }GraphKind; //枚举图的 4 种类型
typedef struct {
VRType adj; //对于无权图,用 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;

AMGraph.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"AMGraph.h"
//根据顶点本身数据,判断出顶点在二维数组中的位置
int LocateVex(MGraph * G, VertexType v)
{
int i = 0;
//遍历一维数组,找到变量v
for (; i<G->vexnum; i++)
{
if (G->vexs[i] == v)
{
break;
}
}
//如果找不到,输出提示语句,返回-1
if (i>G->vexnum)
{
printf("no such vertex.\n");
return -1;
}
return i;
}
//构造无向网。和无向图唯一的区别就是二阶矩阵中存储的是权值
void CreateUDN(MGraph* G)
{
scanf("%d,%d", &(G->vexnum), &(G->arcnum));
for (int i = 0; i < G->vexnum; i++)
{
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].adj = 0;
G->arcs[i][j].info = NULL;
}
}
for (int i = 0; i < G->arcnum; i++)
{
int v1, v2, w;
scanf("%d,%d,%d", &v1, &v2, &w);
int m = LocateVex(G, v1);
int n = LocateVex(G, v2);
if (m == -1 || n == -1)
{
printf("no this vertex\n");
return;
}
G->arcs[n][m].adj = w;
G->arcs[m][n].adj = w;//矩阵对称
}
}
//构造有向网,和有向图不同的是二阶矩阵中存储的是权值。
void CreateUDG(MGraph *G)
{
scanf("%d,%d", &(G->vexnum), &(G->arcnum));
for (int i = 0; i < G->vexnum; i++)
{
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].adj = 0;
G->arcs[i][j].info = NULL;
}
}
for (int i = 0; i < G->arcnum; i++)
{
int v1, v2, w;
scanf("%d,%d,%d", &v1, &v2, &w);
int n = LocateVex(G, v1);
int m = LocateVex(G, v2);
if (m == -1 || n == -1) {
printf("no this vertex\n");
return;
}
G->arcs[n][m].adj = w;
}
}

3.邻接矩阵的优缺点

优点

■直观、简单、好理解

■方便检查任意- 对顶点间是否存在边

■方便找任一顶点的所有“邻接点”(有边直接相连的顶点)

■方便计算任一顶点的"度”(从该点发出的边数为“出度”,指向该点的边数为"入度”)

 无向图:对应行(或列)非0元素的个数

 有向图:对应行非0元素的个数是“出度”;

 对应列非0元素的个数是"入度"

缺点

■不便于增加和删除顶点

■浪费空间一存稀疏图 人点很多而边很少)有大量无效元素

     对稠密图(特别是完全图)还是很合算的

■浪费时间---统计稀疏图中一共有多少条边

4.邻接表(链式)表示法

数据结构 - 图2_结点_07

●顶点:

按编号顺序将顶点数据存储在一维数组中;

●关联同一顶点的边(以顶点为尾的弧) :

用线性链表存储



数据结构 - 图2_i++_08

特点:

●邻接表不唯一

●若无向图中有n个顶点、e条边,则其邻接表需n个头结点和2e个表结点。适宜存储稀疏图。

●无向图中顶点vi的度为第i个单链表中的结点数。


数据结构 - 图2_结点_09

特点:

顶点Vi的出度为第i个单链表中的结点个数。

顶点Vi的入度为整个单链表中邻接点域值是i-1的结点个数。

数据结构 - 图2_i++_10


数据结构 - 图2_i++_11

特点:

顶点Vi的入度为第i个单链表中的结点个数。

顶点Vi的出度为整个单链表中邻接点域值是i-1的结点个数。

数据结构 - 图2_结点_12


5.邻接矩阵的(链式)存储表示:

1.

#define  MAX_VERTEX_NUM 20//最大顶点个数
#define VertexType int//顶点数据的类型
#define InfoType int//图中弧或者边包含的信息的类型

typedef struct ArcNode{ //表结点
int adjvex;//邻接点在数组中的位置下标
struct ArcNode * nextarc;//指向下一个邻接点的指针

}ArcNode;

typedef struct VNode{ //头结点
VertexType data;//顶点的数据域
ArcNode * firstarc;//指向邻接点的指针
}VNode,AdjList[MAX_VERTEX_NUM];//存储各链表头结点的数组

2.

数据结构 - 图2_i++_13

typedef struct ArcNode{ //表结点
int adjvex;//邻接点在数组中的位置下标
struct ArcNode * nextarc;//指向下一个邻接点的指针
InfoType * info;//信息域
}ArcNode;

图的结构定义:

typedef struct {
AdjList vertices;//图中顶点的数组
int vexnum,arcnum;//记录图中顶点数和边或弧数
int kind;//记录图的种类
}ALGraph;

如:一些操作

ALGragh G;//定义了邻接表表示的图G

G.vexum=5; G.arcnum=5; //图G包含5个顶点, 5条边

G.vertices[1].data= 'b'//图G中第2个顶点是b

p=G.vertices[1].firtarc;,//指针p指向顶点b的第一条边结点

p-> adjvex =4;//p指针所指边结点是到下标为4的结点的边


可采用邻接表表示法创建无向网

6.邻接矩阵与邻接表表示法的关系

数据结构 - 图2_结点_14

1.联系:邻接表中每个链表对应于邻接矩阵中的一行,链表中结点个数等于一行中非零元素的个数。

2.区别:

①对于任一-确定的无向图,邻接矩阵是唯一的(行列号与顶点编号一致),但邻接表不唯一(链接次序与顶点编号无关)。

②邻接矩阵的空间复杂度为O(n2),而邻接表的空间复杂度为O(n+e)。数量级都为e

3.用途:邻接矩阵多用于稠密图;而邻接表多用于稀疏图