版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/83008491
图是一种较线性表和树更为复杂的数据结构。在线性表中,数据元素之间只有线性关系,每个数据元素只有一个直接前驱和一个直接后继。在树形结构中,数据元素之间有着明显的层次关系,并且每一层上的数据元素可能与下一层中多个元素相关,但只能与上一层中一个元素相关。而在图形结构中,结点之间的关系可以是任意的,图中任意两个数据元素之间都可能相关。因此,图的应用极为广泛。
可以用两个数组分别存储数据元素(顶点)的信息和数据元素之间的关系(边或弧)的信息。
邻接矩阵:行、列各对应一个顶点,若第i行对应顶点到第j列对应的顶点有弧相连则A[i][j]=1,否则为0.
辅助宏的定义:
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -1
#define UNDERFLOW -2
#define maxn 100
#define INFINITY 32767 //最大值 一定要很大
#define MAX_INFO 50
#define MVNUM 100
typedef int Status;
typedef char VertexType;
typedef char InfoType;
typedef enum {DG,DN,UDG,UDN} GraphKind; //图类型 有向图,无向图, 有向网,无向网
弧的存储结构定义:
typedef struct ArcType {//弧的定义
double adj; //邻接数,0、1或w、无穷大
InfoType *Info; //弧的附加信息
}ArcType;
图的数组表示存储结构定义:
//图的数组表示存储结构定义
typedef struct{
VertexType *vexs; //顶点信息
ArcType **arcs; //邻接矩阵
int vexnum,arcnum; //顶点数 弧数
GraphKind kind; //图的类型标记
}MGraph;
图的创建.
Status CreateGraph(MGraph &G){
//图的创建
//输入图的种类及顶点和边信息构造图G
scanf("%d",&G.kind); //枚举值DG DN UDG UDN 实际输入0 1 2 3
switch(G.kind){
case DG: return CreateDG(G);
case DN: return CreateDN(G);
case UDG:return CreateUDG(G);
case UDN:return CreateUDN(G);
default :return ERROR;
}
}
建立无向网G.
Status CreateUDN(MGraph &G){
//建立无向网G
int IncInfo,i,j,k;
double w;
char s[MAX_INFO];
VertexType v1,v2;
scanf("%d %d %d",&G.vexnum,&G.arcnum,&IncInfo); //IncInfo为0表弧没有附加信息
if(!(G.vexs=(VertexType *)malloc(G.vexnum*sizeof(VertexType))))
exit(OVERFLOW);
if(!(G.arcs=(ArcType **)malloc(G.vexnum*sizeof(ArcType *))))
exit(OVERFLOW);
for(i=0;i<G.vexnum;i++){
if(!(G.arcs[i]=(ArcType *)malloc(G.vexnum*sizeof(ArcType))))
exit(OVERFLOW);
scanf(" %c",&G.vexs[i]);
for(j=0;j<G.vexnum;j++){
G.arcs[i][j].adj=INFINITY; //各弧初始化
G.arcs[i][j].Info=NULL;
}
}
for(k=0;k<G.arcnum;k++){
scanf(" %c %c %lf",&v1,&v2,&w); //输入一边及其权值
i=LocateVex(G,v1);//确定顶点下标
j=LocateVex(G,v2);
G.arcs[i][j].adj=w;
if(IncInfo){
scanf(" %s",s);
int l=strlen(s);
if(!(G.arcs[i][j].Info=(InfoType*)malloc((l+1)*sizeof(InfoType))))
exit(OVERFLOW);
strcpy(G.arcs[i][j].Info,s);
if(!(G.arcs[j][i].Info=(InfoType*)malloc((l+1)*sizeof(InfoType)))) //无向网需要将对称弧的附加信息加入
exit(OVERFLOW);
strcpy(G.arcs[j][i].Info,s);
}
G.arcs[j][i].adj=w; //无向网需要将对称弧的权值加入
}
G.arcnum*=2;
return OK;
}
建立有向网G.
Status CreateUDG(MGraph &G){
//建立有向网G
int i,j,k,IncInfo,l;
double w;
char s[MAX_INFO];
VertexType v1,v2;
scanf("%d %d %d",&G.vexnum,&G.arcnum,&IncInfo);
if(!(G.vexs=(VertexType *)malloc(G.vexnum*sizeof(VertexType))))
exit(OVERFLOW);
if(!(G.arcs=(ArcType **)malloc(G.vexnum*sizeof(ArcType *))))
exit(OVERFLOW);
for(i=0;i<G.vexnum;i++){
if(!(G.arcs[i]=(ArcType *)malloc(G.vexnum*sizeof(ArcType))))
exit(OVERFLOW);
scanf(" %c",&G.vexs[i]);
for(j=0;j<G.vexnum;j++){
G.arcs[i][j].adj=INFINITY;
G.arcs[i][j].Info=NULL;
}
}
for(k=0;k<G.arcnum;k++){
scanf(" %c %c %lf",&v1,&v2,&w);
i=LocateVex(G,v1);
j=LocateVex(G,v2);
G.arcs[i][j].adj=w;
if(IncInfo){
scanf(" %s",s);
l=strlen(s);
if(!(G.arcs[i][j].Info=(InfoType *)malloc((l+1)*sizeof(InfoType)))) //开辟空间存附加信息
exit(OVERFLOW);
strcpy(G.arcs[i][j].Info,s);
}
}
return OK;
}
创建无向图G.
Status CreateDN(MGraph &G){
//创建无向图G
int i,j,k;
VertexType v1,v2;
scanf("%d %d",&G.vexnum,&G.arcnum);
if(!(G.vexs=(VertexType *)malloc(G.vexnum*sizeof(VertexType))))
exit(OVERFLOW);
if(!(G.arcs=(ArcType **)malloc(G.vexnum*sizeof(ArcType *))))
exit(OVERFLOW);
for(i=0;i<G.vexnum;i++){
if(!(G.arcs[i]=(ArcType *)malloc(G.vexnum*sizeof(ArcType))))
exit(OVERFLOW);
scanf(" %c",&G.vexs[i]);
for(j=0;j<G.vexnum;j++){
G.arcs[i][j].adj=INFINITY;
G.arcs[i][j].Info=NULL;
}
}
for(k=0;k<G.arcnum;k++){
scanf(" %c %c",&v1,&v2);
i=LocateVex(G,v1);
j=LocateVex(G,v2);
G.arcs[i][j].adj=1;
G.arcs[j][i].adj=1; //无向图需要加入对称弧
}
G.arcnum*=2;//无向图弧数加倍
return OK;
}
创建有向图G:
Status CreateDG(MGraph &G){
//创建有向图G
int i,j,k;
VertexType v1,v2;
scanf("%d %d",&G.vexnum,&G.arcnum);
if(!(G.vexs=(VertexType *)malloc(G.vexnum*sizeof(VertexType))))
exit(OVERFLOW);
if(!(G.arcs=(ArcType **)malloc(G.vexnum*sizeof(ArcType *)))) //开辟邻接矩阵
exit(OVERFLOW);
for(i=0;i<G.vexnum;i++){
if(!(G.arcs[i]=(ArcType *)malloc(G.vexnum*sizeof(ArcType))))
exit(OVERFLOW);
scanf(" %c",&G.vexs[i]); //输入结点
for(j=0;j<G.vexnum;j++){
G.arcs[i][j].adj=INFINITY;
G.arcs[i][j].Info=NULL;
}
}
for(k=0;k<G.arcnum;k++){
//输入弧
scanf(" %c %c",&v1,&v2);
i=LocateVex(G,v1);
j=LocateVex(G,v2);
G.arcs[i][j].adj=1; //最短路径时要判断大小再赋值
}
return OK;
}
若G中存在顶点v 返回v的位置 否则返回-1.
int LocateVex(MGraph M,VertexType v){
//若G中存在顶点v 返回v的位置 否则返回-1
for(int i=0;i<M.vexnum;i++)
if(M.vexs[i]==v)
return i;
return -1;
}
销毁一个图G.
Status DestroyGraph(MGraph &G){
//销毁一个图G
for(int i=0;i<G.vexnum;i++){
for(int j=0;j<G.vexnum;j++){
if(G.vexs[i]&&G.arcs[i][j].Info) {
free(G.arcs[i][j].Info); //销毁附加信息
G.arcs[i][j].Info=NULL;
}
}
free(G.arcs[i]); //销毁邻接数组每一行
G.arcs[i]=NULL;
}
free(G.arcs);//销毁邻接数组
G.arcs=NULL;
free(G.vexs);
G.vexs=NULL;
G.arcnum=0;
G.vexnum=0;
return OK;
}
向图G中插入一个新的结点v.
Status InsertVex(MGraph &G,VertexType v){
//向图G中插入一个新的结点v
int i,j;
G.vexnum++;
if(!(G.vexs=(VertexType *)realloc(G.vexs,G.vexnum*sizeof(VertexType)))) //结点数组扩充容量
exit(OVERFLOW);
G.vexs[G.vexnum-1]=v; //加入结点
if(!(G.arcs=(ArcType **)realloc(G.arcs,G.vexnum*sizeof(ArcType *))))//邻接矩阵扩充容量
exit(OVERFLOW);
for(i=0;i<G.vexnum-1;i++)
if(!(G.arcs[i]=(ArcType *)realloc(G.arcs[i],G.vexnum*sizeof(ArcType))))
exit(OVERFLOW);
i=G.vexnum-1;
if(!(G.arcs[i]=(ArcType *)malloc(G.vexnum*sizeof(ArcType))))
exit(OVERFLOW);
for(j=0;j<G.vexnum;j++){
//初始化弧
G.arcs[i][j].adj=INFINITY;
G.arcs[i][j].Info=NULL;
G.arcs[j][i]=G.arcs[i][j];
}
return OK;
}
删除图G中顶点v 及其关联的弧..
Status DeleteVex(MGraph &G,VertexType v){
//删除图G中顶点v 及其关联的弧
int j,i=LocateVex(G,v);
for(j=0;j<G.vexnum;j++){
if(G.arcs[i][j].adj!=INFINITY){
G.arcnum--;
if(G.arcs[i][j].Info){ //销毁弧
free(G.arcs[i][j].Info); //销毁附加信息
G.arcs[i][j].Info=NULL;
}
G.arcs[i][j].adj=INFINITY; //修改度
}
if(i!=j&&G.vexs[j]&&G.arcs[j][i].adj!=INFINITY){ //销毁对称弧
G.arcnum--;
if(G.arcs[j][i].Info){
free(G.arcs[j][i].Info);
G.arcs[j][i].Info=NULL;
}
G.arcs[j][i].adj=INFINITY;
}
}
free(G.arcs[i]); //销毁一行邻接矩阵数组
G.arcs[i]=NULL;
G.vexs[i]=NULL; //顶点赋空
return OK;
}
向图G中添加弧v,w 如果是无向的,还应该添加w,v.
Status InsertArc(MGraph &G,VertexType v,VertexType w){
//向图G中添加弧v,w 如果是无向的,还应该添加w,v
int i=LocateVex(G,v),j=LocateVex(G,w);
char s[MAX_INFO];
G.arcnum++;
if(G.kind==DG||G.kind==DN){//是有向图或者无向图
G.arcs[i][j].adj=1;
G.arcs[i][j].Info=NULL;
if(G.kind==DN) {
//添加对称弧
G.arcnum++;
G.arcs[j][i].adj=G.arcs[i][j].adj;
}
}
else if(G.kind==UDG||G.kind==UDN){//是有向网或者无向网
scanf("%lf %s",&G.arcs[i][j].adj,s); //添加度与附加信息
int l=strlen(s);
if(!(G.arcs[i][j].Info=(InfoType*)malloc((l+1)*sizeof(InfoType)))) //为附加信息开辟空间
exit(OVERFLOW);
strcpy(G.arcs[i][j].Info,s);
if(G.kind==UDN){//无向网 加入对称弧
G.arcnum++;
if(!(G.arcs[j][i].Info=(InfoType*)malloc((l+1)*sizeof(InfoType))))
exit(OVERFLOW);
G.arcs[j][i].adj=G.arcs[i][j].adj;
strcpy(G.arcs[j][i].Info,s);
}
}
return OK;
}
删除G中的弧v,w 如果G是无向的 还应该删除 w,v.
Status DeleteArc(MGraph &G,VertexType v,VertexType w){
//删除G中的弧v,w 如果G是无向的 还应该删除 w,v
int i=LocateVex(G,v),j=LocateVex(G,w);
G.arcs[i][j].adj=INFINITY;
G.arcnum--;
if(G.arcs[i][j].Info){ //销毁附加信息
free(G.arcs[i][j].Info);
G.arcs[i][j].Info=NULL;
}
if(G.kind==DN||G.kind==UDN){ //是无向的 销毁对称弧
G.arcnum--;
G.arcs[j][i].adj=INFINITY;
if(G.arcs[j][i].Info){
free(G.arcs[j][i].Info);
G.arcs[j][i].Info=NULL;
}
}
return OK;
}
为G中顶点v 赋值为value.
Status PutVex(MGraph &G,VertexType v,VertexType value){
//为G中顶点v 赋值为value
int i=LocateVex(G,v);
if(i>=0)
G.vexs[i]=value;
return OK;
}
返回G中 v顶点的第一个邻接点 若没有返回空.
int FirstAdjVex(MGraph G,int v){
//返回G中 v顶点的第一个邻接点 若没有返回空
if(v>=0) {//如果找到v顶点
for(int j=0;j<G.vexnum;j++)
if(G.arcs[v][j].adj!=INFINITY)
return j;
}
return -1;
}
返回G中 w是v顶点的一个邻接点 返回v的临界点w后下一个邻接点 若w是最后一个邻接点 返回空.
int NextAdjVex(MGraph &G,int v,int w){
//返回G中 w是v顶点的一个邻接点 返回v的临界点w后下一个邻接点 若w是最后一个邻接点 返回空
int k;
if(v>=0&&w>=0){
for(k=w+1;k<G.vexnum;k++)
if(G.arcs[v][k].adj!=INFINITY)
return k;
}
return -1;
}
输出图G的结点数 弧数 图类型 以及所有顶点和其对应的弧.
void PrintGraph(MGraph G){
//输出图G的结点数 弧数 图类型 以及所有顶点和其对应的弧
int i,j,n=0;
for(i=0;i<G.vexnum;i++)
if(!G.vexs[i]) //去除空节点
n++;
printf("结点个数:%d 弧个数:%d ",G.vexnum-n,G.arcnum);
if(!(G.vexnum-n))
printf("空图\n");
else{
switch(G.kind){
case DG:
printf("有向图\n");
break;
case DN:
printf("无向图\n");
break;
case UDG:
printf("有向网\n");
break;
case UDN:
printf("无向网\n");
break;
}
printf("结点:");
for(i=0;i<G.vexnum;i++)
if(G.vexs[i])
printf("%c ",G.vexs[i]);
printf("\n");
for(i=0;i<G.vexnum;i++){
for(j=0;j<G.vexnum;j++)
if(G.vexs[i]&&G.arcs[i][j].adj!=INFINITY)
printf("%c %c %.2f %s\n",G.vexs[i],G.vexs[j],G.arcs[i][j].adj,G.arcs[i][j].Info);
}
}
}