- 查找函数(LocateVex查找坐标)
- 构建有向图(Directed Graph)
- 构建无向图(Undirected Graph)
- 图的类型选择函数(GraphChoice)
- 输出邻接矩阵(print)
邻接表结构解析:
- 邻接表由 顶点表 和 边表 组成,顶点表是结构体数组,边表是一环一环的链节。
- 顶点表是结构体数组,其中的每个元素有两个域:数据域(用于存放顶点元素如V1、V2、V3或A、B、C之类的)。指针域,用于连接边表。
- 边表是结构体,其中每个结点也有两个域:下标域,存储的是对应元素在顶点表中的下标。指针域,用于连接后续结点
- 如何定义边表、单个顶点、顶点表?
注:此代码为有向图/无向图,若需存储有向网与无向网,需要在顶点结构体中加入权值w
typedef struct ArcNode
{
int adjvex;
struct ArcNode *next;
}ArcNode;
typedef struct VNode
{
VertexType vertex;
struct ArcNode *firstarc;
}VNode;
typedef struct
{
VNode AdjList[VertexMax];
int vexnum,arcnum;
int kind;
}ALGraph;
- 邻接表用顶点表和边表所表示的含义是:从当前顶点(V1)出发对应有那些其他顶点(V4)与当前顶点有边,就记录在边表中,记录的内容是顶点的下标(记录V4的坐标3),若后续还有顶点(V2)与当前顶点有边,则连接到下去(V2链接到V4后面)
构建邻接表的基本步骤:
- 输入顶点数n,和边数e
- 给顶点表数据域填值(将顶点写入顶点表数据域),并初始化顶点表指针域
- 输入边的信息,构造邻接表
3.1 输入边信息,查找两顶点下标
3.2 根据输入的边的信息用头插法插入结点(尾插法也行)
邻接表的空间复杂度及局限性:
- 邻接表的空间复杂度为O(n+e),其中n是顶点数,e是边数。
- 邻接表空间利用率低,适用于存储稀疏图
邻接表、逆邻接表、十字链表
- 对于有向图而言,邻接表是将当前顶点走向其他顶点的路径信息存储在边表当中,既将出度信息存储于边表,所以求出度十分容易,出度就是边表中的链节个数,但是邻接表却难求出度。逆邻接表将入度信息存储于边表,所以容易求入度,但逆邻接表却难求出度。所以在我们如果需要频繁的求出度与入度的时候,就会引用——十字链表。十字链表是将邻接表与逆邻接表合二为一,易求出度也易求入度。总结如下:
- 邻接表:易求出度,不易求入度
- 逆邻接表:易求入度,不易求出度
- 十字链表:合二为一,易求出度也易求入度
完整源代码
#include <stdio.h>
#include <stdlib.h>
#define VertexType char
#define VertexMax 20
typedef struct ArcNode
{
int adjvex;
struct ArcNode *next;
}ArcNode;
typedef struct VNode
{
VertexType vertex;
struct ArcNode *firstarc;
}VNode;
typedef struct
{
VNode AdjList[VertexMax];
int vexnum,arcnum;
int kind;
}ALGraph;
int LocateVex(ALGraph *G,VertexType v)
{
int i;
for(i=0;i<G->vexnum;i++)
{
if(v==G->AdjList[i].vertex)
{
return i;
}
}
printf("No Such Vertex!\n");
return -1;
}
void CreateDG(ALGraph *G)
{
int i,j;
printf("输入顶点个数和边数:\n");
printf("顶点数 n=");
scanf("%d",&G->vexnum);
printf("边 数 e=");
scanf("%d",&G->arcnum);
printf("\n");
printf("\n");
printf("输入顶点元素(用空格隔开):");
for(i=0;i<G->vexnum;i++)
{
scanf(" %c",&G->AdjList[i].vertex);
G->AdjList[i].firstarc=NULL;
}
printf("\n");
int n,m;
VertexType v1,v2;
ArcNode *p1,*p2;
printf("请输入边的信息:\n\n");
for(i=0;i<G->arcnum;i++)
{
printf("输入第%d条边信息:",i+1);
scanf(" %c%c",&v1,&v2);
n=LocateVex(G,v1);
m=LocateVex(G,v2);
if(n==-1||m==-1)
{
printf("NO This Vertex!\n");
return;
}
p1=(ArcNode *)malloc(sizeof(ArcNode));
p1->adjvex=m;
p1->next=G->AdjList[n].firstarc;
G->AdjList[n].firstarc=p1;
}
G->kind=1;
}
void CreateUDG(ALGraph *G)
{
int i,j;
printf("输入顶点个数和边数:\n");
printf("顶点数 n=");
scanf("%d",&G->vexnum);
printf("边 数 e=");
scanf("%d",&G->arcnum);
printf("\n");
printf("\n");
printf("输入顶点元素(无需空格隔开):");
for(i=0;i<G->vexnum;i++)
{
scanf(" %c",&G->AdjList[i].vertex);
G->AdjList[i].firstarc=NULL;
}
printf("\n");
int n,m;
VertexType v1,v2;
ArcNode *p1,*p2;
printf("请输入边的信息:\n\n");
for(i=0;i<G->arcnum;i++)
{
printf("输入第%d条边信息:",i+1);
scanf(" %c%c",&v1,&v2);
n=LocateVex(G,v1);
m=LocateVex(G,v2);
if(n==-1||m==-1)
{
printf("NO This Vertex!\n");
return;
}
p1=(ArcNode *)malloc(sizeof(ArcNode));
p1->adjvex=m;
p1->next=G->AdjList[n].firstarc;
G->AdjList[n].firstarc=p1;
p2=(ArcNode *)malloc(sizeof(ArcNode));
p2->adjvex=n;
p2->next=G->AdjList[m].firstarc;
G->AdjList[m].firstarc=p2;
}
G->kind=2;
}
void print(ALGraph G)
{
int i;
ArcNode *p;
printf("\n-------------------------------");
printf("\n图的邻接表表示:\n");
for(i=0;i<G.vexnum;i++)
{
printf("\n AdjList[%d]%4c",i,G.AdjList[i].vertex);
p=G.AdjList[i].firstarc;
while(p!=NULL)
{
printf("-->%d",p->adjvex);
p=p->next;
}
}
printf("\n");
}
void GraphChoice(ALGraph *G)
{
int target;
printf(" 请选择图的类型:1.有向图DG 2.无向图UDG\n\n");
scanf("%d",&target);
printf("\n");
switch (target)
{
case 1:
printf("您选择的是 1.DG\n\n");
printf("-------------------------------\n");
CreateDG(G);
break;
case 2:
printf("您选择的是 2.UDG\n\n");
printf("-------------------------------\n");
CreateUDG(G);
break;
default:
printf("无效选择!!!请重新选择!\n\n");
printf("-------------------------------\n");
GraphChoice(G);
break;
}
}
int main()
{
ALGraph G;
GraphChoice(&G);
print(G);
return 0;
}
执行结果:
1.DG
2.UDG