图的邻接表存储
代码如下:
//图的邻接表存储结构
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#define MAX_VERTEX_NUM 20 //最大顶点个数
#define MAX_NAME 3 //顶点字符串最大长度+1
#define ERROR 0
#define OK 1
typedef int ElemType;
typedef int Status;
typedef enum{DG,DN,AG,AN}GraphKind; //图的种类:有向图、有向网、无向图、无向网
typedef int InfoType;
typedef char VertexType[MAX_NAME];
//队列结构
typedef struct node
{
ElemType data;
struct node *next;
}QueueNode;
typedef struct
{
QueueNode *front;
QueueNode *rear;
}LinkQueue;
typedef struct ArcNode
{
int adjvex; //邻接点域,该弧所指向的顶点的位置
InfoType *info; //网的权值指针
struct ArcNode *nextarc; //指向下一条弧的指针
}ArcNode; //表结点
typedef struct
{
VertexType data; //顶点信息
ArcNode *firstarc; //第一个表结点的地址,指向第一条依附该顶点的弧
}VNode; //顶点
typedef struct
{
VNode vertices[MAX_VERTEX_NUM];
int vexnum,arcnum; //顶点数和弧度
int kind; //种类标志
}ALGraph;
//求顶点位置
int LocateVex(ALGraph G,VertexType u)
{
int i;
for(i=0;i<G.vexnum;i++)
{
if(strcmp(u,G.vertices[i].data)==0)
return i;
}
return -1;
}
//求顶点信息
VertexType *GetVex(ALGraph G,int v)
{
if(v>=G.vexnum||v<0)
return 0;
return &G.vertices[v].data;
}
//对顶点赋新值
Status PutVex(ALGraph *G,VertexType v,VertexType value)
{
int i;
i=LocateVex(*G,v);
if(i>-1)
{
strcpy((*G).vertices[i].data,value);
return OK;
}
return ERROR;
}
//求顶点的第一个邻接顶点的序号
int FirstAdjVex(ALGraph G,VertexType v)
{
ArcNode *p;
int i;
i=LocateVex(G,v);
p=G.vertices[i].firstarc;
if(p)
{
return p->adjvex;
printf("该顶点的第一个邻接顶点的序号为%d\n",p->adjvex);
}
else
return -1;
}
//求顶点v相对于某顶点w的下一个邻接顶点序号的算法
int NextAdjVex(ALGraph G,VertexType v,VertexType w)
{
ArcNode *p;
int v1,w1;
v1=LocateVex(G,v);
w1=LocateVex(G,w);
p=G.vertices[v1].firstarc;
while(p&&p->adjvex!=w1)
p=p->nextarc;
if(!p||!p->nextarc)
return -1;
else
{
return p->nextarc->adjvex;
printf("顶点%s相对于顶点%s的下一个邻接顶点序号为:%s\n",v,w,p->nextarc->adjvex);
}
}
//插入新顶点
void InsertVex(ALGraph *G,VertexType v)
{
strcpy((*G).vertices[(*G).vexnum].data,v);
(*G).vertices[(*G).vexnum].firstarc=NULL;
(*G).vexnum++;
}
//删除顶点
Status DeleteVex(ALGraph *G,VertexType v)
{
int i,j;
ArcNode *p,*q;
j=LocateVex(*G,v);
if(j<0)
return ERROR;
p=(*G).vertices[j].firstarc;
while(p)
{
q=p;
p=p->nextarc;
if((*G).kind%2)
free(q->info);
free(q);
}
(*G).vexnum--;
for(i=j;i<(*G).vexnum;i++)
{
p=(*G).vertices[i].firstarc;
while(p)
{
if(p->adjvex==j)
{
if(p==(*G).vertices[i].firstarc)
{
(*G).vertices[i].firstarc=p->nextarc;
if((*G).kind%2)
free(p->info);
free(p);
p=(*G).vertices[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 OK;
}
//插入新弧
Status InsertArc(ALGraph *G,VertexType v,VertexType w)
{
ArcNode *p;
int w1,i,j;
i=LocateVex(*G,v);
j=LocateVex(*G,v);
if(i<0||j<0)
return ERROR;
(*G).arcnum++;
if((*G).kind%2)
{
printf("请输入弧(边)%s -> %s的权值",v,w);
scanf("%d",&w1);
}
p=(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex=j;
if((*G).kind%2)
{
p->info=(int *)malloc(sizeof(int));
*(p->info)=w1;
}
else
p->info=NULL;
p->nextarc=(*G).vertices[i].firstarc;
(*G).vertices[i].firstarc=p;
if((*G).kind>2)
{
p=(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex=i;
if((*G).kind==3)
{
p->info=(int*)malloc(sizeof(int));
*(p->info)=w1;
}
else
p->info=NULL;
p->nextarc=(*G).vertices[j].firstarc;
(*G).vertices[j].firstarc=p;
}
return OK;
}
//删除弧
Status DeleteArc(ALGraph *G,VertexType v,VertexType w)
{
ArcNode *p,*q;
int i,j;
i=LocateVex(*G,v);
j=LocateVex(*G,w);
if(i<0||j<0||i==j)
return ERROR;
p=(*G).vertices[i].firstarc;
while(p&&p->adjvex!=j)
{
q=p;
p=p->nextarc;
}
if(p&&p->adjvex==j)
{
if(p==(*G).vertices[i].firstarc)
(*G).vertices[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).vertices[j].firstarc;
while(p&&p->adjvex!=i)
{
q=p;
p=p->nextarc;
}
if(p&&p->adjvex==i)
{
if(p==(*G).vertices[i].firstarc)
(*G).vertices[i].firstarc=p->nextarc;
else
q->nextarc=p->nextarc;
if((*G).kind==3)
free(p->info);
free(p);
}
}
return OK;
}
//图的销毁
void DestoryGraph(ALGraph *G)
{
int i;
ArcNode *p,*q;
(*G).vexnum=0;
(*G).arcnum=0;
for(i=0;i<(*G).vexnum;++i)
{
p=(*G).vertices[i].firstarc;
(*G).vertices[i].firstarc=NULL;
while(p)
{
q=p->nextarc;
if((*G).kind%2)
free(p->info);
free(p);
p=q;
}
}
}
//图的创建
Status CreateGraph(ALGraph *G)
{
int i,j,k;
int w;
VertexType va,vb;
ArcNode *p;
printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3):");
scanf("%d",&(*G).kind);
printf("请输入图的顶点数、边数:");
scanf("%d %d",&(*G).vexnum,&(*G).arcnum);
printf("请输入%d个顶点的值(<%d个字符):",(*G).vexnum,MAX_NAME);
for(i=0;i<(*G).vexnum;++i)
{
scanf("%s",(*G).vertices[i].data);
(*G).vertices[i].firstarc=NULL;
}
if((*G).kind==1||(*G).kind==3)
printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n");
else
printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\n");
for(k=0;k<(*G).arcnum;++k)
{
printf("请输入第%d条边",k+1);
if((*G).kind==1||(*G).kind==3)
scanf("%d %s %s",&w,va,vb);
else
scanf("%s %s",va,vb);
i=LocateVex(*G,va);
j=LocateVex(*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).vertices[i].firstarc;
(*G).vertices[i].firstarc=p;
if((*G).kind>=2)
{
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).vertices[j].firstarc;
(*G).vertices[j].firstarc=p;
}
}
printf("图已创建完毕!");
return OK;
}
Status wenjian(ALGraph *G)
{
FILE *fp;
int i,j,k;
int w;
VertexType va,vb;
ArcNode *p;
if((fp=fopen("algraph.txt","r"))==NULL) //打开文件
{
printf("文件打开失败!\n");
}
else
printf("文件打开成功!\n");
fscanf(fp,"%d",&(*G).kind);
fscanf(fp,"%d,%d",&(*G).vexnum,&(*G).arcnum);
for(i=0;i<(*G).vexnum;++i)
{
fscanf(fp,"%s",(*G).vertices[i].data);
(*G).vertices[i].firstarc=NULL;
}
for(k=0;k<(*G).arcnum;++k)
{
if((*G).kind==1||(*G).kind==3)
fscanf(fp,"%d%s%s",&w,va,vb);
else
fscanf(fp,"%s%s",va,vb);
i=LocateVex(*G,va);
j=LocateVex(*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).vertices[i].firstarc;
(*G).vertices[i].firstarc=p;
if((*G).kind>=2)
{
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).vertices[j].firstarc;
(*G).vertices[j].firstarc=p;
}
}
fclose(fp); //关闭文件
printf("图已创建完毕!");
return OK;
}
//图的打印输出
void Display(ALGraph G)
{
int i;
ArcNode *p;
switch(G.kind)
{
case DG:printf("有向图\n");
break;
case DN:printf("有向网\n");
break;
case AG:printf("无向图\n");
break;
case AN:printf("无向网\n");
}
printf("%d个顶点:\n",G.vexnum);
for(i=0;i<G.vexnum;++i)
{
printf("%s ",G.vertices[i].data);
}
printf("\n%d条弧(边):\n",G.arcnum);
for(i=0;i<G.arcnum;i++)
{
p=G.vertices[i].firstarc;
while(p)
{
if(G.kind<=1)
{
printf("%s -> %s",G.vertices[i].data,G.vertices[p->adjvex].data);
if(G.kind==DN)
printf(":%d ",*(p->info));
}
else
{
if(i<p->adjvex)
{
printf("%s -> %s",G.vertices[i].data,G.vertices[p->adjvex].data);
if(G.kind==AN)
printf(":%d ",*(p->info));
}
}
p=p->nextarc;
}
printf("\n");
}
}
int InitQueue(LinkQueue *Q) //链队列的初始化操作
{
Q->front=(QueueNode *)malloc(sizeof(QueueNode));
Q->front->next=NULL;
Q->rear=Q->front;
return OK;
}
int EnQueue(LinkQueue *Q,ElemType e) //链队列的入操作
{
QueueNode *p;
p=(QueueNode *)malloc(sizeof(QueueNode));
p->data=e;
p->next=NULL;
Q->rear->next=p;
Q->rear=p;
return OK;
}
int DeQueue(LinkQueue *Q,ElemType *e) //链队列的出队操作
{
QueueNode *p;
if(Q->front==Q->rear)
return ERROR;
p=Q->front->next;
*e=p->data;
Q->front->next=p->next;
if(Q->rear==p)
Q->rear=Q->front;
free(p);
return OK;
}
int QueueEmpty(LinkQueue Q)
{
if(Q.front==Q.rear)
return 0;
else
return 1;
}
//邻接表存储结构上的深度优先遍历非递归算法
void DFSTraverse(ALGraph G,VertexType v0)
{
int visited[MAX_VERTEX_NUM]={0};
int S[MAX_VERTEX_NUM];
int top=-1;
int v,w;
VertexType *Vt1;
for(v=0;v<G.vexnum;v++)
visited[v]=0;
v=LocateVex(G,v0);
S[++top]=v;
visited[v]=1;
printf("%s ",G.vertices[v].data);
while(top!=-1)
{
v=S[top];
Vt1=GetVex(G,v);
w=FirstAdjVex(G,*Vt1); //求v的第一个邻接点
while(w!=-1)
{
if(!visited[w])
{
S[++top]=w;
visited[w]=1;
printf("%s ",G.vertices[w].data);
break;
}
w=NextAdjVex(G,G.vertices[v].data,G.vertices[w].data);
}
if(w==-1 && top>-1)
top--;
}
printf("\n");
}
//邻接表存储结构上的广度优先遍历算法
void BFSTraverse(ALGraph G)
{
int v,u,w;
VertexType u1,w1;
LinkQueue Q;
int visited[MAX_VERTEX_NUM];
for(v=0;v<G.vexnum;++v)
visited[v]=-1;
InitQueue(&Q);
for(v=0;v<G.vexnum;v++)
if(visited[v]==-1)
{
visited[v]=1;
printf("%s ",G.vertices[v].data);
EnQueue(&Q,v);
while(!QueueEmpty(Q))
{
DeQueue(&Q,&u);
strcpy(u1,*GetVex(G,u));
w=FirstAdjVex(G,u1);
for(;w>=0;w=NextAdjVex(G,u1,strcpy(w1,*GetVex(G,w))))
if(visited[w]==-1)
{
visited[w]=1;
printf("%s ",G.vertices[w].data);
EnQueue(&Q,w);
}
}
}
printf("\n");
}
int menu()
{
int i;
printf("\n||-----------------------------图的邻接表存储--------------------------------||\n");
printf("|| 请选择操作: ||\n");
printf("|| 1.求顶点位置 ||\n");
printf("|| 2.求顶点信息 ||\n");
printf("|| 3.对顶点赋新值 ||\n");
printf("|| 4.求顶点的第一个邻接顶点序号 ||\n");
printf("|| 5.求顶点相对于某顶点的下一个邻接顶点序号 ||\n");
printf("|| 6.插入新顶点 ||\n");
printf("|| 7.删除顶点 ||\n");
printf("|| 8.插入新弧 ||\n");
printf("|| 9.删除弧 ||\n");
printf("|| 10.销毁图 ||\n");
printf("|| 11.图的打印与输出 ||\n");
printf("|| 12.图的广度优先遍历 ||\n");
printf("|| 13.图的深度优先遍历 ||\n");
printf("||---------------------------------------------------------------------------||\n");
scanf("%d",&i);
return i;
}
int main()
{
int select,i,d;
char c[3],e[3],v[3]="v1";
ALGraph myG;
printf("请选择构图方式 1.手动输入;2.文件读入\n");
scanf("%d",&select);
if(select==1)
{
CreateGraph(&myG);
}
else
{
wenjian(&myG);
}
while(i)
{
i=menu();
switch(i)
{
case 1:
printf("请输入所求顶点:");
scanf("%s",c);
d=LocateVex(myG,c);
printf("该顶点为%d\n",d);
break;
case 2:
printf("请输入所求序号:");
scanf("%d",&d);
GetVex(myG,d);
break;
case 3:
printf("请输入顶点和所赋新值:");
scanf("%s %s",e,c);
PutVex(&myG,e,c);
printf("赋值成功\n");
break;
case 4:
printf("请输入顶点:");
scanf("%s",e);
FirstAdjVex(myG,e);
break;
case 5:
printf("请输入顶点、相对顶点:");
scanf("%s %s",e,c);
NextAdjVex(myG,e,c);
break;
case 6:
printf("请输入新顶点值:");
scanf("%s",e);
InsertVex(&myG,e);
printf("插入成功!\n");
break;
case 7:
printf("请输入要删除的顶点:");
scanf("%s",e);
DeleteVex(&myG,e);
printf("删除成功!\n");
break;
case 8:
printf("请输入要插入新弧的弧尾、弧头:");
scanf("%s %s",e,c);
InsertArc(&myG,e,c);
printf("插入成功!\n");
break;
case 9:
printf("请输入要删除弧的弧尾、弧头:");
scanf("%s %s",e,c);
DeleteArc(&myG,e,c);
printf("删除成功!\n");
break;
case 10:
printf("该图已销毁!\n");
break;
case 11:
Display(myG);
printf("打印已完成!\n");
break;
case 12:
printf("邻接表存储结构上的广度优先遍历:\n");
BFSTraverse(myG);
break;
case 13:
printf("邻接表存储结构上的深度优先遍历非递归:\n");
DFSTraverse(myG,v);
}
}
return 0;
}