图 邻接矩阵 邻接表

1.图常用的两种存储结构:邻接矩阵和邻接表。

2. 邻接矩阵结构和操作定义

SeqQueue.h

//功能:邻接矩阵图的广度遍历用到的队列结构体
#define QUEUE_MAXSIZE 256
typedef struct{
	int Data[QUEUE_MAXSIZE];	//QUEUE_MAXSIZE在GraphTest.cpp文件中定义
	int head;
	int tail;
}SeqQueue;

//队列相关操作
void QueueInit(SeqQueue *Q){
	Q->head=Q->tail = 0;
}
//因为判断空函数不设计改变队列Q,所以参数不是指针变量
int QueueIsEmpty(SeqQueue *Q){
	return (Q->head == Q->tail);
}

int QueueIsFull(SeqQueue *Q){
	return ((Q->tail + 1) %QUEUE_MAXSIZE == Q->head);
}

int QueueIn(SeqQueue *Q, int ch){
	if(QueueIsFull(Q)){
		printf("队列已满,无法再插入!!");
		return 0;
	}
	Q->Data[Q->tail] = ch;
	Q->tail = (Q->tail + 1)%QUEUE_MAXSIZE;
	return 1;
}

int QueueOut(SeqQueue *Q, int *ch){
	if(QueueIsEmpty(Q)){
		printf("队列已空!!");
		return 0;
	}
	*ch = Q->Data[Q->head];
	Q->head = (Q->head + 1)%QUEUE_MAXSIZE;
	return 1;
}


AdjMatrixGraph.h

#include"SeqQueue.h"
#define VERTEX_MAX 26					//图的最大顶点数,26个字母
#define MAXVALUE 32767					//表示两点间不构成边
//Prim算法用到
#define USED 0			//已使用,加入U集合
#define NOADJ -1		//非邻接点

//功能:邻接矩阵结构体
typedef struct{
	char Vertex[VERTEX_MAX];			//保存顶点信息
	int Endges[VERTEX_MAX][VERTEX_MAX];	        //保存边的权
	int isTrav[VERTEX_MAX];				//顶点遍历标识
	int VertexNum;					//顶点总数
	int EndgeNum;					//边总数
	int GraphType;					//图的类型
}MatrixGraph;

/*--------------------------函数原型声明 start----------------------*/
void CreateMatrixGraph(MatrixGraph *G);			//功能:创建邻接矩阵图
void OutMatrix(MatrixGraph *G);				//功能:输出邻接矩阵图
void BFSTraverse(MatrixGraph *G);			//功能:广度优先遍历主函数
void BFSM(MatrixGraph *G, int k);			//功能:广度优先遍历具体实现
void DFSTraverse(MatrixGraph *G);			//功能:深度优先遍历主函数
void DFSM(MatrixGraph *G, int k);			//功能:深度优先遍历具体实现
void Prim(MatrixGraph G);				//功能:Prim最小生成树算法具体实现
void Dijkstra(MatrixGraph G);				//功能:Dijkstra最短路径算法具体实现
/*--------------------------函数原型声明 end----------------------*/

/*--------------------------函数具体实现 start----------------------*/

//功能:创建邻接矩阵图
void CreateMatrixGraph(MatrixGraph *G){
	char start, end;
	int i,j,k;
	int weight;
	printf("请输入生成图的类型(0:无向图, 1:有向图):");
	fflush(stdin);
	scanf("%d", &G->GraphType);
	printf("请输入图的顶点数和边数:");
	fflush(stdin);
	scanf("%d %d", &G->VertexNum, &G->EndgeNum);
	for(i=0; i<G->VertexNum; i++)				//清空邻接矩阵
		for(j=0; j<G->VertexNum; j++)
			G->Endges[i][j] = MAXVALUE;
	printf("请输入各顶点信息:\n");
	for(i=0; i<G->VertexNum; i++){
		printf("请输入第%d个顶点的信息:", i+1);
		fflush(stdin);
		scanf("%c", &(G->Vertex[i]));
	}

	printf("请输入构成各边的两个顶点及权值:\n");			
	for(k=0; k<G->EndgeNum; k++){
		printf("请输入第%d条边的两个顶点及权值(用空格分隔):", k+1);
		fflush(stdin);
		scanf("%c %c %d", &start, &end, &weight);
		for(i=0; start!=G->Vertex[i]; i++);
		for(j=0; end!=G->Vertex[j]; j++);
		G->Endges[i][j] = weight;
		if(G->GraphType == 0)
			G->Endges[j][i] = weight;
	}
	return;
}		

//功能:输出邻接矩阵图
void OutMatrix(MatrixGraph *G){
	int i, j;
	for(i=0; i<G->VertexNum; i++)
		printf("\t%c", G->Vertex[i]);
	printf("\n");

	for(i=0; i<G->VertexNum; i++){
		printf("%c\t", G->Vertex[i]);
		for(j=0; j<G->VertexNum; j++){
			if(G->Endges[i][j] == MAXVALUE)
				printf("∞\t");
			else
				printf("%d\t", G->Endges[i][j]);
		}
		printf("\n");
	}
	return;
}	

