#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MAX_VERTEX_NUM 20
//顶点数据类型
typedef int VertexType;
typedef int Status;
typedef enum {unvisited,isvisited}VisitIf;//枚举类型,判断是否被访问 0 代表没有被访问 1 代表访问过了
//图的种类:无向图/网
typedef enum {UDG,UDN}GraphKind;
typedef struct EBox {
VisitIf mark; //访问标记
int ivex; //边顶点一
int jvex; //边顶点二
struct EBox *ilink; //指向依附于顶点一的下一条边,类似于起点相同的一条弧
struct EBox *jlink; //指向依附于顶点二的下一条边,类似与终点想同的一条弧
int weight; //边的权值
}EBox;
typedef struct VexBox {
VertexType data;//数据域
EBox *firstarc; //指向第一条依附于该顶点的边
}VexBox;
typedef struct {
VexBox adjmulist[MAX_VERTEX_NUM];//顶点数组
int vexnum; //图的顶点数
int arcnum; //图的边数
GraphKind kind; //图的种类
}AMLGraph;
//访问标志数组
int visited[MAX_VERTEX_NUM];
//创建图
Status CreateGraph(AMLGraph *G);
//定位一个顶点值为图中的位置,否则返回-1
int LocateVex(AMLGraph G,VertexType v);
//返回顶点的值
VertexType GetVex(AMLGraph G,int v);
//赋值
Status PutVex(AMLGraph *G,VertexType v,VertexType value );
//插入一个顶点
Status InsertVex(AMLGraph *G,VertexType v);
//插入一段弧
Status InsertArc(AMLGraph *G,VertexType v,VertexType w);
//返回顶点值为v的下一个邻接顶点的序号,否怎返回-1
int FirstAdjVex(AMLGraph G,VertexType v);
//返回顶点值为v相对于顶点值为w的下一个顶点的序号
int NextAdjVex(AMLGraph G,VertexType v,VertexType w);
//深度优先遍历
Status DFSTraverse(AMLGraph G);
//递归实现深度遍历邻接点
void DFS(AMLGraph G,int i);
这是"amlgraph.h"的头文件
#include <stdio.h>
#include <stdlib.h>
#include "amlgraph.h"
/*
* @description:创建图(无向图/网)
*/
Status CreateGraph(AMLGraph *G) {
int i,j,k,w;
VertexType va,vb;
EBox *p;
//确定图的种类
printf("please enter the kind of graph:");
//输入0 代表无相图 输入1 代表网 就是有权值 是根据枚举来的
scanf("%d",&(*G).kind);//这是c语言的标记方式 &是取地址符号
//确定图的顶点和边数
printf("please enter vexnum and arcnum:");
//依次输入图中的点点数 vexnum 边数 arcnum 记得用逗号隔开
scanf("%d,%d",&(*G).vexnum,&(*G).arcnum);
//确定图的各个顶点
printf("please enter each value of graph:");
for(i = 0; i < (*G).vexnum ; i++) {
//输入链表中顶点的信息 输入数据
scanf("%d,",&(*G).adjmulist[i].data);
//一开始的时候 将firstarc指向空
(*G).adjmulist[i].firstarc = NULL;
}
//确定各个顶点间关系,即建立边
if((*G).kind == UDG)
//如果是无向图 只要输入头尾结点即可
printf("please enter heads and tails:\n");
else
//如果是网 那么就要输入头结点 尾结点 以及权重
printf("please enter heads,weights and tails\n");
//接下来是具体的输入过程 ,记得中间要用逗号隔开数据
for(k = 0; k < (*G).arcnum ;k++) {
if((*G).kind == UDG)
scanf("%d,%d",&va,&vb);
else
scanf("%d,%d",&va,&vb,&w);
//放回两顶点在顶点向量数组中位置
//将这两个顶点在顶点向量数组中的位置传出来
i = LocateVex(*G,va);
j = LocateVex(*G,vb);
if(i < 0 || j < 0)
return ERROR;
//为变表分配空间
p = (EBox *) malloc(sizeof(struct EBox));
if(!p)
exit(OVERFLOW);
///建立新节点 在边表中将头尾结点的信息填上
p->ivex = i;
p->jvex = j;
p->mark = unvisited;//设置这条边为未访问
//注意每次插入新节点都是在链表的表头进行
//插入的时候采用的都是头插法
//这里是将p->ilink指向原来firstarc指向的位置
//再将firstarc指向这条边
p->ilink = (*G).adjmulist[i].firstarc;
p->jlink = (*G).adjmulist[j].firstarc;
(*G).adjmulist[i].firstarc = p;
(*G).adjmulist[j].firstarc = p;
if((*G).kind == UDN)
//如果是网图还需要输入权值
p->weight = w;
}
return OK;
}
/*
* @description:定位一个顶点值在图中的位置,无则返回-1
*/
//返回该顶点在顶点数组中的下标位置
int LocateVex(AMLGraph G,VertexType v) {
int i;
for(i = 0; i < G.vexnum ; i++)
if(G.adjmulist[i].data == v)
return i;
return -1;
}
/*
* @description:返回顶点v的值
*/
//这里是给定一个位置,返回顶点数组中该位置的信息
VertexType GetVex(AMLGraph G,int v) {
if(v > G.vexnum || v < 0)
exit(ERROR);
return G.adjmulist[v].data;
}
/*
* @description:对顶点值为v的顶点赋值为value
*/
//就是替换顶点的数据域
Status PutVex(AMLGraph *G,VertexType v,VertexType value) {
int i;
//先返回该顶点在顶点的数组中的位置
i = LocateVex(*G,v);
if(i < 0)
return ERROR;
//再讲这个顶点的数据域改为value
(*G).adjmulist[i].data = value;
return OK;
}
/*
* @description:返回顶点值为v的下一个邻接点的序号,否则返回-1
*/
int FirstAdjVex(AMLGraph G,VertexType v) {
int i;
EBox *p;
//先找到这个顶点在顶点数组中的位置
i = LocateVex(G,v);
if(i < 0)
return -1;
//指针p指向这个顶点的第一个邻接边
p = G.adjmulist[i].firstarc;
if(p)
//如果这个边的尾顶点与输入顶点在顶点数中的位置相等
if(p->ivex == i)
return p->jvex; //返回这个边的头结点
//要注意这种情况的理解
else
//这里是出度与入度的关系
return p->ivex;
else
return -1;
}
/*
* @description:返回顶点值为v相对于顶点值为w的下一个邻接顶点的序号
*/
int NextAdjVex(AMLGraph G,VertexType v,VertexType w) {
int i,j;
EBox *p;
//先找到这两个顶点在顶点数组中的位置
i = LocateVex(G,v);
j = LocateVex(G,w);
p = G.adjmulist[i].firstarc; //不管怎样先找到入口
while(p)
//其实这两句话的意思就是 这条边不是以v w位顶点的边
if(p->ivex == i && p->jvex != j ) //情况1 所谓的情况一 就是这条边是以v为起点 但不是以 w为结点的边
p = p->ilink;
else if(p->jvex == i && p->ivex != j) //情况2 就是指:这条边是以v为终点 但起点不是w的边
p = p->jlink;
else
break;
//情况1
if(p && p->ivex == i && p->jvex == j) {
p = p->ilink;
if(p && p->ivex == i)
return p->jvex;
else if(p && p->jvex == i)
return p->ivex;
}
//情况2
if(p && p->ivex == j && p->jvex == i) {
p = p->jlink;
if(p && p->ivex == i)
return p->jvex;
else if(p && p->jvex == i)
return p->ivex;
}
return -1;
}
/*
* @description:插入一个顶点
*/
Status InsertVex(AMLGraph *G,VertexType v) {
int i;
i = (*G).vexnum;//赋予其一个下标值
//在顶点数组中添加一个顶点
(*G).adjmulist[i].data = v;//数据域赋值
(*G).adjmulist[i].firstarc = NULL;//第一条指向空
(*G).vexnum++;//数组数目增加
return OK;
}
/*
* @description:插入一段弧
*/
Status InsertArc(AMLGraph *G,VertexType v,VertexType w) {
int i,j;
EBox *p;
//放回两顶点在顶点向量数组中位置
//首先返回这两个顶点在顶点数组中的位置
i = LocateVex(*G,v);
j = LocateVex(*G,w);
if(i < 0 || j < 0)
return ERROR;
//为边表分配内存
p = (EBox *) malloc(sizeof(struct EBox));
if(!p)
exit(OVERFLOW);
///建立新节点
//这一步操作就类似于在两个顶点之间画上一条线
p->ivex = i;
p->jvex = j;
p->mark = unvisited;
//注意每次插入新节点都是在链表的表头进行
//采用头插法
p->ilink = (*G).adjmulist[i].firstarc;
p->jlink = (*G).adjmulist[j].firstarc;
(*G).adjmulist[i].firstarc = p;
(*G).adjmulist[j].firstarc = p;
if((*G).kind == UDN) {
//如果这是一个网图 还需要如数权值
printf("please enter the weight of the arc:");
scanf("%d",&p->weight);
}
return OK;
}
/*
* @description:深度优先遍历图
*/
Status DFSTraverse(AMLGraph G) {
int i;
for(i = 0;i < G.vexnum ; i++)
visited[i] = FALSE;//先初始化访问结点 将其都设置位false 然后逐个访问
//循环是为保证每个顶点都能被访问到
for(i = 0; i < G.vexnum; i++)
if(!visited[i])
DFS(G,i);//采用递归的方法
}
/*
* @description:递归实现深度优先遍历
*/
void DFS(AMLGraph G,int i) {
int j;
EBox *p;
printf("%d",G.adjmulist[i].data);
visited[i] = TRUE;
p = G.adjmulist[i].firstarc;
while(p) {
//如果这条边是以i为尾结点 那么讲头结点赋值给j,否则就将这条边的头结点赋值给j
j = p->ivex == i ? p->jvex : p->ivex;
if(!visited[j])
DFS(G,j);//最后采用递归遍历
p = p->ivex == i ? p->ilink : p->jlink ;//然后遍历与顶点相同顶点的边 一层一层的访问
}
}
AMLGraph.c
#include<stdio.h>
#include<stdlib.h>
#include"amlgraph.h"
void main(){
AMLGraph G;
CreateGraph(&G);
DFSTraverse(G);
printf("\n");
这是test.c
下面是测试的结果
please enter the kind of graph:0
please enter vexnum and arcnum:8,8
please enter each value of graph:1,2,3,4,5,6,7,8
please enter heads and tails:
1,2
1,3
2,4
2,5
3,6
3,7
4,8
5,8
13762584