数据结构之图论算法(一)图的存储结构
总:图 = 顶点 + 边
1、邻接矩阵存储结构(数组表示法)(Adjacency Matrix)
#define INFINITY INT_MAX
#define MAX_VERTEX_NUM 20
typedef int VRType;
typedef struct ArcCell{
VRType adj;
InfoType *info;
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
- 顶点——顶点表(一维数组)
- 图——二维数组整体
(因为数组表示法的特殊性,所以图与顶点一起构建,定义如下:)
typedef enum{
DG, DN, AG, AN}Graphkind;
typedef struct{
VertexType vexs[MAX_VERTEX_NUM];
AdjMatrix arcs;
int vexnum, arcnum;
Graphkind kind;
}MGraph;
设图为:A = (V,E),则
注意:A.arcs[ i ][ i ] = 0
上面是无向图的情况。其邻接矩阵是对称的。而有向图的邻接矩阵中,将列看为“出”,行看为“入”, 所以列上的顶点出,行上的顶点入,满足的才是1。因此,有向图不一定对称。
有向网络的邻接矩阵也是同理:
图的创建的算法表示:
Status CreateUDN(MGraph &G){
int LocateVex(MGraph, VertexType);
void Input(InfoType *);
int i,j,k, IncInfo;
scanf("%d %d %d",&G.vexnum,&G.arcnum, &IncInfo);
for(i = 0; i < G.vexnum; i++) scanf(&G.vexs[i]);
for(i = 0; i < G.vexnum; i++)
for(j = 0; j < G.vexnum; j++){
G.arcs[i][j].adj = INFINITY;
G.arcs[i][j].info = NULL;
}
VertexType v1, v2;
VRType w;
for(k = 0; k < G.arcnum;k++){
scanf(&v1, &v2, &w);
i = LocateVex(G, v1); j = LocateVex(G, v2);
G.arcs[i][j].adj = w;
if(IncInfo) Input(G.arcs[i][j].info);
G.arcs[j][i] = G.arcs[i][j];
}
return OK;
}
2、邻接表存储结构(Adjacency List)
#define MAX_VERTEX_NUM 20
typedef struct VNode{
VertexType data;
ArcNode *firstarc;
}VNode,AdjList[MAX_VERTEX_NUM];
邻接点域 |
权值 |
指针域 |
adjvex |
info |
nextarc |
typedef struct ArcNode{
int adjvex;
InfoType *info;
struct ArcNode *nextarc;
}ArcNode;
typedef struct{
AdjList vertices;
int vexnum, arcnum;
}ALGraph;
算法思想:(采用邻接表创建无向网)
- 输入总顶点数和总边数;
- 建立顶点表:
依次输入点的信存入顶点表中,使每个表头结点的指针域初始化为NULL
- 建立邻接表:
依次输入每条边依附的两个顶点,确定两个顶点的序号i和j,建立边结点;
将此边结点分别插入vi和vj对应的两个边链表的头部
Status CreateUDG(ALGraph &G){
int LocateVex(ALGraph, VertexType);
int i, k, j;
VertexType v1, v2;
ArcNode *p1, *p2;
scanf("%d %d", &G.vexnum, &G.arcnum);
for(i = 0; i < G.vexnum; i++){
scanf("%d", G.vertices[i].data);
G.vertices[i].firstarc = NULL;
}
for(k = 0; k < G.arcnum; k++){
scanf(&v1,&v2);
i = LocateVex(G, v1);
j = LocateVex(G, v2);
p1 = (ArcNode *)malloc(sizeof(ArcNode));
p1->adjvex = j;
p1->nextarc = G.vertices[i].firstarc;
G.vertices[i].firstarc = p1;
p2 = (ArcNode *)malloc(sizeof(ArcNode));
p2->adjvex = i;
p2->nextarc = G.vertices[j].firstarc;
G.vertices[j].firstarc = p2;
}
return OK;
}
十字链表存储结构
顶点结点:
数据域 |
头链表头指针 |
尾链表头指针 |
data |
firstin |
firstout |
typedef struct VexNode{
VertexType data;
ArcBox *firstin, *firstout;
}VexNode;
弧结点:
尾域 |
头域 |
头链域 |
尾链域 |
数据域 |
tailvex |
headadvex |
hlink |
tlink |
info |
typedef struct ArcBox{
int tailvex, headvex;
struct ArcBox *hlink, *tlink;
InfoType *info;
}ArcBox;
图:顶点表+有向图的总顶点数和总边数
typedef struct{
VexNode xlist[MAX_VERTEX_NUM];
int vexnum, arcnum;
}OLGraph;
用十字链表构造有向图的算法表示:
Status CreateDG(OLGraph &G){
int LocateVex(OLGraph, VertexType);
void Input(InfoType);
VertexType v1, v2;
ArcBox *p;
int IncInfo, i, j, k;
scanf("%d %d %d", &G.vexnum, &G.arcnum, &IncInfo);
for(i = 0; i < G.vexnum; i++){
scanf("%d",&G.xlist[i].data);
G.xlist[i].firstin = NULL; G.xlist[i].firstout = NULL;
}
for(k = 0; k < G.arcnum; k++){
scanf(&v1, &v2);
i = LocateVex(G, v1);j = LocateVex(G, v2);
p = (ArcBox*)malloc(sizeof(ArcBox));
p->tailvex = i;p->headvex = j;
p->hlink = G.xlist[j].firstin;p->tlink = G.xlist[i].firstout;
p->info = NULL;
G.xlist[j].firstin = G.xlist[i].firstout = p;
if(IncInfo) Input(*p->info);
}
return OK;
}
可以说十字链表是邻接表的进阶版
临界多重表存储结构
顶点结点:
弧结点:
顶点域1 |
ivex链域 |
顶点域2 |
jvex链域 |
数据域 |
ivex |
ilink |
jvex |
jlink |
info |
图:
横向的ivex相同,纵向的jvex相同
顺着ilink可以找到同意依附于ivex的下一条边,同理,顺着jlink可以找到同样依附于jvex的下一条边。