//功能:广度优先遍历主函数
void BFSTraverse(MatrixGraph *G){
	int i;
	for(i=0; i<G->VertexNum; i++)
		G->isTrav[i] =0;
	printf("广度优先遍历节点:");
	for(i=0; i<G->VertexNum; i++)
		if(!G->isTrav[i])
			BFSM(G, i);
	printf("\n");
}						

//功能:广度优先遍历具体实现
void BFSM(MatrixGraph *G, int k){
	int i,j;
	SeqQueue Q;
	QueueInit(&Q);
	G->isTrav[k] = 1;
	printf("->%c", G->Vertex[k]);
	QueueIn(&Q, k);

	while(!QueueIsEmpty(&Q)){
		QueueOut(&Q, &i);
		for(j=0; j<G->VertexNum; j++)
			if(G->Endges[i][j] != MAXVALUE && !G->isTrav[j]){
				G->isTrav[j] = 1;
				printf("->%c", G->Vertex[j]);
				QueueIn(&Q, j);
			}
	}
}

//功能:深度优先遍历主函数
void DFSTraverse(MatrixGraph *G){
	int i;
	for(i=0; i<G->VertexNum; i++)
		G->isTrav[i] = 0;
	printf("深度优先遍历节点:");
	for(i=0; i<G->VertexNum; i++)
		if(!G->isTrav[i])
			DFSM(G, i);
	printf("\n");
}

//功能:深度优先遍历具体实现(递归)
void DFSM(MatrixGraph *G, int k){
	int i,j;
	G->isTrav[k] = 1;
	printf("->%c",G->Vertex[k]);

	for(j=0; j<G->VertexNum; j++)
		if(G->Endges[k][j] != MAXVALUE && !G->isTrav[j])
			DFSM(G, j);
}		

//功能:Prim最小生成树算法具体实现
void Prim(MatrixGraph G){
	int i,j,k,min,sum=0;
	//Prim算法两个辅助数组
	int weight[VERTEX_MAX];			//保存tmpvertex中对应邻接边的权值
	char tmpvertex[VERTEX_MAX];		//保存邻接顶点信息

	//初始化:保存邻接矩阵中的一行数据,即0号顶点的邻接顶点、权值
	for(i=1; i<G.VertexNum; i++){
		weight[i] = G.Endges[0][i];
		if(weight[i] == MAXVALUE)
			tmpvertex[i] = NOADJ;			//非邻接点
		else
			tmpvertex[i] = G.Vertex[0];		//邻接点
	}
	tmpvertex[0] = USED;
	weight[0] = MAXVALUE;
	//生成最小生成树:即包含所有顶点
	for(i=1; i<G.VertexNum; i++){
		min = weight[0];
		k=i;
		for(j=1; j<G.VertexNum; j++)
			if(weight[j] < min && tmpvertex[j]!=0){
				min = weight[j];
				k=j;
			}
		sum +=min;
		printf("(%c,%c),", tmpvertex[k],G.Vertex[k]);
		tmpvertex[k] = USED;
		weight[k] = MAXVALUE;
		for(j=0; j<G.VertexNum; j++)
			if(G.Endges[k][j] < weight[j] && tmpvertex[j] != 0){
				weight[j] = G.Endges[k][j];
				tmpvertex[j] = G.Vertex[k];
			}
	}
	printf("\n最小生成树的总权值为:%d\n", sum);
}			

//功能:Dijkstra最短路径算法具体实现
void Dijkstra(MatrixGraph G){
	//Dijkstra算法辅助数组
	int weight[VERTEX_MAX];
	int path[VERTEX_MAX];
	int tmpvertex[VERTEX_MAX];
	int i,j,k,v0,min;
	printf("\n请输入源点的编号:");
	fflush(stdin);
	scanf("%d", &v0);
	v0--;				//编号减1(因为数组从0开始)
	//初始辅助数组
	for(i=0; i<G.VertexNum;i++){
		weight[i] = G.Endges[v0][i];	//保存最小权值
		if(weight[i]<MAXVALUE && weight[i] > 0)  //有效权值
			path[i] = v0;
		tmpvertex[i] =0;
	}
	tmpvertex[v0] = 1;		//将顶点v0添加到集合U中
	weight[v0] = 0;			//将源顶点的权值设为0
	for(i=0; i<G.VertexNum; i++){
		min = MAXVALUE;
		k = v0;
		for(j=0;j<G.VertexNum;j++)
			if(tmpvertex[j] == 0 && weight[j]<min){
				min = weight[j];
				k = j;
			}
		tmpvertex[k] = 1;
		for(j=0; j<G.VertexNum; j++)
			if(tmpvertex[j] == 0 && weight[k] + G.Endges[k][j] < weight[j]){
				weight[j] = weight[k] + G.Endges[k][j];
				path[j] = k;
			}
	}
	//输出结果
	printf("\n顶点%c到各顶点的最短路径为(终点 < 源点):\n", G.Vertex[v0]);
	for(i=0; i<G.VertexNum; i++){
		if(tmpvertex[i]==1){
			k=i;
			while(k!=v0){
				printf("%c < ", G.Vertex[k]);
				k = path[k];		//上一个顶点
			}
			printf("%c\n", G.Vertex[k]);
		}
		else
			printf("%c<-%c:无路径\n", G.Vertex[i], G.Vertex[v0]);
	}
}										
/*--------------------------函数具体实现 end----------------------*/

