如题 自用笔记 如有错误欢迎及时指正
两种存储结构的转换涉及以下数据:
a.顶点数目与边数目
b.顶点信息
c.边信息
d.为要转换的结构申请空间
e.其他存储结构中保存的信息包括顶点度数,边权值等等
下面以无向带权图讨论该问题,有向图转换类似不再赘述。
存储结构定义
邻接表
*顶点表中带顶点度数域,边表中带权值域
/* ===预定义=== */
#define MAX_VEX_NUM 10
#define INF 2147483647
typedef int VertexType; //顶点数据类型
typedef int EdgeType; //边权值
/*===邻接表结构===*/
//边表结点
typedef struct ArcNode{
int adjvex; //以上一个顶点起始的边 所指向结尾顶点 在顶点表中的下标
EdgeType weight; //边权值
struct ArcNode *nextarc; //指向边表下一个结点
}ArcNode;
//顶点表结点
typedef struct VexNode{
VertexType data; //顶点的数据域
int degree; //度数
ArcNode *firstarc; //指向第一条出边 也就是指向第一个邻接顶点
} VexNode, AdjList[MAX_VEX_NUM]; //结构体数组 即为一个顺序存储的顶点表 用来保存顶点信息
//邻接表
typedef struct AdjacentList{
AdjList List;
int vexnum;
int edgenum;
}ALGraph,*AdjListGraph;
/* ===建立邻接表=== */
void CreateGraph_AdjList(AdjListGraph &G){
int numV, numE; //要创建图的总顶点数与边数
//建立初始结构
printf("输入图的总顶点数与边数,使用空格隔开: ");
scanf("%d%d", &numV, &numE);
if(numV>MAX_VEX_NUM){
printf("结点数超出限制!\n");
return;
}
G = (ALGraph *)malloc(sizeof(ALGraph));
G->vexnum = numV;
G->edgenum = numE;
printf("\n");
int i, j; //遍历控制器
int start, end; //一条弧的弧尾与弧头结点序号
int w; //弧权值
//设置顶点表List 输入顶点信息存入list的data域并初始化firstarc指针域
for (i = 0; i < G->vexnum; i++){
printf("请输入第%d个结点的信息: ", i + 1);
scanf("%d",&G->List[i].data);
G->List[i].firstarc = NULL; //初始化firstarc域
G->List[i].degree = -1;
}
printf("\n");
//创建边表数据
for (i = 0; i < G->edgenum; i++){
printf("依次输入第%d条边的'起始节点序号start','结束结点序号end','权值w',使用空格隔开(satrt与end在(1,...,n)取值)\n: ",i+1);
scanf("%d%d%d", &start, &end, &w);
printf("在无向图G中建立权值为%d的边(V%d,V%d)...\n", w, start, end);
//注意无向图特性 邻接表中 边要记录两次
//建立边<satrt,end>
ArcNode *arc1 = (ArcNode *)malloc(sizeof(ArcNode));
arc1->adjvex = end-1; //边的结束结点下标为end-1
arc1->weight = w; //权值
/* 采用头插法将边结点插入到顶点表表头结点之后 */
arc1->nextarc = G->List[start-1].firstarc;
G->List[start-1].firstarc = arc1;
/* 采用头插法将边结点插入到顶点表表头结点之后 */
//建立边<end,start>,若建立有向图,无此步
ArcNode *arc2 = (ArcNode *)malloc(sizeof(ArcNode));
arc2->adjvex = start-1; //边的结束结点下标为start-1
arc2->weight = w; //权值
/* 采用头插法将边结点插入到顶点表表头结点之后 */
arc2->nextarc = G->List[end-1].firstarc;
G->List[end - 1].firstarc = arc2;
/* 采用头插法将边结点插入到顶点表表头结点之后 */
}
}
/* ===输出图的邻接矩阵=== */
void PrintGraph_AdjList(AdjListGraph G){
ArcNode *p; //工作指针
int i, j; //遍历控制器
printf(" [顶点表] [边表] \n");
for (int i = 0; i < G->vexnum; i++){
//输出顶点表 第一个是下标 第二个是顶点信息
printf("%d[ V%d | ]->",i, G->List[i].data);
p = G->List[i].firstarc;
while(p!=NULL){ //p不空
//第一个是邻接点在顶点表中下标 第二个是边权值
printf("[ %d | %d | ]->", p->adjvex, p->weight);
p = p->nextarc;
}
printf("[ ∞ | ∞ | ^ ]");
printf("\n");
}
}
邻接矩阵
*内含一个数组保存顶点度数
/* ===预定义=== */
#define MAX_VEX_NUM 10
#define INF 2147483647
typedef int VertexType; //顶点数据类型
typedef int EdgeType; //边权值
/* ===邻接矩阵结构=== */
typedef struct AdjacentMatrix{
VertexType Vex[MAX_VEX_NUM]; //顶点表 保存顶点信息
int Degree[MAX_VEX_NUM]; //存储顶点度数
EdgeType Edge[MAX_VEX_NUM][MAX_VEX_NUM]; //边表 保存边信息
int vexnum,edgenum; //图当前顶点数与边数
} MGraph,*MatrixGraph;
/* ===创建图的邻接矩阵=== */
void CreateGraph_Matrix(MatrixGraph &G){
int numV, numE; //要创建图的总顶点数与边数
printf("输入图的总顶点数与边数,使用空格隔开: ");
scanf("%d%d", &numV, &numE);
if(numV>MAX_VEX_NUM){
printf("结点数超出限制!\n");
return;
}
G = (MGraph *)malloc(sizeof(MGraph));
G->vexnum = numV;
G->edgenum = numE;
memset(G->Degree, -1, MAX_VEX_NUM);
printf("\n");
int i, j; //遍历控制器
int start, end; //一条弧的弧尾与弧头结点序号
int w; //弧权值
//邻接矩阵即二维数组Edge初始化
for (i = 0; i < G->vexnum;i++){
for (j = 0; j < G->vexnum;j++){
if(i==j){ //主对角线结点值为0
G->Edge[i][j] = 0;
}else{ //其他结点值为INF
G->Edge[i][j] = INF;
}//if
}//for
}//for
//将顶点信息存入顶点表vex中
for (i = 0; i < G->vexnum;i++){
printf("请输入第%d个结点的信息: ", i + 1);
scanf("%d", &G->Vex[i]);
}
printf("\n");
//输入图的边信息
for (i = 0; i < G->edgenum;i++){
printf("依次输入第%d条边的'起始节点序号start','结尾结点序号end','权值w',使用空格隔开(satrt与end在(1,...,n)取值): ",i+1);
scanf("%d %d %d", &start, &end, &w);
G->Edge[start - 1][end - 1] = w;
G->Edge[end - 1][start - 1] = w; //无向图邻接矩阵对称性
//若建立的是有向图 把这一句去掉即可
}
}
/* ===输出图的邻接矩阵=== */
void PrintGraph_Matrix(MatrixGraph G){
int i, j;
printf("\n图的顶点为:");
for (i = 0; i < G->vexnum; i++)
printf("%d ", G->Vex[i]);
printf("\n输出邻接矩阵:\n");
printf("\t");
for (i = 0; i < G->vexnum; i++)
printf("\t%8d", G->Vex[i]);
for (i = 0; i < G->vexnum; i++)
{
printf("\n\n%8d", G->Vex[i]);
for (j = 0; j < G->vexnum; j++)
{
if (G->Edge[i][j] == INF)
printf("\t%8s", "∞");
else
printf("\t%8d", G->Edge[i][j]);
}
printf("\n");
}
}
代码实现
邻接表转换邻接矩阵
/* ===邻接表转换为邻接矩阵=== */
void ListToMatrix(AdjListGraph ALG,MatrixGraph &MTG){
MTG = (MGraph *)malloc(sizeof(MGraph)); //建立邻接矩阵结构
MTG->vexnum = ALG->vexnum; //矩阵图顶点数
MTG->edgenum = ALG->edgenum; //矩阵图边数
memset(MTG->Degree, -1, MAX_VEX_NUM);
int i, j; //遍历控制器
//邻接矩阵即二维数组Edge初始化
for (i = 0; i < MTG->vexnum;i++){
for (j = 0; j < MTG->vexnum;j++){
if(i==j){ //主对角线结点值为0
MTG->Edge[i][j] = 0;
}else{ //其他结点值为INF
MTG->Edge[i][j] = INF;
}//if
}//for
}//for
/* ===开始转换=== */
//将顶点信息存入顶点表vex中
for (int v = 0; v < MTG -> vexnum; v++){
MTG->Vex[v] = ALG->List[v].data; //MTG中顶点信息为ALG中顶点表信息
MTG->Degree[v] = ALG->List[v].degree;
}
for (int v = 0; v < MTG -> edgenum; v++){
for (ArcNode *p = ALG->List[v].firstarc; p != NULL;p=p->nextarc){ //p找到顶点信息
MTG->Edge[v][p->adjvex] = p->weight; //带权无向图 矩阵元素值为权值
MTG->Edge[p->adjvex][v] = p->weight; //由ALG中v到v的adjvex边建立MTG中对应元素
}
}
printf("\n");
/* ===开始转换=== */
}
邻接矩阵转换邻接表
/* ===邻接矩阵转换为邻接表=== */
void MatrixToList(MatrixGraph MTG,AdjListGraph &ALG){
ALG = (ALGraph *)malloc(sizeof(ALGraph)); //建立邻接表结构
ALG->vexnum = MTG->vexnum; //设置顶点数与边数
ALG->edgenum = MTG->edgenum;
/* ===开始转换=== */
//设置顶点表List 输入顶点信息存入list的data域并初始化firstarc指针域
for (int v = 0; v < ALG->vexnum; v++){
ALG->List[v].data = MTG->Vex[v]; //设置顶点信息
ALG->List[v].firstarc = NULL; //初始化firstarc域
ALG->List[v].degree = MTG->Degree[v];
}
//设置边表
//创建边表数据 遍历整个邻接矩阵
for (int v = 0; v < ALG->vexnum; v++){ //遍历每个元素
for (int w = 0; w <ALG->vexnum; w++){
if(MTG->Edge[v][w]!=INF&&v!=w){ //v到w边存在 去除对角线元素
ArcNode *p = (ArcNode *)malloc(sizeof(ArcNode));
p->adjvex = w; //终点为w 起点为v的边 采用头插入插入到对应的顶点表之后
p->weight = MTG->Edge[v][w]; //设置权值
p->nextarc=ALG->List[v].firstarc; //头插
ALG->List[v].firstarc = p;
}
}
}
printf("\n");
/* ===开始转换=== */
}
2021.12.29
11:30
以上