数据结构:图的邻接矩阵存储实现

/******************************************************

程序:图的邻接矩阵存储实现
完成者:小单
完成时间:2013年5月31日

*******************************************************/
//测试
图片

#include <stdio.h>
#include <stdlib.h>

//#include <limits.h>
#define MAX_VERTEX_NUM 20   //最大顶点数
#define MAX MAX_VERTEX_NUM

#define INFINITY 0  //用0表示顶点之间无关系

#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0
typedef int Status;

/*----------------用到的数据结构---队-------------------*/
typedef char QElemType;
typedef struct QNode
{
	QElemType data;
	struct QNode *next;
}QNode, *QueuePtr;
typedef struct  
{
	QueuePtr front;  //队头
	QueuePtr rear;  //队尾
}LinkQueue;
Status InitQueue(LinkQueue &Q)
{
	Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
	if(!Q.front)
		exit(OVERFLOW);
	Q.front->next = NULL;
	return OK;
}

Status EnQueue(LinkQueue &Q, QElemType e)
{
	QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
	if(!p)
		exit(OVERFLOW);
	p->data = e;
	p->next = NULL;
	Q.rear->next = p;
	Q.rear = p;
	return OK;
}

Status DeQueue(LinkQueue &Q, QElemType &e)
{
	if(Q.front == Q.rear)
		return ERROR;
	QueuePtr 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 EmptyQueue(LinkQueue &Q)
{
	if(Q.front == Q.rear )
		return TRUE;
	return FALSE;
}

/*---------------------数据结构--队-----------------*/



typedef int VRType;//顶点关系类型
typedef int InfoType;  
typedef char VertexType; //顶点值类型
typedef enum{DG, DN, UDG, UDN}GraphKind;  //{有向图,有向网,无向图,无向网}
typedef struct ArcCell
{
	VRType adj;  //VRType是顶点关系类型,对无权图,用1或0表示相邻否
				//对带权图,则为权值类型
	InfoType *info;  //该弧相关信息的指针
}ArcCell, AdjMatric[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

typedef struct  
{
	VertexType vexs[MAX_VERTEX_NUM];  //顶点向量
	AdjMatric arcs;  //邻接矩阵
	int vexnum, arcnum;  //图的当前顶点数与弧数
	GraphKind kind;  //图的种类标志
}MGraph;

bool visited[MAX];  //访问标志数组
Status (*VisitFunc)(MGraph &G,int v);  //函数变量

int LocateVex(const MGraph &G, VertexType u)
{
	//初始条件:图G存在,u与G中顶点有相同特征
	//操作结果:若G中存在顶点u,则返回该顶点在图中位置,否则返回-1
	for(int i=0; i < G.vexnum; ++i)
	{
		if(u == (G.vexs[i]))
			return i;
	}
	return -1;
}

Status CreateDG(MGraph &G)//构造有向图
{
	//采用数组(邻接矩阵)表示法,构造有向图G
	printf("请输入有向图的顶点数与边数:\n");
	scanf("%d%d",&G.vexnum, &G.arcnum);  
	int i,j;
	printf("请输入%d个顶点的值:\n",G.vexnum);
	getchar();//取出输入流中的回车符
	for(i = 0; i < G.vexnum; ++i)
	{
		scanf("%c",&G.vexs[i]);
	}
	//scanf("%*c"); //跳过输入流中的回车符
	//char buffer = getchar(); //取出输入流中的回车符
	for(i=0; i<G.vexnum; ++i)  //初始化邻接矩阵
	{
		for(j=0; j<G.vexnum; ++j)
		{
			G.arcs[i][j].adj = 0;  //表示图
			G.arcs[i][j].info = NULL;  //表示无边的相关信息
		}
	}
	int k;
	VertexType v1, v2;//顶点的临时存储变量
	for(k=0; k<G.arcnum; ++k) //构造邻接矩阵
	{
		printf("请输入第%d条边依附的顶点:\n", k+1);
		getchar(); //取出输入流中的回车符
		scanf("%c%c",&v1, &v2); //%*c  跳过回车符
		i=LocateVex(G,v1);
		j=LocateVex(G,v2);
		if(i==-1 || j==-1)
			return ERROR;  //无此顶点,构造失败,返回出错信息
		G.arcs[i][j].adj = 1;
		//因为边没有其他的相关信息,G.arcs[i][j].info== NULL,保持不变
	}
	G.kind = DG;  //有向图
	return OK;
}

Status CreateDN(MGraph &G)
{
	//采用数组(邻接矩阵)表示法,构造有向网G
	printf("请输入有向网的顶点数与边数:\n");
	scanf("%d %d",&G.vexnum, &G.arcnum);
	getchar();//取出输入流中的回车符
	int i,j;
	printf("请输入%d个顶点的值:\n",G.vexnum);
	for(i=0; i<G.vexnum; ++i)//构造顶点向量
	{
		scanf("%c",&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;  //表示无边的相关信息
		}
	}
	
	int k;
	VertexType v1, v2;//顶点的临时存储变量
	VRType w;  //顶点关系,此时代表权值
	for(k=0; k<G.arcnum; ++k) //构造邻接矩阵
	{
		printf("请输入第%d条边依附的顶点及权值:\n", k+1);
		getchar();//取出输入流中的回车符
		scanf("%c%c%d",&v1, &v2, &w);
		i=LocateVex(G,v1);
		j=LocateVex(G,v2);
		if(i==-1 || j==-1)
			return ERROR;  //无此顶点,构造失败,返回出错信息
		G.arcs[i][j].adj = w;
		//因为边没有其他的相关信息,G.arcs[i][j].info== NULL,保持不变
	}
	G.kind = DN;  //有向网
	return OK;
}

Status CreateUDG(MGraph &G)//构造无向图
{
	//采用数组(邻接矩阵)表示法,构造无向图G
	printf("请输入无向图的顶点数与边数:\n");
	scanf("%d%d",&G.vexnum, &G.arcnum);  
	int i,j;
	printf("请输入%d个顶点的值:\n",G.vexnum);
	getchar();//取出输入流中的回车符
	for(i = 0; i < G.vexnum; ++i)
	{
		scanf("%c",&G.vexs[i]);
	}
	//scanf("%*c"); //跳过输入流中的回车符
	//char buffer = getchar(); //取出输入流中的回车符
	for(i=0; i<G.vexnum; ++i)  //初始化邻接矩阵
	{
		for(j=0; j<G.vexnum; ++j)
		{
			G.arcs[i][j].adj = 0;  //表示图
			G.arcs[i][j].info = NULL;  //表示无边的相关信息
		}
	}
	int k;
	VertexType v1, v2;//顶点的临时存储变量
	for(k=0; k<G.arcnum; ++k) //构造邻接矩阵
	{
		printf("请输入第%d条边依附的顶点:\n", k+1);
		getchar(); //取出输入流中的回车符
		scanf("%c%c",&v1, &v2); //%*c  跳过回车符
		i=LocateVex(G,v1);
		j=LocateVex(G,v2);
		if(i==-1 || j==-1)
			return ERROR;  //无此顶点,构造失败,返回出错信息
		G.arcs[i][j].adj = 1;
		G.arcs[j][i].adj = G.arcs[i][j].adj;  //对称弧的信息
		//因为边没有其他的相关信息,G.arcs[i][j].info== NULL,保持不变
	}
	G.kind = UDG;  //无向图
	return OK;
}


Status CreateUDN(MGraph &G)
{
	//采用数组(邻接矩阵)表示法,构造无向网G
	printf("请输入无向网的顶点数与边数:\n");
	scanf("%d %d",&G.vexnum, &G.arcnum);
	getchar();//取出输入流中的回车符
	int i,j;
	printf("请输入%d个顶点的值:\n",G.vexnum);
	for(i=0; i<G.vexnum; ++i)//构造顶点向量
	{
		scanf("%c",&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;  //表示无边的相关信息
		}
	}

	int k;
	VertexType v1, v2;//顶点的临时存储变量
	VRType w;  //顶点关系,此时代表权值
	for(k=0; k<G.arcnum; ++k) //构造邻接矩阵
	{
		printf("请输入第%d条边依附的顶点及权值:\n", k+1);
		getchar();//取出输入流中的回车符
		scanf("%c%c%d",&v1, &v2, &w);
		i=LocateVex(G,v1);
		j=LocateVex(G,v2);
		if(i==-1 || j==-1)
			return ERROR;  //无此顶点,构造失败,返回出错信息
		G.arcs[i][j].adj = w;
		//因为边没有其他的相关信息,G.arcs[i][j].info== NULL,保持不变
		G.arcs[j][i].adj = G.arcs[i][j].adj;  //置<v1,v2>的对称弧<v2,v1>;
	}
	G.kind = UDN;  //无向网
	return OK;
}

Status CreateGraph(MGraph &G)
{
	//构造图G
	printf("请输入构造的类型:(0:有向图,1:有向网,2:无向图,3:无向网):");
	scanf("%d",&G.kind);
	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;
	}
}
VertexType GetVex(MGraph &G, int v)
{
	//初始条件:图G存在,v是G中某个顶点的序号
	//操作结果:若存在,则返回其值,否则返回空
	if(v >= G.vexnum || v < 0)
		return NULL;
	return G.vexs[v];
}

Status PutVex(MGraph &G,int v, VertexType value)
{
	//初始条件:图G存在,v是G中某个顶点的序号
	//操作结果:对v赋值value
	if(v >= G.vexnum || v < 0)
		return ERROR;
	G.vexs[v] = value;
	return OK;
}

int FirstAdjVex(MGraph &G, VertexType v)
{
	//初始条件:图G存在,v是G中某个顶点
	//操作结果:返回v的第一个邻接顶点,若顶点在G中没有邻接顶点,则返回"空"
	int k = LocateVex(G,v);
	if(k == -1)//无此顶点
		return -1;
	int adjValue = 0; 
	if(G.kind == DN || G.kind == UDN)
		adjValue = INFINITY;
	
	for(int i=0; i < G.vexnum; ++i)
	{
		if(G.arcs[k][i].adj != adjValue)
			return i;
	}
	return -1;
}

int NextAdjVex(MGraph &G, VertexType v, VertexType w)
{
	//初始条件:图G存在,v是G中某个顶点,w是v的邻接顶点
	//操作结果:返回v的(相对于w的)下一个邻接顶点。若w是v的最后一个邻接点,则返回“空”
	int k1=LocateVex(G,v);
	int k2=LocateVex(G,w);

	if(k1 == -1 || k2 == -1)//无此顶点
	{
		return -1;
	}
	int adjValue = 0; 
	if(G.kind == DN || G.kind == UDN)
		adjValue = INFINITY;
	for(int i=k2+1; i < G.vexnum; ++i)
	{
		if(G.arcs[k1][i].adj != adjValue)
		{
			return i;
		}
	}
	return -1;

}

Status InsertVex(MGraph &G, VertexType v)
{
	//初始条件:图G存在,v和图G某个顶点有相同的特征
	//操作结果:在图G中增添新顶点v(此时不增加关系)
	G.vexs[G.vexnum] = v;  //赋于顶点值
	for(int i=0; i <=G.vexnum; ++i)
	{
		if(G.kind%2==0)//图
		{
			G.arcs[G.vexnum][i].adj = 0;
			G.arcs[i][G.vexnum].adj = 0;
		}
		else  //网
		{
			G.arcs[G.vexnum][i].adj = INFINITY;
			G.arcs[i][G.vexnum].adj = INFINITY;
		}
	}
	G.arcs[G.vexnum][i].info = NULL; //初始化该弧的相关信息
	G.arcs[i][G.vexnum].info = NULL; //初始化该弧的相关信息
	G.vexnum++;
	
	return OK;
}

Status DeleteVex(MGraph &G, VertexType v)
{
	//初始条件:图G存在,v是G中某个顶点
	//操作结果:删除G中顶点v及其相关的弧
	int k = LocateVex(G,v);
	if(k == -1)
		return ERROR; //无此结点
	//1.从顶点向量中删除该顶点
	int i,j;
	for(i=k; i < G.vexnum-1; ++i)
	{
		G.vexs[i] = G.vexs[i+1];
	}

	//2.删除边的关系
	for(i=k; i < G.vexnum-1; ++i)
	{
		for(j=0; j < G.vexnum; ++j)
		{
			G.arcs[i][j].adj = G.arcs[i+1][j].adj;
			//因为没有设弧的相关信息,就不考虑G.arcs[][].info了
		}
	}
	for(j=k; j < G.vexnum-1; ++j)
	{
		for(i=0; i < G.vexnum; ++i)
		{
			G.arcs[i][j].adj = G.arcs[i][j+1].adj;
			//因为没有设弧的相关信息,就不考虑G.arcs[][].info了
		}
	}

	--G.arcnum;  //边数减1
	--G.vexnum;  //顶点数减1
	return OK;
}

Status InsertArc(MGraph &G, VertexType v, VertexType w)
{
	//初始条件:图G存在,v和w是G中两个顶点
	//操作结果:在G中增添弧<v,w>,若是无向的,则还增添对称弧
	int k1= LocateVex(G,v);
	int k2= LocateVex(G,w);
	if(k1==-1 || k2==-1)
		return ERROR;  //图中不存在v或w
	if(G.kind%2 == 1)//网
	{
		printf("请输入该弧的权值:");
		scanf("%d",&G.arcs[k1][k2].adj);
	}
	else // 图
	{
		G.arcs[k1][k2].adj = 1;
	}

	if(G.kind > 1) //无向
	{
		G.arcs[k2][k1].adj = G.arcs[k1][k2].adj;
	}
	++G.arcnum;  //弧数加1
	return OK;
	
}

Status DeleteArc(MGraph &G, VertexType v, VertexType w)
{
	//初始条件:图G存在,v和w是G中两个顶点
	//操作结果:在G中删除弧<v,w>,若是无向的,则还删除对称弧
	int k1= LocateVex(G,v);
	int k2= LocateVex(G,w);
	if(k1==-1 || k2==-1)
		return ERROR;  //图中不存在v或w
	if(G.kind%2 == 1)//网
	{
		G.arcs[k1][k2].adj = INFINITY;
	}
	else // 图
	{
		G.arcs[k1][k2].adj = 0;
	}
	
	if(G.kind > 1) //无向
	{
		G.arcs[k2][k1].adj = G.arcs[k1][k2].adj;
	}
	--G.arcnum;  //弧数加1
	return OK;

}

void DFS(MGraph &G, int v)
{
	//从第v个顶点出发递归地深度优先遍历图G
	visited[v] = TRUE;
	VisitFunc(G,v);  //访问第v个顶点
	for(int w = FirstAdjVex(G,GetVex(G,v)); w >= 0; w = NextAdjVex(G,GetVex(G,v),GetVex(G,w)))
		if(!visited[w])
			DFS(G,w);  //对v的尚未访问的邻接顶点w递归调用DFS
}

void DFSTraverse(MGraph &G, Status(*Visit)(MGraph &G,int v))//对图作深度优先遍历
{
	VisitFunc = Visit;  //使用全局变量VisitFunc,使DFS不必设函数指针参数
	for(int v=0; v < G.vexnum; ++v)
	{
		visited[v] = FALSE;  //访问标志数组初始化
	}
	for(v = 0; v < G.vexnum; ++v)
	{
		if(!visited[v])
			DFS(G,v);  //对尚未访问的顶点调用DFS
	}
}

void BFSTraverse(MGraph &G, Status(*Visit)(MGraph &G,int v))//对图作广度优先遍历
{
	int BFSvisited[MAX],i;
	for(i = 0; i<G.vexnum; ++i)
	{
		BFSvisited[i] = FALSE;//初始化辅助访问数组,开始顶点均为未访问的标志
	}
	LinkQueue Q;
	InitQueue(Q); //初始化辅助队列Q
	for(i=0; i < G.vexnum; ++i)
	{
		if(!BFSvisited[i])//序号为i的顶点未访问
		{
			BFSvisited[i] = TRUE;
			Visit(G,i);
			EnQueue(Q,GetVex(G,i));//序号为i的顶点入队
			while(!EmptyQueue(Q))
			{
				QElemType u;
				DeQueue(Q,u);
				for(int w=FirstAdjVex(G,u); w >=0; w=NextAdjVex(G,u,GetVex(G,w)))
				{
					if(!BFSvisited[w])
					{
						BFSvisited[w] = TRUE;
						Visit(G,w);
						EnQueue(Q,GetVex(G,w));
					}
				}
			}
		}
	}
}

Status VisitVex(MGraph &G,int v)
{
	//访问序号为v的顶点
	printf("%3c",G.vexs[v]);
	return OK;
}
void DisplayVexValue(const MGraph &G)//显示所有的顶点
{
	printf("顶点为:");
	for(int i=0; i < G.vexnum; ++i)
		printf("%c\t",G.vexs[i]);
	printf("\n");
}

void DisplayAdjMatrix(const MGraph &G)
{
	//输出邻接矩阵
	printf("\n邻接矩阵为:\n");
	for(int i=0; i<G.vexnum; ++i)
	{
		for(int j=0; j<G.vexnum; ++j)
		{
			printf("%d\t",G.arcs[i][j]);
		}
		printf("\n");
	}
}

void Panel()
{
	//操作菜单
	printf("\n");
	printf("\t\t----------------------------------------------\n");
	printf("\t\t---------------------图的操作-----------------\n\n");
	printf("\t\t     0-创建图              1-查看顶点信息     \n");
	printf("\t\t     2-更改指定顶点的值    3-插入顶点         \n");
	printf("\t\t     4-删除顶点            5-插入弧           \n");
	printf("\t\t     6-删除弧              7-深度优先遍历图   \n");
	printf("\t\t     8-广度优先遍历图      9-查看图的邻接矩阵 \n");
	printf("\t\t     10-退出                                  \n\n");
	printf("\t\t---------------------图的操作-----------------\n");
	printf("\t\t----------------------------------------------\n");
}

int main()
{
	MGraph G;
	int n;
	int i;
	VertexType v,w;
	while(1)
	{
		Panel();
		printf("请输入操作号:");
		scanf("%d",&n);
		getchar();
		switch(n)
		{
		case 0://创建图
			if(CreateGraph(G))
				printf("创建成功\n");
			else
				printf("创建失败\n");
			system("pause");
			break;
		case 1://查看顶点信息
			DisplayVexValue(G);
			system("pause");
			break;
		case 2://更改指定顶点的值
			printf("请输入更改顶点的序号:");
			scanf("%d",&i);
			getchar();
			printf("请输入顶点的新值:");
			scanf("%c",&v);
			getchar();
			PutVex(G,i,v);
			system("pause");
			break;
		case 3://插入顶点
			printf("请输入你所要插入顶点的值:");
			scanf("%c",&v);
			getchar();
			InsertVex(G,v);
			system("pause");
			break;
		case 4://删除顶点
			printf("请输入你所要删除的顶点的值:");
			scanf("%c",&v);
			getchar();
			DeleteVex(G,v);
			system("pause");
			break;
		case 5://插入弧
			printf("插入:请输入弧依赋的两个顶点的值:");
			scanf("%c%c",&v,&w);
			getchar();
			InsertArc(G,v,w);
			system("pause");
			break;
		case 6://删除弧 
			printf("删除:请输入弧依赋的两个顶点的值:");
			scanf("%c%c",&v,&w);
			getchar();
			DeleteArc(G,v,w);
			system("pause");
			break;
		case 7://深度优先遍历图
			printf("深度优先遍历的结果为:\n");
			DFSTraverse(G,VisitVex);
			printf("\n");
			system("pause");
			break;
		case 8://广度优先遍历图
			printf("广度优先遍历的结果为:\n");
			BFSTraverse(G,VisitVex);
			printf("\n");
			system("pause");
			break;
		case 9://查看图的邻接矩阵
			DisplayAdjMatrix(G);
			system("pause");
			break;
		case 10://退出
			exit(OVERFLOW);
			break;
		default:
			printf("无此操作\n");
			system("pause");
			
		}

	}

/*	printf("创建无向网\n");
	CreateUDN(G);
	for(int i=0; i<G.vexnum; ++i)
	{
		for(int j=0; j<G.vexnum; ++j)
		{
			printf("%d\t",G.arcs[i][j]);
		}
		printf("\n");
	}
*/

/*	printf("创建有向图\n");
	CreateDG(G);
	for(int i=0; i<G.vexnum; ++i)
	{
		for(int j=0; j<G.vexnum; ++j)
		{
			printf("%d\t",G.arcs[i][j]);
		}
		printf("\n");
	}
	
	

	while(1)//测试GetVex,与PutVex
	{
		system("pause");
		DisplayVexValue(G);
		printf("请输入你要查询的顶点序号:\n");
		int v;
		scanf("%d",&v);
		VertexType a = GetVex(G,v);
		if(!a)
		{
			printf("没有这个顶点\n");
		}
		else
		{
			printf("顶点为:%c\n",a);
		}
		VertexType vt;
		printf("请输入你要对所查询的顶点更改的值:\n");
		getchar();
		scanf("%c",&vt);
		PutVex(G,v,vt);

		system("pause");
		DisplayVexValue(G);//输出此时的顶点号

		printf("请输入你要查找邻接结点的结点:\n");
		getchar();
		scanf("%c",&v);
		vt = FirstAdjVex(G,v);
		if(vt)
		{
			printf("顶点%c第一个邻接结点为:%c", v, vt);
		}
		else
		{
			printf("没有第一个邻接结点");
		}
		VertexType w;
		printf("\n请输入相对位置的顶点,以便查询顶点%c的下一个邻接顶点:\n",v);
		getchar();
		scanf("%c",&w);
		vt = NextAdjVex(G,v,w);
		if(vt)
		{
			printf("顶点%c相对于顶点%c的下一个邻接顶点为:%c\n",v,w,vt);
		}
		else
		{
			printf("没有下一个邻接顶点\n");
		}
	
	}*/

	return 0;
}


  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值