Dijkstra算法的堆实现

本文详细介绍了如何使用最小堆实现Dijkstra算法,以求解图中每个节点到源节点的最短路径。文中提供了节点类和边类的定义,并通过C++代码实现了堆的维护、数据初始化和主算法过程。

/**

使用最小堆实现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();

}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值