《数据结构(C语言版)第二版》第六章-图(6.4 图的存储结构——链式存储——6.4.2 邻接表(稀疏图)、6.4.3 十字链表、6.4.4 邻接多重表)

6.4.2 邻接表(稀疏图)

采用邻接表表示法创建无向图

//算法6.2 采用邻接表表示法创建无向图

#include <stdio.h>
#include <stdlib.h>

#define MVNum 100

typedef int OtherInfo;   //假设在边结点中的数据域存储边的权值,且边的权值类型为整型
typedef char VerTexType;  //假设顶点的数据类型为字符型

typedef struct ArcNode
{
	int adjvex;
	struct ArcNode* nextarc;
	OtherInfo info;
}ArcNode;  //边结点

typedef struct VNode
{
	VerTexType data;
	ArcNode* firstarc; 
}VNode,AdjList[MVNum];  //表头结点

typedef struct
{
	AdjList vertices;  //存储所有顶点
	int vexnum;  //顶点总数
	int arcnum;  //总边数
}ALGraph;  //图的信息

void CreateUDG(ALGraph& G);
int LocateVex(ALGraph& G, VerTexType v);
void printALGraph(ALGraph &G);

int main()
{
	ALGraph G = { {'\0',NULL}, 0,0};
	CreateUDG(G);
	printALGraph(G);

	return 0;
}

void CreateUDG(ALGraph& G)
{
	int i = 0;
	int k = 0;
	VerTexType v1 = 0;
	VerTexType v2 = 0;
	int j = 0;
	ArcNode *p1 = NULL;
	ArcNode *p2 = NULL;

	printf("请输入无向图的总顶点数:");
	scanf_s(" %d", &G.vexnum);

	printf("请输入无向图的总边数:");
	scanf_s(" %d", &G.arcnum);

	for (i = 0; i < G.vexnum; ++i)
	{
		printf("请输入第%d个顶点的值:", i + 1);
		scanf_s(" %c", &(G.vertices[i].data));
		G.vertices[i].firstarc = NULL;   //初始化
	}

	for (k = 0; k < G.arcnum; k++)
	{
		printf("请输入第%d条边依附的两个顶点(用空格间隔,输入结束后按回车): ", k + 1);
		scanf_s(" %c %c", &v1, sizeof(VerTexType), &v2, sizeof(VerTexType)); 

		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;  //将新结点*p1插入顶点Vi的边表头部

		p2 = (ArcNode*)malloc(sizeof(ArcNode));
		p2->adjvex = i;
		p2->nextarc = G.vertices[j].firstarc;
		G.vertices[j].firstarc = p2;  //将与*p1对称的新的边结点*p2插入顶点Vj的边表头部
	}
}


//在G的顶点表vexs中获取字符v的下标(数组G.vexs的下标从0开始)
int LocateVex(ALGraph& G, VerTexType v)
{
	int i = 0;
	for (i = 0; i < G.vexnum && (G.vertices[i].data != v); ++i)
	{
		;
	}

	return i;
}