3. 邻接表结构和操作定义

AdjListGraph.h

#define VERTEX_MAX 20

//功能:邻接表边的结构体
typedef struct edgeNode{
	int Vertex;			//顶点序号
	int weight;			//权值
	struct edgeNode *next;		//指向下一个顶点
}EdgeNode;

//功能:图的邻接表存储结构体
typedef struct{
	EdgeNode *AdjList[VERTEX_MAX];
	int VertexNum;
	int EndgeNum;
	int GraphType;
}ListGraph;

/*--------------------------函数原型声明 start----------------------*/
void CreateListGraph(ListGraph *G);	//功能:创建邻接表图
void OutList(ListGraph *G);		//功能:输出表图
/*--------------------------函数原型声明 end----------------------*/

/*--------------------------函数具体实现 start----------------------*/

//功能:创建表图
void CreateListGraph(ListGraph *G){
	int i, weight;
	int start, end;
	EdgeNode *s;
	printf("请输入生成图的类型(0:无向图, 1:有向图):");
	fflush(stdin);
	scanf("%d", &G->GraphType);
	printf("请输入图的顶点数和边数:");
	fflush(stdin);
	scanf("%d %d", &G->VertexNum, &G->EndgeNum);
	for(i=0; i<G->VertexNum; i++)		//将图中各顶点指针清空
		G->AdjList[i] = NULL;
	for(i=1; i<=G->EndgeNum; i++){
		printf("请输入第%d条边的两个顶点及权值:", i);
		fflush(stdin);
		scanf("%d %d %d", &start, &end, &weight);
		s = (EdgeNode *)malloc(sizeof(EdgeNode));
		if(s==NULL){
			printf("申请内存失败!!");
			return ;
		}
		s->next = G->AdjList[start];		//头插法,将顶点插入到链表中
		s->weight = weight;
		s->Vertex = end;
		G->AdjList[start] = s;
		if(G->GraphType == 0){
			s = (EdgeNode *)malloc(sizeof(EdgeNode));
			if(s==NULL){
				printf("申请内存失败!!");
				return ;
			}
			s->next = G->AdjList[end];
			s->weight = weight;
			s->Vertex = start;
			G->AdjList[end] = s;
		}
	}
	return;
}	

//功能:输出表图
void OutList(ListGraph *G){
	int i;
	EdgeNode *s;
	for(i=1; i<=G->VertexNum; i++){
		printf("顶点%d", i);
		s = G->AdjList[i];
		while(s){
			printf("->%d(%d)",s->Vertex, s->weight);
			s = s->next;
		}
		printf("\n");
	}
	return;
}

/*--------------------------函数具体实现 end----------------------*/

4.图操作测试函数

GraphTest.cpp

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

#define QUEUE_MAXSIZE 30		//SeqQueue.h头文件中队列元素最大值

#include"AdjListGraph.h"
#include"AdjMatrixGraph.h"

int main(){
	int select;
	ListGraph LG;
	MatrixGraph G;
	do{
		printf("---------------------------\n");
		printf("1.用邻接矩阵法创建图       2.输出邻接矩阵\n");
		printf("3.用邻接表法创建图         4.输出邻接表\n");
		printf("5.广度优先遍历邻接矩阵图   6.深度优先遍历邻接矩阵图\n");
		printf("7.求邻接矩阵图的最小生成树 8.求邻接矩阵图指定顶点到其他顶点的最短路径\n");
		printf("0.退出\n");
		printf("请选择执行的操作序号:");
		//select = getch();
		fflush(stdin);
		scanf("%d", &select);
		switch(select){
			case 1:
				CreateMatrixGraph(&G);
				break;
			case 2:
				printf("邻接矩阵数据如下:\n");
				OutMatrix(&G);
				break;
			case 3:
				CreateListGraph(&LG);
				break;
			case 4:
				printf("邻接矩阵数据如下:\n");
				OutList(&LG);
				break;
			case 5:
				BFSTraverse(&G);
				break;
			case 6:
				DFSTraverse(&G);
				break;
			case 7:
				printf("构成最小生成树的边如下:\n");
				Prim(G);
				break;
			case 8:
				printf("最短路径算法开始执行:\n");
				Dijkstra(G);
				break;
		}
	}while(select != 0);
	system("pause");
	return 1;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值