/**
使用最小堆实现Dijkstra算法,图的表示是邻接表表示
这边只是求出每一个节点到源节点的最短路径,并没有记录父节点,用来生成最短路径
**/
#include <iostream>
using namespace std;
#define MAX_NODES 1000 //定义最多的节点数
#define MAX_COST 10000 //定义边的最大的权值
//节点类
class Edge;
class Node
{
public:
int index ; //节点在堆中的下标,因为堆是在不断调整的。如果节点的最小的权值改变后需要调整堆的时候根据index获得节点在堆中的下标
Edge * first; //这个节点连接的边中的第一条
Node (int index ):index(index),first(NULL){}
Node(){}
};
//边类
class Edge
{
public:
double cost ; //每条边的权值
int head ,tail; //边的头尾节点
Edge * next; //同一个节点的下一条边
Edge (int head,int tail ,double cost):head(head),tail(tail),cost(cost),next(NULL){}
};
double mincost [MAX_NODES]; //存储的是每一条边的最小的权值
int nodeheap[MAX_NODES]; //节点生成的堆,存储的是每一个堆的下标
Node node[MAX_NODES]; //这边是图的存储中的每一个节点
int nodes; //图中实际的节点数
int edges; //堆中边数
int s ; //最短路的源节点
void min_heapify(int index) //index是需要调整的最小的下标
{
int i = index;
int l = 2 * i + 1;
int r = 2 * i + 2;
if(l < nodes && mincost[nodeheap[l]] < mincost [nodeheap[i]])
i = l;
if(r < nodes && mincost[nodeheap[r]] < mincost [nodeheap[i]])
i = r;
if(i != index)
{
int tem = nodeheap[i];
nodeheap[i] = nodeheap[index];
nodeheap[index] = tem;
node[nodeheap[index]].index = index; //他们在堆中的下标改变了,需要更新他们的index
node[nodeheap[i]].index = i;
min_heapify(i);
}
}
void make_heap( )
{
for(int i = 0;i < nodes; i++)
nodeheap[i] = i;
for(int i = nodes/2 ; i >= 0 ; i--)
min_heapify(i);
}
//这边假定的输入格式是源节点,节点数,边数,然后跟着的是每一条边(头尾节点,权值)
void init()
{
//读入数据
cin >>s >> nodes >> edges ;
for(int i = 0 ;i < nodes; i++)
node[i] = Node(i);
for(int i = 0 ; i < edges ;i ++)
{
int head , tail;
double cost ;
cin >> head >> tail >> cost ;
Edge * e = new Edge(head,tail,cost);
e->next = node[head].first;
node[head].first = e;
}
//对mincost和nodeheap初始化
for(int i = 0 ; i < nodes; i++)
mincost [i] = MAX_COST;
mincost [s]= 0;
Edge * e = node[s].first;
while(e!=NULL)
{
mincost [e->tail] = e->cost;
e = e->next;
}
make_heap();
}
//主算法
void dijk()
{
init();
while(nodes > 0)
{
int minindex = nodeheap[0];
Edge * e = node[minindex].first;
while(e != NULL)
{
int head = e->head;
int tail = e->tail;
double cost = e->cost;
if((cost + mincost [head])<mincost[tail]) //如果到tail节点有更短的路径,那么就用新的路径值替换原来的
{
mincost [tail] = cost + mincost [head];
for(int i = node[tail].index; i>=0;i--) //tail值改变后需要调整堆保持性质
min_heapify(i);
}
e = e->next;
}
nodes--;
nodeheap[0] = nodeheap[nodes-1];
min_heapify(0);
}
}
/**
测试数据:
0
5
7
0 1 10
0 3 30
0 4 100
1 2 50
2 4 10
3 2 20
3 4 60
**/
void test()
{
::dijk();
for(int i = 0 ;i < 5 ;i ++)
cout << mincost[i] <<" --- " ;
cout << endl;
}
int main()
{
test();
}
本文详细介绍了如何使用最小堆实现Dijkstra算法,以求解图中每个节点到源节点的最短路径。文中提供了节点类和边类的定义,并通过C++代码实现了堆的维护、数据初始化和主算法过程。
1410

被折叠的 条评论
为什么被折叠?



