图的存储结构(1):数组表示法

引言:图是一种较线性表和树更为复杂的数据结构。在线性表中,数据元素之间仅有线性关系,每个数据元素只有一个直接前驱和一个直接后继;在树形结构中,数据元素之间有明显的层次关系,每一层的数据元素只能与下一层的多个元素相关,但只能和上一层中的一个元素相关;而在图形结构中,结点之间的关系可以是任意的,图中任意两个数据元素之间都有可能相关。因此这对于刚掌握c语言的学生来说掌握图这种数据结构,并且可以用完整的代码实现还是有一定困难的!特别是数据结构(严蔚敏版)!但是随着时间的推移,越发觉得严蔚敏老师写的程序实在是精妙!以下程序是根据数据结构上严蔚敏老师算法片段而写的完整的数组表示法!

例子:



数组表示法的特点:
1、用二维数组存储有n个顶点的图时,需要存放n个顶点信息和n^2个弧的信息。若图是无向图,根据无向图的邻接矩阵的对称性,则可采用压缩存储的方式只存入矩阵的下三角或上三角元素。
2、根据邻接矩阵容易判定任意两个顶点之间是有边(或弧)相连,并且容易求得各个顶点的度。
3、对于无向图,顶点vi的度是邻接矩阵中第i行(或第i列)的元素之和。
4、对于有向图,顶点vi的出度是邻接矩阵中第i行的元素之和。

#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include<string.h>
#define INFINITY 0                          //两个顶点之间无边或弧时的数值
#define MAX_VERTEX_NUM 26                   //最大顶点个数
#define MAX_INFO    10                      //弧相关信息的字符串的最大长度
#define TRUE  1
#define FALSE 0
#define ERROR 0
#define OK    1
typedef int Status;
typedef int VRType;                        //顶点关系类型
typedef char InfoType;
typedef char VertexType[MAX_VERTEX_NUM];   //顶点类型    
enum GraphKind{DG,DN,UDG,UDN};

