图中的一些算法(邻接矩阵的方式)

使用邻接矩阵建立图

头文件

#include "Queue.cpp"//自己编写队列文件
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>

所需函数

PtrGraph initGraphWithoutEdge(int VertexNum);//初始化一个有顶点但没有边的图
void insertEdge(PtrGraph pGraph, PtrEdge pEdge);//将边插入图中(修改邻接矩阵)
PtrGraph buildGraph(void); //创建有边和节点的图
void BFS(PtrGraph pGraph, Vertex V);//广度优先搜索(利用队列实现),从V节点开始
void visitNode(Vertex V);//访问V节点
bool isEdge(PtrGraph pGraph, Vertex W, Vertex V);//判断<W,V>是不是图中的边
void DFS(PtrGraph pGraph, Vertex V);//深度优先搜索,从V节点开始
void DFStraversal(PtrGraph pGraph, Vertex V, int* visited);//深度优先搜索的内部函数,从V节点开始,visited是已被访问的节点的数组
void unweigtedShortestPath(PtrGraph pGraph, Source S, Vertex* path, int* distance);//无权图的单源最短路算法
																				//S是源点,path记录到顶点的要经过的顶点,distance记录到顶点的最短路径
void Dijkstra(PtrGraph pGraph, Source S, Vertex* path, int* distance);//单源加权图,所有权都为正
void Floyd(PtrGraph pGraph, Vertex path[MAX_SIZE][MAX_SIZE], int distance[MAX_SIZE][MAX_SIZE]);//多源加权图最短路径

Vertex findMinDist(int* dist, int length, int* collected);//寻未被搜集中的最小值

int* newZeroArray(int length);
int* newConstantArray(int length, int val);//创建一个长度为length,值都为val的数组
void showArray(int* arr, int length); //输出数组中的所有元素

定义图,边的结构

//使用邻接矩阵建立图
constexpr auto MAX_SIZE = 10; //顶点的最大数目
constexpr auto INFINITY = 100; //定义无穷大

typedef int WeightType; //图的权重为int型
typedef int Vertex, Source; //抽象图中的边的类型

typedef struct { //图结构
	int Nv;//顶点数目
	int Ne;//边的数目
	WeightType AdjMatrix[MAX_SIZE][MAX_SIZE];//邻接矩阵(对加权图元素表示边的权重)
	//DataType Date[MAX_SIZE]; //顶点的数据类型 
}Graph, * PtrGraph;

typedef struct {//边要包括起点和终点,以及边自身的权重
	Vertex V1;
	Vertex V2;
	WeightType Weight;
}Edge, * PtrEdge;

建立图的方式

先创建顶点,再插入边,具体实现方式:

/*initGraphWithoutEdge函数 和 insertEdge函数 需要根据图的具体类型改变*/
PtrGraph initGraphWithoutEdge(int vertexNum) {//初始化一个有顶点但没有边的图
	PtrGraph pGraph = (PtrGraph)malloc(sizeof(Graph));
	if (pGraph == NULL) {
		printf("分配内存失败!\n");
		exit(-1);
	}
	else {
		pGraph->Nv = vertexNum;
		pGraph->Ne = 0;
		for (Vertex V = 0; V < vertexNum; V++)
			for (Vertex W = 0; W < vertexNum; W++) {
				pGraph->AdjMatrix[V][W] = INFINITY;//加权图:INFINITY,但对角线上都是0
												   //无加权图:0
				if (W == V)
					pGraph->AdjMatrix[V][W] = 0;
			}
				
	}
	return pGraph;
}

void insertEdge(PtrGraph pGraph, PtrEdge pEdge) {//将边插入图中(修改邻接矩阵)
	pGraph->AdjMatrix[pEdge->V1][pEdge->V2] = pEdge->Weight;
	//如果是无向图
	//pGraph->AdjMatrix[pEdge->V2][pEdge->V1] = pEdge->Weight;
}

PtrGraph buildGraph(void) {//创建有边和节点的图
	int vertexNum, edgeNum;
	printf("请输入顶点数:");
	scanf_s("%d", &vertexNum); //输入顶点数
	PtrGraph pGraph = initGraphWithoutEdge(vertexNum);

	printf("请输入边数:");
	scanf_s("%d", &edgeNum); //输入边数
	pGraph->Ne = edgeNum;
	if (edgeNum != 0) {
		Edge E;
		for (int i = 1; i <= edgeNum; i++) {
			printf("请输入第%d条边的端点(起点):",i);
			scanf_s("%d", &E.V1);//输入边的信息
			printf("请输入第%d条边的端点(终点):",i);
			scanf_s("%d", &E.V2);//输入边的信息
			printf("请输入第%d条边的权重:",i);
			scanf_s("%d", &E.Weight);//输入边的信息
			insertEdge(pGraph, &E);
		}
	}
	return pGraph;
}

两种遍历方式:

广度优先搜索

