算法提升:图的Dijkstra(迪杰斯特拉)算法

目录

概念

思路

代码


概念

迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。

注意该算法要求图中不存在负权边,不然会导致算法被困在一个圈内。

思路

假设我们的目标是从A到D

基本的思路就是维护一个路径长度表,每个节点就是key本身,因为是从A节点出发到D节点,然后A的初始值就是0,其余值都是-1(表示还没有到)。

A

B

C

D

0

-1

-1

-1

然后开始从A往外找,找到所有的下游节点,我们发现可以是B、C、D,分别是2、8、6,这个时候就更新表:

A

B

C

D

0

2

8

6

然后A这个节点就被遍历过了,不需要再次遍历了,把A这个项close,从其余的所有项中找到最小值,然后以这个值为开始节点, 继续往下找,这里就是B节点。

B节点的下游是D,C,分别是1、4,但是因为从A出发时候到B,里面有了A到B的长度是2,所以A到D、C的长度就是3、6,我们发现比原来的值更小就更新表单,把B也close。

A

B

C

D

0

2

6

3

然后就发现现在距离最短的就是D,我们的目的地也是D,这个时候算法其实已经可以结束了。

简单总结一下就是:

  1. 从开始节点往下游找,更新维护一个open表,遍历完的节点进入close表;
  2. 从open表中找到不为-1,的最小值,作为新的开始节点找下游;
  3. 找到下游后要与之相比:
    1. 若下游节点OPEN表的值为-1,直接覆盖,并记录他的上游节点,为了之后追溯路径;
    2. 若下游节点OPNE表值不为-1,就把路径权值+开始节点的open表值与之相比,若比之较小便加入,并记录他的上游节点,为了之后追溯路径;
    3. 直到当前Open表中所有节点close,或open 表中最小的节点就是目标节点。

这也解释了为什么不可以在有负权,因为一旦有负数权重,就会导致之前的表单记录内容不再是“最小值”,尤其在带环的情况下,环最转,值越小,整个算法就会在环里自娱自乐。

代码

#include<iostream>
#include<string>
using namespace std;
class Node{
public:
	Node()
	{
		minL=100;//初始化最短路径为无穷大。
	}
	char node;//节点名称
	int minL;//当前节点的最短路径
	Node* last;//下一个节点
};//定义从一个节点类
 
void print(Node *node)//最短路径函数的递归打印
{
	if (node == NULL)
	{
		return;
	}
	print(node->last);/*递归调用,先打印前面的节点*/
    cout << node->node << "->";
}
 
int main()
{
 
	int wvalue[8][8];//定义路径权重	
for (int a = 0; a < 8; a++)
	{
		for (int b = 0; b < 8; b++)
		{
			wvalue[a][b] = 1000;//初始化权值,如若两个点没有连接则为无穷大。
		}
	}
    wvalue[0][1] = 2;//根据图来设置各个点之间的路径。
	wvalue[0][2] = 5;
	wvalue[0][3] = 4;
	wvalue[1][6] = 12;
	wvalue[1][2] = 2;
	wvalue[1][4] = 7;
	wvalue[2][3] = 1;
	wvalue[2][4] = 4;
	wvalue[2][5] = 3;
	wvalue[3][5] = 4;
	wvalue[4][5] = 1;
	wvalue[4][7] = 5;
	wvalue[5][7] = 7;
	wvalue[6][7] = 3;
	Node node[8];//定义节点变量
	node[0].node = 'O';//命名各个节点
	node[0].last = NULL;//初始化前一个节点为空
	node[1].node = 'A';
	node[2].node = 'B';
	node[3].node = 'C';
	node[4].node = 'D';
	node[5].node = 'E';
	node[6].node = 'F';
	node[7].node = 'T';
	Node u;//定义当前被访问的节点
	Node S[8];//辅助变量存储8个节点
    int a = 0;
	for (int i = 0; i < 8;i++) //第一个循环遍历这8个节点
{
		u = node[i];//当前被遍历的节点
		if (i==0)
		{
		 u.minL = 0;//初始化第一个结点的最短路径	
	    }
		S[i] = node[i];//储存被遍历的节点
		for (int j = 0;j<8; j++)//遍一个节点与其他8个节点的两个路径权值	
        {
			if (u.minL + wvalue[i][j] < node[j].minL)/*如果当前节点的最短路径加上该节点到相邻节点的权重小于其下一个节点路径的权重,则更新其下一个节点路径的最小距离*/	
        	{
				node[j].minL = u.minL + wvalue[i][j];
				node[j].last = &S[i];
 
			}
		}
}
	cout << node[7].minL << endl;//打印最短路径
	print(&node[7]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_32378713/article/details/128073478