//有向图,有向网,无向图,无线网
typedef struct
{
	VRType adj;                        // VRType是顶点关系类型,对无权图,用1或0
	                                   //表示相邻否,对带权图,则为权值类型
        InfoType *info;                    //  该弧相关信息的指针
}ArcCell, AdjMartix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct
{ 
	VertexType vexs[MAX_VERTEX_NUM];   //顶点向量
	AdjMartix arcs;                    //邻接矩阵
        int vexnum,arcnum;                 //图的当前顶点个数和弧数
	GraphKind kind;                    //图的种类标志
}MGraph;
int LocateVex(MGraph G,VertexType u)       //若图中存在顶点u,则返回该顶点在图中的位置;否则返回其他信息
{
    for(int i = 0; i < G.vexnum; ++i)
	    if(strcmp(u,G.vexs[i]) == 0)
		    return i;
	   return -1;
}
Status CreateDG(MGraph &G)                 //采用数组(邻接矩阵)表示法,构造有向图
{
	int i,j,k,l,IncInfo;
	char a[MAX_INFO];
	VertexType va,vb;
	cout << "**********************************有向图*************************************" << endl;
	cout << "请输入有向图的顶点数,边数,以及边是否含有其它信息(是:1,否:0):" << endl;
	cout << "请输入顶点数: ";
	cin >> G.vexnum;
	cout << "请输入弧数: " << endl;
	cin >> G.arcnum ;
	cout << "请输入边是否含有其它信息(是:1,否:0): " << endl;
	cin >> IncInfo;
	cout << "开始构造有向图:\n" << "逐一输入顶点向量" << endl;
	for(i = 0;i < G.vexnum;++i)
	{
		cout << "请输入第"<<i+1<<"个顶点的向量: "<<endl;
		cin >> G.vexs[i] ;
		
	}
	for(i = 0; i < G.vexnum; ++i)                                                           //初始化邻接矩阵
		for(j = 0; j < G.vexnum; ++j)
		{
			G.arcs[i][j].adj = INFINITY;                                            //有向图
			G.arcs[i][j].info = NULL;
		}
		cout << "请输入"  << G.arcnum << "条弧的弧头和弧尾" << endl;
		for(k = 0; k < G.arcnum; ++k)
		{       
			cout << "请输入第" << k + 1 << "条弧的弧尾:" << endl;
			cin >> va ;
			cout << "请输入第" << k + 1 << "条弧的弧头:" << endl;
			cin >> vb;
			i = LocateVex(G,va);
			j = LocateVex(G,vb);
			G.arcs[i][j].adj = 1;          //有向图
			if(IncInfo)
			{
				cout << "请输入该边的相关信息(" << MAX_INFO  << "个字符)";
				cin >> a;
				l = strlen(a);
				if(l)
				{
					G.arcs[i][j].info = (char *)malloc( (l+1)*sizeof(char) ); //有向图
					strcpy(G.arcs[i][j].info,a);
				}
			}
		}
		G.kind = DG;
		return OK;
}
Status CreateDN(MGraph &G)                                                                        //采用数组(邻接矩阵),构造有向网
{
	int i, j, k, w, IncInfo;
	char a[MAX_INFO];
	VertexType va,vb;
	cout << "**********************************有向网*************************************" << endl;
	cout << "请输入有向网的顶点数,弧数、权值以及边是否含有其它信息(是:1,否:0):" << endl;
	cout << "请输入顶点数: ";
	cin >> G.vexnum;
	cout << "请输入弧数: " << endl;
	cin >> G.arcnum ;
	cout << "请输入边是否含有其它信息(是:1,否:0): " << endl;
	cin >> IncInfo;
	cout << "开始构造有向网: \n" << "逐一输入顶点向量" << endl;
	for(i = 0;i < G.vexnum;++i)
	{
		cout << "请输入第"<<i+1<<"个顶点的向量: "<<endl;
		cin >> G.vexs[i] ;
		
	}
	for(i = 0; i < G.vexnum; ++i)                                                              //初始化邻接矩阵
		for(j = 0; j < G.vexnum; ++j)
		{
			G.arcs[i][j].adj = INFINITY;                                               //有线网
			G.arcs[i][j].info = NULL;
		}
		cout << "请输入"  << G.arcnum << "条弧的弧尾、弧头和权值" << endl;
		for(k = 0; k < G.arcnum; ++k)
		{
			
			cout << "请输入第" << k + 1 << "条弧的弧尾:" << endl;
			cin >> va ;
			cout << "请输入第" << k + 1 << "条弧的弧头:" << endl;
			cin >> vb;
			cout << "请输入该弧的权值: " << endl;
			cin >> w;
			i = LocateVex(G,va);
			j = LocateVex(G,vb);
			G.arcs[i][j].adj = w;                                                      //有向网
			if(IncInfo)
			{
				cout << "请输入该边的相关信息(" << MAX_INFO  << "个字符)";
				cin >> a;
				w = strlen(a);
				if(w)
				{
					G.arcs[i][j].info = (char *)malloc((w+1)*sizeof(char));    //有向网
					strcpy(G.arcs[i][j].info,a);
				}
			}
		}
		G.kind = DN;
		return OK;
}

