本文针对图的邻接表存储。
邻接表示图的链式存储方式。有几个顶点就有几个链表,每个链表的后边的节点表示与顶点有关的边。如下图:
左边都是顶点,右边都是边。
在本文程序里没有包含边的附件信息。
程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
typedef int status;
#define MAX_NAME 5 //顶点字符串的最大长度 + 1
typedef char VertexType[MAX_NAME];
#define MAX_VERTEX_NUM 20
typedef enum {DG,DN,UDG,AN} GraphKind; //{有向图,有向网,无向图,无向网}
int visited[MAX_VERTEX_NUM];
void(*VisitFunc)(char* v); /* 函数变量(全局量) */
typedef struct ArcNode //没有相关信息
{
int adjvex; //所指向的顶点的下标
int *info; //网权值
struct ArcNode *nextarc;
}ArcNode; //边结点
typedef struct
{
VertexType data;
ArcNode *firstarc;
}VNode,AdjList[MAX_VERTEX_NUM]; //头结点
typedef struct
{
AdjList vertexs;
int vexnum,arcnum; //图当前顶点数和弧数
int kind;
}Graph; //图
//返回顶点在图中位置
int locate_vertex(Graph *G,VertexType u)
{
int i;
for(i = 0;i < G->vexnum;++i)
if(strcmp(u,G->vertexs[i].data) == 0)
return i;
return -1;
}
//创建图
status CreateGraph(Graph *G)
{
int i,j,k;
int w;
VertexType va,vb;
ArcNode *p;
printf("please input the type of graph(directed graph:0 directed net:1 undirected graph:2 undirected net:3): ");
scanf("%d",&G->kind);
printf("please input the vertex number, edge number: ");
scanf("%d %d",&G->vexnum,&G->arcnum);
printf("please input %d string of vertex value(<%d chars of each string):\n",G->vexnum,MAX_NAME);
for(i = 0;i < G->vexnum;++i){
scanf("%s",G->vertexs[i].data);
G->vertexs[i].firstarc = NULL;
}
if(G->kind == 1 || G->kind == 3) //网
printf("please input tail head power of %d edges in order:\n",G->arcnum);
else //图
printf("please input tail head of %d edges in order:\n",G->arcnum);
for(k = 0;k < G->arcnum;++k){
if(G->kind == 1 || G->kind == 3) //网
scanf("%s %s %d",va,vb,&w);
else //图
scanf("%s %s",va,vb);
i = locate_vertex(G,va);
j = locate_vertex(G,vb);
p = (ArcNode*)malloc(sizeof(ArcNode));
p->adjvex = j;
if(G->kind == 1 || G->kind == 3){
p->info = (int*)malloc(sizeof(int));
*(p->info) = w;
}
else
p->info = NULL;
p->nextarc = G->vertexs[i].firstarc; //往表头插
G->vertexs[i].firstarc = p;
if(G->kind >= 2){ //无向图或网 (vb,va)
p = (ArcNode*)malloc(sizeof(ArcNode));
p->adjvex = i;
if(G->kind == 3){ //无向网
p->info = (int*)malloc(sizeof(int));
*(p->info) = w;
}
else
p->info = NULL; //无向图
p->nextarc = G->vertexs[j].firstarc; /* 插在表头 */
G->vertexs[j].firstarc = p;
}
}
return 1;
}
//销毁图
void DestroyGraph(Graph *G)
{
int i;
ArcNode *p,*q;
G->vexnum = 0;
G->arcnum = 0;
for(i = 0;i < G->vexnum;++i){
p = G->vertexs[i].firstarc;
while(p){
q = p->nextarc;
if(G->kind % 2) //网要释放权值
free(p->info);
free(p);
p = q;
}
}
}
//返回顶点下标v的值
VertexType* GetVex(Graph *G,int v)
{
if(v < 0 || v >= G->vexnum)
exit(0);
return G->vertexs[v].data;
}
//返回顶点值为v的第一个邻接顶点的下标
int first_adjver(Graph *G,VertexType v)
{
ArcNode *p;
int v1;
v1 = locate_vertex(G,v);
p = G->vertexs[v1].firstarc;
if(p)
return p->adjvex;
else
return -1;
}
//返回顶点值为v的(w之后的)下一个邻接顶点的下标
int NextAdjVex(Graph *G,VertexType v,VertexType w)
{
ArcNode *p;
int v1,w1;
v1 = locate_vertex(G,v);
w1 = locate_vertex(G,w);
p = G->vertexs[v1].firstarc;
while(p && p->adjvex != w1)
p = p->nextarc;
if(!p || !p->nextarc)
return -1;
else
return p->nextarc->adjvex;
}
//添加新顶点值为v
void InsertVex(Graph *G,VertexType v)
{
strcpy(G->vertexs[G->vexnum].data,v);
G->vertexs[G->vexnum].firstarc = NULL;
G->vexnum++;
}
//删除G中顶点值为v及其相关的弧
status delete_vertex(Graph *G,VertexType v)
{
int i,j;
ArcNode *p,*q;
j = locate_vertex(G,v);
if(j < 0)
return 0;
p = G->vertexs[j].firstarc;
while(p){ //从前往后删除以顶点值v为出度的弧
q = p;
p = p->nextarc;
if(G->kind % 2) //网
free(q->info);
free(q);
G->arcnum--;
}
G->vexnum--;
for(i = j;i < G->vexnum;i++) //顶点数组之后的向前移
G->vertexs[i] = G->vertexs[i + 1];
for(i = 0;i < G->vexnum;i++){ //删除以顶点值v为入度的弧
p = G->vertexs[i].firstarc; //指向第1条弧或边
while(p){
if(p->adjvex == j){
if(p == G->vertexs[i].firstarc) //待删结点是第1个结点
{
G->vertexs[i].firstarc = p->nextarc;
if(G->kind % 2) //网
free(p->info);
free(p);
p = G->vertexs[i].firstarc;
if(G->kind < 2) //有向,无向的只减一次
G->arcnum--;
}
else{
q->nextarc = p->nextarc;
if(G->kind % 2) //网
free(p->info);
free(p);
p = q->nextarc;
if(G->kind < 2) //有向,无向的只减一次
G->arcnum--;
}
}
else{
if(p->adjvex>j)
p->adjvex--;
q = p;
p = p->nextarc;
}
}
}
return 1;
}
//添加弧<v,w>或(v,w)
status insert_arc(Graph *G,VertexType v,VertexType w)
{
ArcNode *p;
int w1,i,j;
i = locate_vertex(G,v);
j = locate_vertex(G,w);
if(i < 0 || j < 0)
return 0;
G->arcnum++;
p = (ArcNode*)malloc(sizeof(ArcNode));
if(G->kind % 2){ //网
printf("please input the power of the edge: ");
scanf("%d",&w1);
p->info = (int*)malloc(sizeof(int));
*(p->info) = w1;
}
else
p->info=NULL;
p->adjvex = j;
p->nextarc = G->vertexs[i].firstarc; //插在表头
G->vertexs[i].firstarc = p;
if(G->kind >= 2){ //无向图、网
p = (ArcNode*)malloc(sizeof(ArcNode));
if(G->kind == 3){
p->info = (int*)malloc(sizeof(int));
*(p->info) = w1;
}
else
p->info = NULL;
p->adjvex = i;
p->nextarc = G->vertexs[j].firstarc;
G->vertexs[j].firstarc = p;
}
return 1;
}
//删除弧<v,w>或(v,w)
status DeleteArc(Graph *G,VertexType v,VertexType w)
{
ArcNode *p,*q;
int i,j;
i = locate_vertex(G,v);
j = locate_vertex(G,w);
if(i < 0 || j < 0 || i == j)
return 0;
p = G->vertexs[i].firstarc;
while(p && p->adjvex != j){
q = p; //记录前一个边
p = p->nextarc;
}
if(p && p->adjvex == j){ //没有这个边就不做处理
if(p == G->vertexs[i].firstarc)
G->vertexs[i].firstarc = p->nextarc;
else
q->nextarc = p->nextarc;
if(G->kind % 2) //网
free(p->info);
free(p);
G->arcnum--;
}
if(G->kind >= 2){
p = G->vertexs[j].firstarc;
while(p && p->adjvex != i){
q = p;
p = p->nextarc;
}
if(p && p->adjvex == i){
if(p == G->vertexs[j].firstarc)
G->vertexs[j].firstarc = p->nextarc;
else
q->nextarc = p->nextarc;
if((*G).kind==3)
free(p->info);
free(p);
}
}
return 1;
}
//第v个顶点出发递归地深度优先遍历图G。算法7.5 */
void DFS(Graph *G,int v)
{
int w;
VertexType v1,w1;
strcpy(v1,*GetVex(G,v));
visited[v] = 1;
printf("%s",G->vertexs[v].data);
for(w = first_adjver(G,v1);w >= 0;w = NextAdjVex(G,v1,w1)){
if(!visited[w])
DFS(G,w);
strcpy(w1,*GetVex(G,w));
}
}
//深度优先遍历
void DFSTraverse(Graph *G,void(*Visit)(char*))
{
int v;
VisitFunc = Visit;
for(v = 0;v < G->vexnum;v++)
visited[v] = 0;
for(v = 0;v < G->vexnum;v++)
if(!visited[v])
DFS(G,v);
printf("\n");
}
//输出顶点值与邻接矩阵
void Display(Graph *G)
{
int i;
ArcNode *p;
char s[20];
switch(G->kind){
case DG: strcpy(s,"directed graph\0");break;
case DN: strcpy(s,"directed net\0");break;
case UDG: strcpy(s,"undirected graph\0");break;
case AN: strcpy(s,"undirected net\0");
}
printf("the %s has %d vertex and %d edge\n",s,G->vexnum,G->arcnum);
for(i = 0;i < G->vexnum;++i)
printf("%s\n",G->vertexs[i].data);
for(i = 0;i < G->vexnum;i++){
p = G->vertexs[i].firstarc;
while(p){
if(G->kind <= 1){
printf("%s-->%s",G->vertexs[i].data,G->vertexs[p->adjvex].data);
if(G->kind == DN)
printf("\t power is %d",*(p->info));
}
else{
if(i < p->adjvex){
printf("%s--%s",G->vertexs[i].data,G->vertexs[p->adjvex].data);
if(G->kind == AN)
printf("\t power is %d",*(p->info));
}
}
p = p->nextarc;
printf("\t");
}
printf("\n");
}
}
void main()
{
int i,j,k,n;
Graph g;
VertexType v1,v2;
for(i = 0;i < 4;i++){
CreateGraph(&g);
Display(&g);
printf("please input the new vertex value to insert: ");
scanf("%s",v1);
InsertVex(&g,v1);
Display(&g);
printf("insert the edge of the new vertex, so please input the number of the edge: ");
scanf("%d",&n);
for(k = 0;k < n;k++){
printf("please input the next vertext value: ");
scanf("%s",v2);
if(g.kind <= 1){
printf("please input the vertex %s 's type(head:0 tail:1): ",v1);
scanf("%d",&j);
if(j)
insert_arc(&g,v1,v2);
else
insert_arc(&g,v2,v1);
}
else
insert_arc(&g,v1,v2);
}
Display(&g);
printf("please input the vertex value to delete: ");
scanf("%s",v1);
delete_vertex(&g,v1);
Display(&g);
printf("please input the tail head of the edge to delete: ");
scanf("%s %s",v1,v2);
DeleteArc(&g,v1,v2);
Display(&g);
DestroyGraph(&g);
Display(&g);
}
}