void BFS(PtrGraph pGraph, Vertex V) {//广度优先搜索(利用队列实现),从V节点开始
	PtrQueue pQ = initQueue(MAX_SIZE); //创建队列

	/*用数组记录已经访问的顶点,1表示已访问,0表示未访问*/
	int* visited = newZeroArray(pGraph->Nv);

	visitNode(V); //访问V节点
	visited[V] = 1;
	enQueue(pQ, V); //入队
	Vertex S;
	while (!isEmpty(pQ)) {
		S = deQueue(pQ);
		for (Vertex W = 0; W < pGraph->Nv; W++) {
			if (visited[W]==0 && isEdge(pGraph, S, W)) {
				visitNode(W);
				visited[W] = 1;
				enQueue(pQ, W); //入队
			}
		}
	}

}

深度优先搜索

void DFS(PtrGraph pGraph, Vertex V) {//深度优先搜索,从V节点开始
	/*用数组记录已经访问的顶点,1表示已访问,0表示未访问*/
	int* visited = newZeroArray(pGraph->Nv);
	/*访问节点V,再遍历其他邻居的图(不访问已被访问过的节点)*/
	DFStraversal(pGraph, V, visited);
}

void DFStraversal(PtrGraph pGraph, Vertex V, int* visited) {
	/*访问节点V*/
	visitNode(V);
	visited[V] = 1;
	/*已相同的方式遍历V的邻居*/
	for (Vertex W = 0; W < pGraph->Nv; W++)
		if (visited[W] == 0 && isEdge(pGraph, W, V))//W是V未被访问的邻居
			DFStraversal(pGraph, W, visited);
}

void visitNode(Vertex V) {//访问V节点
	printf("正在访问%d节点\n", V);
}

bool isEdge(PtrGraph pGraph, Vertex W, Vertex V) {//判断<W,V>是不是图中的边
	//temp=0 说明不是是无权图的边,无权图的边为1
	//temp=INFINITY说明不是是加权图的边,加权图的边 <INFINITY && >0(0说明W 和V是同一个点
	int temp = pGraph->AdjMatrix[W][V];
	return temp != 0 && temp != INFINITY;
}

int* newZeroArray(int length) {
	int* visited = newArray(length);
	for (int W = 0; W < length; W++)
		visited[W] = 0;

	return visited;
}

最短路径问题

无权图的单源最短路算法

void unweigtedShortestPath(PtrGraph pGraph, Source S, Vertex* path, int* distance) {//无权图的单源最短路算法 
	/*S是源点,path记录到顶点的要经过的顶点,distance记录到顶点的最短路径*/
	/*类似于广度优先搜索的算法,无加权时,先到的就是最短的*/
	distance[S] = 0;

	PtrQueue pQ = initQueue(pGraph->Nv);
	enQueue(pQ, S);
	Vertex V;
	while (!isEmpty(pQ)) {
		V = deQueue(pQ);
		for(Vertex W = 0;W<pGraph->Nv;W++)
			if (distance[W] == -1 && isEdge(pGraph, V, W)) {//W是V的邻接点
				distance[W] = distance[V] + 1;
				path[W] = V;
				enQueue(pQ, W);
			}			
	}	
}

加权图的单源最短路算法:Dijkstra算法

void Dijkstra(PtrGraph pGraph, Source S, Vertex* path, int* distance){//有源加权图,所有权都为正
	int* collected = newZeroArray(pGraph->Nv);
	distance[S] = 0;
	Vertex V;
	while (1) {
		V = findMinDist(distance, pGraph->Nv, collected);//寻未被搜集中的最小值
		if (V == -1)//这样的V不存在,所有顶点都被搜集了
			break;
		else {
			collected[V] = 1;
			for (Vertex W = 0; W < pGraph->Nv; W++) 
				if (isEdge(pGraph, V, W) && collected[W] == 0) //W是V的邻接点,并且W没有被搜集
					if (distance[W] > distance[V] + pGraph->AdjMatrix[V][W]) {
						distance[W] = distance[V] + pGraph->AdjMatrix[V][W];
						path[W] = V;
					}		
		}
	}
}

int* newZeroArray(int length) {
	int* visited = newArray(length);
	for (int W = 0; W < length; W++)
		visited[W] = 0;

	return visited;
}

Vertex findMinDist(int* dist, int length, int* collected) {//寻未被搜集中的最小值
	int min = INFINITY;
	int minVertex;
	for (int i = 0; i < length; i++) 
		if (collected[i] == 0) //表示未被搜集
			if (dist[i] < min) {
				min = dist[i];
				minVertex = i;
			}
	
	//如果找不到这样的点,返回-1
	if (min == INFINITY)
		return -1;
	else
		return minVertex;
}

多源加权图最短路径:Floyd算法

void Floyd(PtrGraph pGraph, Vertex path[MAX_SIZE][MAX_SIZE], int distance[MAX_SIZE][MAX_SIZE]) {//多源加权图最短路径
	for (Vertex V = 0; V < pGraph->Nv; V++)
		for (Vertex W = 0; W < pGraph->Nv; W++)
			distance[V][W] = pGraph->AdjMatrix[V][W];

	for (Vertex M = 0; M < pGraph->Nv; M++)
		for (Vertex V = 0; V < pGraph->Nv; V++)
			for (Vertex W = 0; W < pGraph->Nv; W++)
				if (distance[V][W] > distance[V][M] + distance[M][W]) {
					distance[V][W] = distance[V][M] + distance[M][W];
					path[V][W] = M;
				}
					
}

最小生成树问题

Prim算法(针对稠密图)

Kruskal算法

拓扑排序

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值