Status CreateUDG(MGraph &G)                                                                        //用数组(邻接矩阵)表示法,构造无向图
{
   int i,j,k,l,IncInfo;
   char a[MAX_INFO];
   VertexType va,vb;
   cout << "**********************************无向图*************************************" << endl;
   cout << "请输入无向图的顶点数,边数,以及边是否含有其它信息(是:1,否:0):" << endl;
   cout << "请输入顶点数: ";
   cin >> G.vexnum;
   cout << "请输入边数: " << endl;
   cin >> G.arcnum ;
   cout << "请输入边是否含有其它信息(是:1,否:0): " << endl;
   cin >> IncInfo;
   cout << "开始构造无向图: \n" << "逐一输入顶点向量……" << endl;
   for(i = 0;i < G.vexnum;++i)
   {
      cout << "请输入第"<<i+1<<"个顶点的向量: "<<endl;
      cin >> G.vexs[i] ;
   
   }
   for(i = 0; i < G.vexnum; ++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)
	{
		
		cout << "请输入第" << k + 1 << "条边的第一个顶点:" << endl;
		cin >> va ;
		cout << "请输入第" << k + 1 << "条边的第二个顶点:" << endl;
			cin >> vb;
		i = LocateVex(G,va);
		j = LocateVex(G,vb);
		G.arcs[i][j].adj = G.arcs[j][i].adj = 1;                                           // 无向图
		if(IncInfo)
		{
                  cout << "请输入该边的相关信息(" << MAX_INFO  << "个字符)";
		  cin >> a;
		  l = strlen(a);
		  if (l)
		  {
			  G.arcs[i][j].info = G.arcs[j][i].info = (char *)malloc( (l + 1)*sizeof(char) );  //给相关信息分配内存空间
			  strcpy(G.arcs[i][j].info,a);
		  }                                                                                        //无向图,两个指针指向同一个信息
		}
	}
	G.kind = UDG;
	return OK;
}
Status CreateUDN(MGraph &G)                                                                                //采用数组(邻接矩阵)表示法,构造无向网
{
    int i,j,k,w,IncInfo;
    char a[MAX_INFO];
    VertexType va,vb;
    cout << "**********************************无向网*************************************" << endl;
    cout << "请输入无向网的顶点数、边数和权值,以及边是否含有其它信息(是:1,否:0):" << endl;
    cout << "请输入顶点数: ";
    cin >> G.vexnum;
    cout << "请输入边数: " << endl;
    cin >> G.arcnum ;
    cout << "请输入边是否含有其它信息(是:1,否:0): " << endl;
     cin >> IncInfo;
    cout << "开始构造无向网: \n" << "逐一输入顶点向量" << endl;
   
    for(i = 0;i < G.vexnum;++i)
    {
	    cout << "请输入第"<<i+1<<"个顶点的向量: "<<endl;
	    cin >> G.vexs[i] ;
	    
    }
    for(i = 0; i < G.vexnum; ++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)
    {
	    cout << "请输入第" << k + 1 << "条边的第一个顶点:" << endl;
	    cin >> va ;
	    cout << "请输入第" << k + 1 << "条边的第二个顶点:" << endl;
	    cin >> vb;
	    cout << "请输入该边的权值: " << endl;
	    cin >> w;
	    i =LocateVex(G,va);
	    j =LocateVex(G,vb);
	    G.arcs[i][j].adj = G.arcs[j][i].adj = w;                                                       //无向网
	    if (IncInfo)
	    {
		    cout << "请输入该边的相关信息(" << MAX_INFO  << "个字符)";
		    cin >> a;
		    w = strlen(a);
		    if (w)
		    {
			    G.arcs[i][j].info = G.arcs[j][i].info = (char *)malloc((w+1)*sizeof(char));   //无向网,两个指针指向同一个信息
			    strcpy(G.arcs[i][j].info,a);
		    }
	    }
    }
    G.kind = UDN;
    return OK;
}


Status CreateGraph(MGraph &G)
{
	cout << "请输入图G的类型\n"  << "有向图:0\n" 
		                     << "有向网:1\n"
				     << "无向图:2\n"
				     << "无向网:3\n";
	scanf("%d",&G.kind);
	switch(G.kind)
	{
	case DG:  CreateDG(G);       //有向图
		  break;
	case DN:  CreateDN(G);       //有向网
		  break;
	case UDG: CreateUDG(G);      //无向图
		  break;
	case UDN: CreateUDN(G);      //无向网
		  break;
	}
	return OK;
}
Status DestroyGraph(MGraph &G)     //若图存在,则销毁图G
{
	int i,j,k = 0;
	if(G.kind % 2)             // 网
		k = INFINITY;      // K为两顶点之间无边或无弧时邻接矩阵元素的值
	for(i = 0; i < G.vexnum; ++i)
		if(G.kind < 2)  //有向
		{
                  for(j = 0; j < G.vexnum; ++j)
		       if(G.arcs[i][j].adj != k)    //两顶点之间有弧
			       if(G.arcs[i][j].info)
			       {
				       free(G.arcs[i][j].info);
				       G.arcs[i][j].info = NULL;    
			       }
		}
	        else
		{
		       for (j = i + 1; j < G.vexnum; ++j)
		       {
			       if (G.arcs[i][j].adj != k)
				       if(G.arcs[i][j].info)
			       {
                                    free(G.arcs[i][j].info);
				    G.arcs[i][j].info = G.arcs[j][i].info = NULL;
			       }
		       }
		}
		G.vexnum = 0;
		G.vexnum = 0;

	return OK;
}
void Display(MGraph &G)
{
     for(int i = 0; i < G.vexnum; ++i)
	     for(int j = 0; j < G.vexnum; ++j)
     {
         cout << G.arcs[i][j].adj << ' ';
	 if((j+1)%G.vexnum == 0)
		 cout << endl;
     }
}
int main()
{
     int i,j,k,n;
     MGraph G;
     CreateGraph( G);
     Display(G);
     DestroyGraph(G);
	return 0;
}

有向图运行效果:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值