迪杰斯特拉算法-寻找最短路径(有权/无权图)

前言:迪杰斯特拉算法寻找最短路径学习和实现笔记

什么是迪杰斯特拉算法-最短路径

迪杰斯特拉算法-手动寻找最短路径

为什么不能应用于负权值图

就比如如下图的情况,此时如果是正的有权图,那么找到的最短路径v0-v2,但是由于负权值图的存在(v1-v2的边权值为-5),这就导致了v0到v2顶点的最短路径就变成了v0-v1-v2

迪杰斯特拉算法-最短路径实现

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 32767
#define OK 1
#define ERROR 0
typedef int ElemType;
typedef int Status;
typedef char VexType;
typedef struct _Graph
{
	int vexNum;
	int arcNum;
	int** arcs;
	char* vexs;
}Graph, *PGraph;

// 初始化graph
Graph* initGraph(int vexNum)
{
	Graph* pGraph = NULL;
	if (pGraph == NULL)
	{
		pGraph = (Graph*)malloc(sizeof(Graph));
		memset(pGraph, 0, sizeof(Graph));
		if (pGraph == NULL)
			return NULL;
		pGraph->vexNum = vexNum;
		pGraph->vexs = (char*)malloc(sizeof(pGraph->vexNum));
		memset(pGraph->vexs, 0, sizeof(pGraph->vexNum));
		pGraph->arcNum = 0;
		pGraph->arcs = (int**)malloc(sizeof(int*)* pGraph->vexNum);
		memset(pGraph->arcs, sizeof(int*)* pGraph->vexNum, 0);
		for (int i = 0; i < pGraph->vexNum; i++)
		{
			pGraph->arcs[i] = (int*)malloc(sizeof(int)* pGraph->vexNum);
			memset(pGraph->arcs[i], 0, sizeof(int)*pGraph->vexNum);
		}
	}
	return pGraph;
}

// 创建邻接矩阵 - 边 - 顶点 - 顶点 - 权值
Status createGraph(Graph** pGraph, char* vexs, int* arcs)
{
	if (*pGraph == NULL)
		return ERROR;
	for (int i = 0; i<(*pGraph)->vexNum; i++)
	{
		*((*pGraph)->vexs + i) = *(vexs + i);
		for (int j = 0; j<(*pGraph)->vexNum; j++)
		{
			(*pGraph)->arcs[i][j] = *(arcs + i*((*pGraph)->vexNum) + j);
			printf("%d\t", (*pGraph)->arcs[i][j]);
			if ((*pGraph)->arcs[i][j] != 0 && (*pGraph)->arcs[i][j] != MAX)
				(*pGraph)->arcNum++;
		}
		printf("\n");
	}
	(*pGraph)->arcNum /= 2;
	return OK;
}

// 深度优先遍历DFS
Status DFS(Graph* pGraph, int* iVisitedArray, int visitedIndex)
{
	if (pGraph == NULL)
		return ERROR;
	iVisitedArray[visitedIndex] = 1;
	printf("%c ", pGraph->vexs[visitedIndex]);
	for (int i = 0; i<pGraph->vexNum; i++)
	{
		if (pGraph->arcs[visitedIndex][i] > 0 && !iVisitedArray[i] && pGraph->arcs[visitedIndex][i] != MAX)
			DFS(pGraph, iVisitedArray, i);
	}
	return OK;
}

// 记录当前顶点的相关的路径权值
typedef struct _Edge{
	char vex;
	int weight;
}Edge;

// 标识当前顶点是否为最短路径使用
typedef struct _VexSet{
	int iFlag;
}VexSet;

// 标识顶点的最小路径
VexSet* initVexSet(Graph* pGraph)
{
	VexSet* pVexSet = (VexSet*)malloc(sizeof(VexSet)* pGraph->vexNum);
	for (int i = 0;i<pGraph->vexNum;i++)
		pVexSet[i].iFlag = 0;
	return pVexSet;
}