//打印邻接表
void printALGraph(ALGraph& G)
{
	int i = 0;
	ArcNode* pMove = NULL;

	for (i = 0; i < G.vexnum; i++)
	{
		printf("\n第%d个顶点为:%c", i + 1, G.vertices[i].data);

		pMove = G.vertices[i].firstarc;
		if (pMove)
		{
			printf("\n与第%d个顶点相邻接的每个顶点在图中的位置(下标值)为:", i + 1);
			while (pMove)
			{
				printf("%d ", pMove->adjvex);
				pMove = pMove->nextarc;
			}
		}
		else
		{
			printf("\n没有与第%d个顶点相邻接的顶点。", i + 1);
		}
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一个图的邻接矩阵表示是唯一的,但其邻接表表示不唯一。

不改变图中每个顶点的命名方式,也不改变图的边(每条边的起终点),
仅改变边的输入次序时,图的邻接表中每个顶点后面边表中的结点排序方式会发生变化。
因为图中的顶点没变,边也没变,每个顶点及其边表中的内容不会发生变化。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

采用邻接表表示法创建有向图

//采用邻接表表示法创建有向图

#include <stdio.h>
#include <stdlib.h>

#define MVNum 100

typedef int OtherInfo;   //假设在边结点中的数据域存储边的权值,且边的权值类型为整型
typedef char VerTexType;  //假设顶点的数据类型为字符型

typedef struct ArcNode
{
	int adjvex;
	struct ArcNode* nextarc;
	OtherInfo info;
}ArcNode;  //边结点

typedef struct VNode
{
	VerTexType data;
	ArcNode* firstarc;
}VNode, AdjList[MVNum];  //表头结点

typedef struct
{
	AdjList vertices;  //存储所有顶点
	int vexnum;  //顶点总数
	int arcnum;  //总边数
}ALGraph;  //图的信息

void CreateDG(ALGraph& G);
int LocateVex(ALGraph& G, VerTexType v);
void printALGraph(ALGraph& G);

int main()
{
	ALGraph G = { {'\0',NULL}, 0,0 };
	CreateDG(G);
	printALGraph(G);

	return 0;
}

//采用邻接表表示法创建有向图
void CreateDG(ALGraph& G)
{
	int i = 0;
	int k = 0;
	VerTexType v1 = 0;
	VerTexType v2 = 0;
	int j = 0;
	ArcNode* p1 = NULL;
	ArcNode* p2 = NULL;

	printf("请输入有向图的总顶点数:");
	scanf_s(" %d", &G.vexnum);

	printf("请输入有向图的总边数:");
	scanf_s(" %d", &G.arcnum);

	for (i = 0; i < G.vexnum; ++i)
	{
		printf("请输入第%d个顶点的值:", i + 1);
		scanf_s(" %c", &(G.vertices[i].data));
		G.vertices[i].firstarc = NULL;   //初始化
	}

	for (k = 0; k < G.arcnum; k++)
	{
		printf("请输入第%d条边依附的两个顶点(用空格间隔,输入结束后按回车): ", k + 1);
		scanf_s(" %c %c", &v1, sizeof(VerTexType), &v2, sizeof(VerTexType));

		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;  //将新结点*p1插入顶点Vi的边表头部
	}
}


//在G的顶点表vexs中获取字符v的下标(数组G.vexs的下标从0开始)
int LocateVex(ALGraph& G, VerTexType v)
{
	int i = 0;
	for (i = 0; i < G.vexnum && (G.vertices[i].data != v); ++i)
	{
		;
	}

	return i;
}


//打印邻接表
void printALGraph(ALGraph& G)
{
	int i = 0;
	ArcNode* pMove = NULL;

	for (i = 0; i < G.vexnum; i++)
	{
		printf("\n第%d个顶点为:%c", i + 1, G.vertices[i].data);

		pMove = G.vertices[i].firstarc;
		if (pMove)
		{
			printf("\n将第%d个顶点作为出度,与其相邻接的每个顶点在图中的位置(下标值)为:", i + 1);
			while (pMove)
			{
				printf("%d ", pMove->adjvex);
				pMove = pMove->nextarc;
			}
		}
		else
		{
			printf("\n将第%d个顶点作为出度,没有与其相邻接的顶点。", i + 1);
		}
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

创建有向图的逆邻接表

//创建有向图的逆邻接表

#include <stdio.h>
#include <stdlib.h>

#define MVNum 100

typedef int OtherInfo;   //假设在边结点中的数据域存储边的权值,且边的权值类型为整型
typedef char VerTexType;  //假设顶点的数据类型为字符型

typedef struct ArcNode
{
	int adjvex;
	struct ArcNode* nextarc;
	OtherInfo info;
}ArcNode;  //边结点

typedef struct VNode
{
	VerTexType data;
	ArcNode* firstarc;
}VNode, AdjList[MVNum];  //表头结点

typedef struct
{
	AdjList vertices;  //存储所有顶点
	int vexnum;  //顶点总数
	int arcnum;  //总边数
}ALGraph;  //图的信息

void CreateDG(ALGraph& G);
int LocateVex(ALGraph& G, VerTexType v);
void printALGraph(ALGraph& G);

int main()
{
	ALGraph G = { {'\0',NULL}, 0,0 };
	CreateDG(G);
	printALGraph(G);

	return 0;
}

//创建有向图的逆邻接表
void CreateDG(ALGraph& G)
{
	int i = 0;
	int k = 0;
	VerTexType v1 = 0;
	VerTexType v2 = 0;
	int j = 0;
	ArcNode* p1 = NULL;
	ArcNode* p2 = NULL;

	printf("请输入有向图的总顶点数:");
	scanf_s(" %d", &G.vexnum);

	printf("请输入有向图的总边数:");
	scanf_s(" %d", &G.arcnum);

	for (i = 0; i < G.vexnum; ++i)
	{
		printf("请输入第%d个顶点的值:", i + 1);
		scanf_s(" %c", &(G.vertices[i].data));
		G.vertices[i].firstarc = NULL;   //初始化
	}

	for (k = 0; k < G.arcnum; k++)
	{
		printf("请输入第%d条边依附的两个顶点(用空格间隔,输入结束后按回车): ", k + 1);
		scanf_s(" %c %c", &v1, sizeof(VerTexType), &v2, sizeof(VerTexType));

		i = LocateVex(G, v1);
		j = LocateVex(G, v2);

		p1 = (ArcNode*)malloc(sizeof(ArcNode));
		p1->adjvex = i;
		p1->nextarc = G.vertices[j].firstarc;
		G.vertices[j].firstarc = p1;  //将新结点*p1插入顶点Vj的边表头部
	}
}


//在G的顶点表vexs中获取字符v的下标(数组G.vexs的下标从0开始)
int LocateVex(ALGraph& G, VerTexType v)
{
	int i = 0;
	for (i = 0; i < G.vexnum && (G.vertices[i].data != v); ++i)
	{
		;
	}

	return i;
}


//打印逆邻接表
void printALGraph(ALGraph& G)
{
	int i = 0;
	ArcNode* pMove = NULL;

	for (i = 0; i < G.vexnum; i++)
	{
		printf("\n第%d个顶点为:%c", i + 1, G.vertices[i].data);

		pMove = G.vertices[i].firstarc;
		if (pMove)
		{
			printf("\n将第%d个顶点作为入度,与其相邻接的每个顶点在图中的位置(下标值)为:", i + 1);
			while (pMove)
			{
				printf("%d ", pMove->adjvex);
				pMove = pMove->nextarc;
			}
		}
		else
		{
			printf("\n将第%d个顶点作为入度,没有与其相邻接的顶点。", i + 1);
		}
	}
}

在这里插入图片描述

在这里插入图片描述

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

#include <stdio.h>
#include <stdlib.h>

#define MVNum 100

typedef int OtherInfo;   //假设在边结点中的数据域存储边的权值,且边的权值类型为整型
typedef char VerTexType;  //假设顶点的数据类型为字符型

typedef struct ArcNode
{
	int adjvex;
	struct ArcNode* nextarc;
	OtherInfo info;
}ArcNode;  //边结点

typedef struct VNode
{
	VerTexType data;
	ArcNode* firstarc;
}VNode, AdjList[MVNum];  //表头结点

typedef struct
{
	AdjList vertices;  //存储所有顶点
	int vexnum;  //顶点总数
	int arcnum;  //总边数
}ALGraph;  //图的信息

void CreateUDN(ALGraph& G);
int LocateVex(ALGraph& G, VerTexType v);
void printALGraph(ALGraph& G);

int main()
{
	ALGraph G = { {'\0',NULL}, 0,0 };
	CreateUDN(G);
	printALGraph(G);

	return 0;
}

//采用邻接表表示法创建无向网
void CreateUDN(ALGraph& G)
{
	int i = 0;
	int k = 0;
	VerTexType v1 = 0;
	VerTexType v2 = 0;
	int j = 0;
	ArcNode* p1 = NULL;
	ArcNode* p2 = NULL;
	int w = 0;

	printf("请输入无向网的总顶点数:");
	scanf_s(" %d", &G.vexnum);

	printf("请输入无向网的总边数:");
	scanf_s(" %d", &G.arcnum);

	for (i = 0; i < G.vexnum; ++i)
	{
		printf("请输入第%d个顶点的值:", i + 1);
		scanf_s(" %c", &(G.vertices[i].data));
		G.vertices[i].firstarc = NULL;   //初始化
	}

	for (k = 0; k < G.arcnum; k++)
	{
		printf("请输入第%d条边依附的两个顶点(用空格间隔,输入结束后按回车): ", k + 1);
		scanf_s(" %c %c", &v1, sizeof(VerTexType), &v2, sizeof(VerTexType));		
		printf("请输入第%d条边的权值 : ", k + 1);
		scanf_s(" %d", &w, sizeof(OtherInfo));

		i = LocateVex(G, v1);
		j = LocateVex(G, v2);

		p1 = (ArcNode*)malloc(sizeof(ArcNode));
		p1->adjvex = j;
		p1->info = w;
		p1->nextarc = G.vertices[i].firstarc;
		G.vertices[i].firstarc = p1;  //将新结点*p1插入顶点Vi的边表头部

		p2 = (ArcNode*)malloc(sizeof(ArcNode));
		p2->adjvex = i;
		p1->info = w;
		p2->nextarc = G.vertices[j].firstarc;
		G.vertices[j].firstarc = p2;  //将与*p1对称的新的边结点*p2插入顶点Vj的边表头部
	}
}


//在G的顶点表vexs中获取字符v的下标(数组G.vexs的下标从0开始)
int LocateVex(ALGraph& G, VerTexType v)
{
	int i = 0;
	for (i = 0; i < G.vexnum && (G.vertices[i].data != v); ++i)
	{
		;
	}

	return i;
}


//打印邻接表
void printALGraph(ALGraph& G)
{
	int i = 0;
	ArcNode* pMove = NULL;

	for (i = 0; i < G.vexnum; i++)
	{
		printf("\n第%d个顶点为:%c", i + 1, G.vertices[i].data);

		pMove = G.vertices[i].firstarc;
		if (pMove)
		{
			printf("\n与第%d个顶点相邻接的每个顶点在网中的位置(下标值)为:", i + 1);
			while (pMove)
			{
				printf("%d ", pMove->adjvex);
				pMove = pMove->nextarc;
			}
		}
		else
		{
			printf("\n没有与第%d个顶点相邻接的顶点。", i + 1);
		}
	}
}

在这里插入图片描述

在这里插入图片描述

采用邻接表表示法创建有向网

#include <stdio.h>
#include <stdlib.h>

#define MVNum 100

typedef int OtherInfo;   //假设在边结点中的数据域存储边的权值,且边的权值类型为整型
typedef char VerTexType;  //假设顶点的数据类型为字符型

typedef struct ArcNode
{
	int adjvex;
	struct ArcNode* nextarc;
	OtherInfo info;
}ArcNode;  //边结点

typedef struct VNode
{
	VerTexType data;
	ArcNode* firstarc;
}VNode, AdjList[MVNum];  //表头结点

typedef struct
{
	AdjList vertices;  //存储所有顶点
	int vexnum;  //顶点总数
	int arcnum;  //总边数
}ALGraph;  //图的信息

void CreateDN(ALGraph& G);
int LocateVex(ALGraph& G, VerTexType v);
void printALGraph(ALGraph& G);

int main()
{
	ALGraph G = { {'\0',NULL}, 0,0 };
	CreateDN(G);
	printALGraph(G);

	return 0;
}

//采用邻接表表示法创建有向网
void CreateDN(ALGraph& G)
{
	int i = 0;
	int k = 0;
	VerTexType v1 = 0;
	VerTexType v2 = 0;
	int j = 0;
	ArcNode* p1 = NULL;
	ArcNode* p2 = NULL;
	int w = 0;

	printf("请输入有向网的总顶点数:");
	scanf_s(" %d", &G.vexnum);

	printf("请输入有向网的总边数:");
	scanf_s(" %d", &G.arcnum);

	for (i = 0; i < G.vexnum; ++i)
	{
		printf("请输入第%d个顶点的值:", i + 1);
		scanf_s(" %c", &(G.vertices[i].data));
		G.vertices[i].firstarc = NULL;   //初始化
	}

	for (k = 0; k < G.arcnum; k++)
	{
		printf("请输入第%d条边依附的两个顶点(用空格间隔,输入结束后按回车): ", k + 1);
		scanf_s(" %c %c", &v1, sizeof(VerTexType), &v2, sizeof(VerTexType));		
		printf("请输入第%d条边的权值 : ", k + 1);
		scanf_s(" %d", &w, sizeof(OtherInfo));

		i = LocateVex(G, v1);
		j = LocateVex(G, v2);

		p1 = (ArcNode*)malloc(sizeof(ArcNode));
		p1->adjvex = j;
		p1->info = w;
		p1->nextarc = G.vertices[i].firstarc;
		G.vertices[i].firstarc = p1;  //将新结点*p1插入顶点Vi的边表头部
	}
}


//在G的顶点表vexs中获取字符v的下标(数组G.vexs的下标从0开始)
int LocateVex(ALGraph& G, VerTexType v)
{
	int i = 0;
	for (i = 0; i < G.vexnum && (G.vertices[i].data != v); ++i)
	{
		;
	}

	return i;
}


//打印邻接表
void printALGraph(ALGraph& G)
{
	int i = 0;
	ArcNode* pMove = NULL;

	for (i = 0; i < G.vexnum; i++)
	{
		printf("\n第%d个顶点为:%c", i + 1, G.vertices[i].data);

		pMove = G.vertices[i].firstarc;
		if (pMove)
		{
			printf("\n将第%d个顶点作为出度,与其相邻接的每个顶点在网中的位置(下标值)为:", i + 1);
			while (pMove)
			{
				printf("%d ", pMove->adjvex);
				pMove = pMove->nextarc;
			}
		}
		else
		{
			printf("\n将第%d个顶点作为出度,没有与第%d个顶点相邻接的顶点。", i + 1);
		}
	}
}

在这里插入图片描述

在这里插入图片描述

创建有向网的逆邻接表

#include <stdio.h>
#include <stdlib.h>

#define MVNum 100

typedef int OtherInfo;   //假设在边结点中的数据域存储边的权值,且边的权值类型为整型
typedef char VerTexType;  //假设顶点的数据类型为字符型

typedef struct ArcNode
{
	int adjvex;
	struct ArcNode* nextarc;
	OtherInfo info;
}ArcNode;  //边结点

typedef struct VNode
{
	VerTexType data;
	ArcNode* firstarc;
}VNode, AdjList[MVNum];  //表头结点

typedef struct
{
	AdjList vertices;  //存储所有顶点
	int vexnum;  //顶点总数
	int arcnum;  //总边数
}ALGraph;  //图的信息

void CreateDN(ALGraph& G);
int LocateVex(ALGraph& G, VerTexType v);
void printALGraph(ALGraph& G);

int main()
{
	ALGraph G = { {'\0',NULL}, 0,0 };
	CreateDN(G);
	printALGraph(G);

	return 0;
}

//创建有向网的逆邻接表
void CreateDN(ALGraph& G)
{
	int i = 0;
	int k = 0;
	VerTexType v1 = 0;
	VerTexType v2 = 0;
	int j = 0;
	ArcNode* p1 = NULL;
	ArcNode* p2 = NULL;
	int w = 0;

	printf("请输入有向网的总顶点数:");
	scanf_s(" %d", &G.vexnum);

	printf("请输入有向网的总边数:");
	scanf_s(" %d", &G.arcnum);

	for (i = 0; i < G.vexnum; ++i)
	{
		printf("请输入第%d个顶点的值:", i + 1);
		scanf_s(" %c", &(G.vertices[i].data));
		G.vertices[i].firstarc = NULL;   //初始化
	}

	for (k = 0; k < G.arcnum; k++)
	{
		printf("请输入第%d条边依附的两个顶点(用空格间隔,输入结束后按回车): ", k + 1);
		scanf_s(" %c %c", &v1, sizeof(VerTexType), &v2, sizeof(VerTexType));
		printf("请输入第%d条边的权值 : ", k + 1);
		scanf_s(" %d", &w, sizeof(OtherInfo));

		i = LocateVex(G, v1);
		j = LocateVex(G, v2);

		p1 = (ArcNode*)malloc(sizeof(ArcNode));
		p1->adjvex = i;
		p1->info = w;
		p1->nextarc = G.vertices[j].firstarc;
		G.vertices[j].firstarc = p1;  //将新结点*p1插入顶点Vj的边表头部
	}
}


//在G的顶点表vexs中获取字符v的下标(数组G.vexs的下标从0开始)
int LocateVex(ALGraph& G, VerTexType v)
{
	int i = 0;
	for (i = 0; i < G.vexnum && (G.vertices[i].data != v); ++i)
	{
		;
	}

	return i;
}


//打印逆邻接表
void printALGraph(ALGraph& G)
{
	int i = 0;
	ArcNode* pMove = NULL;

	for (i = 0; i < G.vexnum; i++)
	{
		printf("\n第%d个顶点为:%c", i + 1, G.vertices[i].data);

		pMove = G.vertices[i].firstarc;
		if (pMove)
		{
			printf("\n将第%d个顶点作为入度,与其相邻接的每个顶点在网中的位置(下标值)为:", i + 1);
			while (pMove)
			{
				printf("%d ", pMove->adjvex);
				pMove = pMove->nextarc;
			}
		}
		else
		{
			printf("\n将第%d个顶点作为入度,没有与第%d个顶点相邻接的顶点。", i + 1);
		}
	}
}

在这里插入图片描述

6.4.3 十字链表

采用十字链表表示法创建有向图

//采用十字链表表示法创建有向图

#include <stdio.h>
#include <stdlib.h>

#define MAX_VERTEX_NUM  20

typedef int InfoType;   //假设在边结点中的数据域存储边的权值,且边的权值类型为整型
typedef char VerTexType;  //假设顶点的数据类型为字符型

typedef struct ArcBox
{
	int tailvex;
	int headvex;
	struct ArcBox* hlink;
	struct ArcBox* tlink; 
	InfoType *info;
}ArcBox;  

typedef struct VexNode
{
	VerTexType data;
	ArcBox *firstin;
	ArcBox *firstout;
}VexNode; 

typedef struct
{
	VexNode xlist[MAX_VERTEX_NUM];  //表头向量
	int vexnum;  //顶点总数
	int arcnum;  //总边数
}OLGraph;  //图的信息

void CreateOLGraph(OLGraph& G);
int LocateVex(OLGraph& G, VerTexType v);
void printOLGraph(OLGraph& G);

int main()
{
	OLGraph G = { {'\0',NULL,NULL}, 0,0 };
	CreateOLGraph(G);
	printOLGraph(G);

	return 0;
}

//采用十字链表表示法创建有向图
void CreateOLGraph(OLGraph& G)
{
	int i = 0;
	int j = 0;
	int k = 0;
	VerTexType v1 = 0;
	VerTexType v2 = 0;
	ArcBox* p1 = NULL;


	printf("请输入有向图的总顶点数:");
	scanf_s(" %d", &G.vexnum);

	printf("请输入有向图的总边数:");
	scanf_s(" %d", &G.arcnum);

	for (i = 0; i < G.vexnum; ++i)
	{
		printf("请输入第%d个顶点的值:", i + 1);
		scanf_s(" %c", &(G.xlist[i].data));
		G.xlist[i].firstin = NULL;
		G.xlist[i].firstout = NULL;//初始化
	}

	for (k = 0; k < G.arcnum; k++)
	{
		printf("请输入第%d条弧依附的两个顶点(用空格间隔,输入结束后按回车): ", k + 1);
		scanf_s(" %c %c", &v1, sizeof(VerTexType), &v2, sizeof(VerTexType));
		//起点v1是弧尾,终点v2是弧头
		//弧<v1,v2>是v1的出度,是v2的入度

		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
		//起点v1是弧尾,下标值为i;终点v2是弧头,下标值为j
		//弧<v1,v2>是第i+1个顶点的出度firstout,是第j+1个顶点的入度firstin

		p1 = (ArcBox*)malloc(sizeof(ArcBox));

		p1->tailvex = i;  //起点v1是弧尾,下标值为i
		p1->headvex = j;   //终点v2是弧头,下标值为j

		//p1弧结点中的链域tlink指向与其弧尾tailvext相同的下一条弧(即指向第i+1个顶点v1的下一个出度firstout)
		p1->tlink = G.xlist[i].firstout;  //p1指向的弧<v1,v2>是第i+1个顶点v1的出度firstout
		G.xlist[i].firstout = p1;   //前插法将p1插入到第i+1个顶点v1的出度单链表中

		//p1弧结点中的链域hlink指向与其弧头headvex相同的下一条弧(即指向第j+1个顶点v2的下一个入度firstin)
		p1->hlink = G.xlist[j].firstin;   //p1指向的弧<v1,v2>是第j+1个顶点v2的入度firstin
		G.xlist[j].firstin = p1;  //前插法将p1插入到第j+1个顶点v2的入度单链表中
	}
}


//在G的顶点表xlist中获取字符v的下标(数组G.xlist的下标从0开始)
int LocateVex(OLGraph& G, VerTexType v)
{
	int i = 0;
	for (i = 0; i < G.vexnum && (G.xlist[i].data != v); ++i)
	{
		;
	}

	return i;
}


//打印十字链表
void printOLGraph(OLGraph& G)
{
	int i = 0;
	ArcBox* pMoveIn = NULL;
	ArcBox* pMoveOut = NULL;

	for (i = 0; i < G.vexnum; i++)
	{
		printf("\n第%d个顶点为:%c", i + 1, G.xlist[i].data);

		pMoveOut = G.xlist[i].firstout;
		if (pMoveOut)
		{
			printf("\n将第%d个顶点作为出度,与其相邻接的每个顶点在图中的位置(下标值)为:", i + 1);
			while (pMoveOut)
			{
				printf("%d ", pMoveOut->headvex);
				pMoveOut = pMoveOut->tlink;
			}
		}
		else
		{
			printf("\n将第%d个顶点作为出度,没有与其相邻接的顶点。", i + 1);
		}


		pMoveIn = G.xlist[i].firstin;
		if (pMoveIn)
		{
			printf("\n将第%d个顶点作为入度,与其相邻接的每个顶点在图中的位置(下标值)为:", i + 1);
			while (pMoveIn)
			{
				printf("%d ", pMoveIn->tailvex);
				pMoveIn = pMoveIn->hlink;
			}
		}
		else
		{
			printf("\n将第%d个顶点作为入度,没有与其相邻接的顶点。", i + 1);
		}

	}
}

在这里插入图片描述
在这里插入图片描述

该有向图的邻接矩阵,其中各行、各列中不为0的元素,与其十字链表每个顶点的出度、入度结果有对应关系。
在这里插入图片描述

采用十字链表表示法创建有向网

输入并读取权值,赋值到 弧结点 ArcBox 结构中的 info 成员即可。

//采用十字链表表示法创建有向网

void CreateOLGraph(OLGraph& G)
{
	int i = 0;
	int j = 0;
	int k = 0;
	VerTexType v1 = 0;
	VerTexType v2 = 0;
	ArcBox* p1 = NULL;

	int* w = 0;

	printf("请输入有向网的总顶点数:");
	scanf_s(" %d", &G.vexnum);

	printf("请输入有向网的总边数:");
	scanf_s(" %d", &G.arcnum);

	for (i = 0; i < G.vexnum; ++i)
	{
		printf("请输入第%d个顶点的值:", i + 1);
		scanf_s(" %c", &(G.xlist[i].data));
		G.xlist[i].firstin = NULL;
		G.xlist[i].firstout = NULL;//初始化
	}

	for (k = 0; k < G.arcnum; k++)
	{
		printf("请输入第%d条弧依附的两个顶点(用空格间隔,输入结束后按回车): ", k + 1);
		scanf_s(" %c %c", &v1, sizeof(VerTexType), &v2, sizeof(VerTexType));

		printf("请输入第%d条边的权值 : ", k + 1);
		scanf_s(" %d", w, sizeof(InfoType));  //在ArcBox中,info由指向int的指针定义

		i = LocateVex(G, v1);
		j = LocateVex(G, v2);

		p1 = (ArcBox*)malloc(sizeof(ArcBox));

		p1->tailvex = i; 
		p1->headvex = j;  

		p1->info = w;  //赋值到弧结点p1中的info成员

		p1->tlink = G.xlist[i].firstout;  
		G.xlist[i].firstout = p1;   

		p1->hlink = G.xlist[j].firstin;   
		G.xlist[j].firstin = p1;  
	}
}

6.4.4 邻接多重表

采用邻接多重表表示法创建无向图

//采用邻接多重表表示法创建无向图

#include <stdio.h>
#include <stdlib.h>

#define MAX_VERTEX_NUM  20

typedef enum {unvisited,visited} VisitIf;
typedef int InfoType;   //假设在边结点中的数据域存储边的权值,且边的权值类型为整型
typedef char VerTexType;  //假设顶点的数据类型为字符型

typedef struct EBox
{
	VisitIf mark;
	int ivex;
	int jvex;
	struct EBox* ilink;
	struct EBox* jlink; 
	InfoType *info;
}EBox;  

typedef struct VexBox
{
	VerTexType data;
	EBox* firstedge;
}VexBox; 

typedef struct
{
	VexBox adjmulist[MAX_VERTEX_NUM];  //表头向量
	int vexnum;  //顶点总数
	int edgenum;  //总边数
}AMLGraph;  //图的信息

void CreateAMLGraph(AMLGraph& G);
int LocateVex(AMLGraph& G, VerTexType v);
void printAMLGraph(AMLGraph& G);

int main()
{
	AMLGraph G = { {'\0',NULL,NULL}, 0,0 };
	CreateAMLGraph(G);
	printAMLGraph(G);

	return 0;
}

//采用邻接多重表表示法创建无向图
void CreateAMLGraph(AMLGraph& G)
{
	int i = 0;
	int j = 0;
	int k = 0;
	VerTexType v1 = 0;
	VerTexType v2 = 0;
	EBox* p1 = NULL;

	printf("请输入无向图的总顶点数:");
	scanf_s(" %d", &G.vexnum);

	printf("请输入无向图的总边数:");
	scanf_s(" %d", &G.edgenum);

	for (i = 0; i < G.vexnum; ++i)
	{
		printf("请输入第%d个顶点的值:", i + 1);
		scanf_s(" %c", &(G.adjmulist[i].data));
		G.adjmulist[i].firstedge = NULL;  //初始化
	}

	for (k = 0; k < G.edgenum; k++)
	{
		printf("请输入第%d条弧依附的两个顶点(用空格间隔,输入结束后按回车): ", k + 1);
		scanf_s(" %c %c", &v1, sizeof(VerTexType), &v2, sizeof(VerTexType));
		
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);

		p1 = (EBox*)malloc(sizeof(EBox));

		p1->ivex = i; 
		p1->jvex = j;  

		p1->ilink = G.adjmulist[i].firstedge;
		G.adjmulist[i].firstedge = p1;

		p1->jlink = G.adjmulist[j].firstedge;
		G.adjmulist[j].firstedge = p1;
	}
}


//在G的顶点表adjmulist中获取字符v的下标(数组G.xlist的下标从0开始)
int LocateVex(AMLGraph& G, VerTexType v)
{
	int i = 0;
	for (i = 0; i < G.vexnum && (G.adjmulist[i].data != v); ++i)
	{
		;
	}

	return i;
}


//打印邻接多重表
void printAMLGraph(AMLGraph& G)
{
	int i = 0;
	EBox* pMove = NULL;

	for (i = 0; i < G.vexnum; i++)
	{
		printf("\n第%d个顶点为:%c", i + 1, G.adjmulist[i].data);
		pMove = G.adjmulist[i].firstedge;

		if (pMove)
		{
			printf("\n与第%d个顶点相邻接的每个顶点在图中的位置(下标值)为:", i + 1);
			while (pMove)
			{
				if (pMove->ivex == i)
				{
					printf("%d ", pMove->jvex);
					pMove = pMove->ilink;
				}
				else if (pMove->jvex == i)
				{
					printf("%d ", pMove->ivex);
					pMove = pMove->jlink;
				}
			}
		}
		else
		{
			printf("\n没有与第%d个顶点相邻接的顶点。", i + 1);
		}	
	}
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

输入并读取权值,赋值到 边结点 EBox 结构中的 info 成员即可。

//采用邻接多重表表示法创建无向网
void CreateAMLGraph(AMLGraph& G)
{
	int i = 0;
	int j = 0;
	int k = 0;
	VerTexType v1 = 0;
	VerTexType v2 = 0;
	EBox* p1 = NULL;

	int* w = 0;

	printf("请输入无向网的总顶点数:");
	scanf_s(" %d", &G.vexnum);

	printf("请输入无向网的总边数:");
	scanf_s(" %d", &G.edgenum);

	for (i = 0; i < G.vexnum; ++i)
	{
		printf("请输入第%d个顶点的值:", i + 1);
		scanf_s(" %c", &(G.adjmulist[i].data));
		G.adjmulist[i].firstedge = NULL;  //初始化
	}

	for (k = 0; k < G.edgenum; k++)
	{
		printf("请输入第%d条弧依附的两个顶点(用空格间隔,输入结束后按回车): ", k + 1);
		scanf_s(" %c %c", &v1, sizeof(VerTexType), &v2, sizeof(VerTexType));

		printf("请输入第%d条边的权值 : ", k + 1);
		scanf_s(" %d", w, sizeof(InfoType));  //在EBox中,info由指向int的指针定义 

		i = LocateVex(G, v1);
		j = LocateVex(G, v2);

		p1 = (EBox*)malloc(sizeof(EBox));

		p1->ivex = i; 
		p1->jvex = j;  

		p1->info = w;   //赋值到边结点p1中的info成员

		p1->ilink = G.adjmulist[i].firstedge;
		G.adjmulist[i].firstedge = p1;

		p1->jlink = G.adjmulist[j].firstedge;
		G.adjmulist[j].firstedge = p1;
	}
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值