目录
↓ 图的定义
↓ 图的基本术语
→ 邻接与依附
→ 完全图
→ 顶点的度
→ 路径长度
→ 回路
→ 连通图、连通分量
→ 生成树与森林
↓ 邻接表存储结构:
→ 十字链表的结构:
→ 多重链表的结构:
一、图的基本概念
图的定义
在图形结构中,结点之间是多对多的任意关系,图中每个数据元素可以有多个直接前驱和多个直接后继,任意两个元素之间都可能相关。
图的基本术语
邻接与依附
完全图
n个顶点
无向完全图的边数为 n*(n-1)/ 2条边。
有向完全图的弧数为 n *(n-1)条弧。
顶点的度
无向图中:总度数为边数和的两倍
有向图中:总度数为各顶点的入度数 与 出度数之和。
其中有向图中:总入度、总出度和总弧数相等。
路径长度
回路
连通图、连通分量
生成树与森林
注意:生成树不唯一
二、图的存储结构
图的存储结构有:邻接矩阵、邻接表、十字链表、多重链表
邻接矩阵存储结构:
表示顶点之间的邻接关系,是顺序存储结构,也称为“数组表示法”.
用一维数组存储顶点的信息,用二维数组存储顶点的边(或弧)的信息。
邻接矩阵的优缺点:
优点:便于查看邻接点之间的关系,方便知道结点的度和边数,适用于稠密图。
缺点:删除或增加结点在二维数组中不方便;在稀疏图中,边数很少,结点数很多时,则存在大量的无效元素,遍历时耗费时间,也浪费空间
#define MAXVEX 20 //最大顶点个数 #define INFINITY 32767 //权值的极大值 typedef struct { int arcs[MAXVEX][MAXVEX]; //用于存储边或弧的信息 Vextype vex[MAXVEX]; //顶点的信息 int vexnum; //顶点的数目 int arcnum; //边或弧的数目 }AdiMatrix; //邻接矩阵
无向图的邻接矩阵为对称矩阵 求无向图第i个顶点 的度: 等于矩阵中第i行非零元素的个数。![]()
有向图的邻接矩阵不一定为对称矩阵。
第i个顶点的出度为:矩阵中第i行的非零元素的个数。
第i个顶点的入度为:矩阵中第i列的非零元素的个数。
邻接矩阵创建无向网:
算法思想:
1、输入网中的结点数、总边数
2、输入结点,存入一维数组中
3、初始化邻接矩阵,二维数组初始化值为权值的极大值
4、建立邻接矩阵。
void Create( AdjMatrix*G) { int i,j,k,weight; char vex1,vex2; //定义顶点的类型为字符型 printf("请输入无向网中的顶点数与边数:\n"); scanf("%d,%d",&G->vexnum,&G->arcnum); printf("请输入无向图%d个顶点\n",G->vexnum); for(i=1;i<=G->vexnum;i++) { printf("请输入第%d个顶点:\n",i); scanf("%c",&G->vex[i]); } for(i=1;i<=G->vexnum;i++) //初始化矩阵,也就是二维数组 { for(j=1;j<=G->vexnum;j++) { G->arcs[i][j]=INFINITF; //初始化矩阵的值为权的极大值 } } printf("请输入无向图中%d条边:\n",G->arcnum); for(k=1;k<=G->arcnum;k++) { printf("第%d条边:\n 顶点V",k); scanf("%c",&vex1); //一条边的一端的顶点 printf("<-->顶点V"); //这条边的另一端的顶点 scanf("%c",&vex2); printf("输入此边的权值:"); scanf("%d",&weight); i=LocateVex(G,vex1); //找到顶点在矩阵中行的位置 j=LocateVex(G,vex2); //另一个顶点在矩阵中列的位置 G->arcs[i][j]=weight; //如果不是网,赋值1 G->arcs[j][i]=weight; //如果是有向图,因有方向,删除此代码 } } int LocateVex(AdjMatrix*G,char v) //定义此函数用于查找顶点在矩阵中的行列位置。 { int i; for(i=1;i<=G->vexnum;i++) { if(G->vex[i]==v) return i; } return 0; }
邻接表存储结构:
对于稀疏图,邻接矩阵存储时浪费空间的问题,邻接表存储可以解决。
邻接表是图的链式存储结构,由边表和顶点表组成。
其中,边表是对每个顶点建立一个单链表,存放与该顶点邻接的所有顶点,相当于矩阵中的非零元素。
顶点表存放用于存储每个顶点的信息,以及指向该顶点边表的头指针。顶点表采用顺序存储结构。
邻接表的数据类型描述:
#define MAXVEX 20 typedef struct ArcNode //边表结构, { int adjvex; int weight; //网的边结构,存放权值 struct ArcNode*next; //指向下一个顶点的邻接点 }ArcNode; typedef struct VertexNode //顶点表结构 { char vexdata; //存放顶点的信息 ArcNode*head; //ArcNode类型的头指针指向边表。 }VertexNode; typedef struct { VertexNode vertex[MAXVEX]; //用VertexNode类型的数组存放邻接表 int vexnum; //顶点数 int arcnum; //弧或边数 }AdjList; //邻接表
邻接表求顶点的度:
对于无向图:第i个顶点的度为第i个单链表上的结点的个数。
而对于有向图:
第i个顶点的出度为第i个单链表上结点的个数,其入度需要遍历整个邻接表,统计该结点出现的次数。耗费时间。
为方便统计顶点的入度,可以采用逆邻接表,变的是边表中存放的是顶点通过入度弧所邻接的其他结点。所以根据需要采用不同的方法。
邻接表创建无向网:
算法思想:
1、统计顶点数与边数
2、输入顶点信息,建立顶点表,顶点表中head指针域置空
3、建立邻接表:
依次输入每条边依附的两个顶点。
确定两个顶点的序号 i 和 j,建立边结点。
将此边结点分别插入到 Vi 和Vj对应的两个边链表的头部,采用头插法。
#define MAXVEX 20 typedef struct ArcNode //边表结构, { int adjvex; struct ArcNode*next; //指向下一个顶点的邻接点 }ArcNode; typedef struct VertexNode //顶点表结构 { char vexdata; //存放顶点的信息 ArcNode*head; //ArcNode类型的头指针指向边表。 }VertexNode; typedef struct { VertexNode vertex[MAXVEX]; //用VertexNode类型的数组存放邻接表 int vexnum; //顶点数 int arcnum; //弧或边数 }AdjList; void CreateUDG(AdjList &G) { int i,j,k; char vex1,vex2; printf("请输入顶点数与边数\n"); scanf("%d,%d",&G.vexnum,&G.arcnum); printf("请输入图中%d个顶点:\n",G.vexnum); for(i=1;i<=G.vexnum;i++) { printf("请输入第%d个顶点:\n",i); scanf("%c",&G.vertex[i].vexdata); G.vertex[i].head=NULL; } printf("请输入图中%d条边\n",G.arcnum); for(k=1;k<=G.arcnum;k++) { printf("第%d条边:\n 顶点V",k); scanf("%d",&vex1); printf("<-->顶点V\n"); scanf("%d",&vex2); i=LocateVex(G,vex1); j=LocateVex(G,vex2); p1=new ArcNode; //生成一个新的边结点*p p1->adjvex=j; //存放邻接点的序号 p1->next=G.vertex[i].head; //用头插法将边结点插在顶点的后面 G.vertex[i].head=p1; p2=new ArcNode; //无向网是两条边,A-》B,B-》A p2->adjvex=i; p2->next=G.vertex[j].head; G.vertex[j].head=p2; } int LocateVex(AdjMatrix*G,char v) //定义此函数用于查找顶点在矩阵中的行列位置。 { int i; for(i=1;i<=G->vexnum;i++) { if(G->vex[i]==v) return i; } return 0; }
如果是有向网:
上述代码变化的是:
出度边与入度边二选一,如果选择入度边建立邻接表,需要采用逆邻接表。
A-》B A结点的出度: p1=new ArcNode; //生成一个新的边结点*p p1->adjvex=j; //存放邻接点的序号 p1->next=G.vertex[i].head; //用头插法将边结点插在顶点的后面 G.vertex[i].head=p1; B-》A A结点的入度: p2=new ArcNode; p2->adjvex=i; p2->next=G.vertex[j].head; G.vertex[j].head=p2;
邻接矩阵与邻接表的联系:
![]()
十字链表存储结构:
十字链表存储是有序图的另一种链式存储结构。是邻接表与逆邻接表的结合,可以同时求出顶点的入度与出度,可以解决邻接表只能求出度的问题。
十字链表的结构:
顶点表结点结构:
vexdata:顶点的信息
head:以该顶点为弧头的边表头指针 (相当于逆邻接表,顺着边表可以找顶点的入度)
tail: 以该顶点为弧尾的边表头指针 (相当于邻接表, 顺着边表可以找顶点的出度 )
边表结点结构:
tailvex :弧尾顶点的序号
headvex:弧头顶点的序号
hnextarc:指向同一弧头顶点的下一条弧
tnextarc: 指向同一弧尾顶点的下一条弧
十字链表存储结构图:
十字链表
十字链表的数据类型描述:
#define MAXVEX 20 typedef struct ArcNode //边表结点结构 { int tailvex,headvex; struct ArcNode*hnextarc,*tnextarc; }ArcNode; typedef struct VertexNode //顶点表结点结构 { char vexdata; ArcNode*head,*tail; //指向边表的头指针 }VertexNode; typedef sturct { VertexNode vertex[MAXVEX]; //存放顶点表 int vexnum; //顶点数 int arcnum; //弧数 }OrthList;
多重链表的存储结构:
多重链表是无向图中的链式存储结构。多重链表可以更方便对无向图的操作。
多重链表中边的两个顶点都存在边表的一个结点中,每个边结点同时链接两个链表。
多重链表的结构:
顶点表结点结构:
vexdat:存放顶点的信息
head:该顶点的边表的头指针
mark:标志域,标记该边访问过,(如果此边标记过,直接指向这条边)
ivex 和 jvex:分别存放边的两个顶点的序号
inext :指向依附于 同一 ivex 顶点的下一条边
jnext:指向依附于同一 jvex 顶点的下一条边
多重链表的结构图:
邻接表
多重链表
多重链表的数据类型描述:
#define MAXVEX 20 typedef struct ArcNode //边表结点结构 { int mark,ivex,jvex; struct ArcNode*inext,*jnext; }ArcNode; typedef struct VertexNode //顶点表结点结构 { char vexdata; ArcNode*head; //指向边表的头指针 }VertexNode; typedef sturct { VertexNode vertex[MAXVEX]; //存放顶点表 int vexnum; //顶点数 int arcnum; //弧数 }AdijMultipleList;