// Edge的结构体用来存储当前顶点相邻顶点之间的边的权值
// 后面每次找到一个最小权值的边之后,会以对应的顶点去更新Edge结构体为后续循环继续使用
Edge* initEdge(Graph* pGraph, VexSet* pVexSet, int index)
{
	Edge* pEdge = (Edge*)malloc(sizeof(Edge)*pGraph->vexNum);
	for (int i = 0; i<pGraph->vexNum; i++)
	{
		pEdge[i].vex = pGraph->vexs[index];
		pEdge[i].weight = pGraph->arcs[index][i];
	}
	// 默认第一个顶点和自己的距离最短,那么这个顶点的最短路径就是自己
	pVexSet[index].iFlag = 1;
	return pEdge;
}

// 返回的是下一个要取得最小权值的顶点的索引
int getMinIndex(Graph* pGraph, Edge* pEdge, VexSet* pVexSet)
{
	int index = 0;
	int iMin = MAX;
	for (int i = 0; i < pGraph->vexNum; i++)
	{
		if (pEdge[i].weight != 0 && pEdge[i].weight < iMin && pVexSet[i].iFlag == 0)
		{
			iMin = pEdge[i].weight;
			index = i;
		}
	}
	// 输出最短路径的边的两个顶点
	printf("%c -- %c -- weight: %d \n", pEdge[index].vex, pGraph->vexs[index], pEdge[index].weight);
	return index; // 每次返回的都是edge中最小权值对应的索引
}

int getMinWeight(Graph* pGraph, Edge* pEdge, VexSet* pVexSet)
{
	int index = 0;
	int iMin = MAX;
	for (int i = 0; i < pGraph->vexNum; i++)
	{
		if (pEdge[i].weight != 0 && pEdge[i].weight < iMin && pVexSet[i].iFlag == 0)
		{
			iMin = pEdge[i].weight;
			index = i;
		}
	}

	return iMin;
}

// 测试从索引0开始进行寻找其他顶点之间的最短路径
void getDijkstra(Graph* pGraph, int index)
{
	VexSet* pVexSet = initVexSet(pGraph);
	Edge* pEdge = initEdge(pGraph, pVexSet, index);
	int iMinIndex;
	int iMinWeight;
	// 循环次数为pGraph->vexNum-1次
	for (int i = 0;i<pGraph->vexNum-1;i++)
	{
		// 获取Edge中当前顶点相邻的最小权值的顶点
		iMinIndex = getMinIndex(pGraph, pEdge, pVexSet);
		iMinWeight = getMinWeight(pGraph, pEdge, pVexSet);
		// 设置顶点最小权值的标志位
		pVexSet[iMinIndex].iFlag = 1; 
		// 每次找完之后都需要更新一次pEdge,pEdge记录的永远是当前权值的最小值
		for (int j = 0;j<pGraph->vexNum;j++)
		{
			if (pEdge[j].weight > pGraph->arcs[iMinIndex][j] && pGraph->arcs[iMinIndex][j] != 0)
			{
				pEdge[j].weight = iMinWeight + pGraph->arcs[iMinIndex][j];
				pEdge[j].vex = pGraph->vexs[iMinIndex];
			}
		}
	}
}

int main()
{
	int initArcs[6][6] = {
		0,1,12,MAX,MAX,MAX,
		MAX,0,9,3,MAX,MAX,
		MAX,MAX,0,MAX,5,MAX,
		MAX,MAX,4,0,13,15,
		MAX,MAX,MAX,MAX,0,4,
		MAX,MAX,MAX,MAX,MAX,0
	};
	char initVexs[7] = "123456";
	Graph* pGraph = initGraph(6);
	createGraph(&pGraph, initVexs, (int*)initArcs);
	getDijkstra(pGraph, 0);
	return 0;
}

posted @ 2022-04-11 18:09  zpchcbd  阅读(280)  评论(0)    收藏  举报