堆优化的dijkstra算法(以邻接表存储)

7 篇文章 0 订阅
7 篇文章 0 订阅

堆优化的dijkstra

  • 对于dijkstra为单源最短路的算法,其未优化版本为直接遍历每个点来寻找到源点最近的点,再以该点去更新与之相连的点,直到将每个点都利用更新其他点,这样便寻找到了从源点K出发的到每个点的最短路。

  • 对其优化,考虑到每次寻找最小距离的那个点去更新其他点,于此与最小根堆的性质相符,我们可以使用堆来取出最小距离元素,由此加速算法。 呃呃,请原谅我时间复杂度不会算╮(╯﹏╰)╭。

详细解释请参见代码;

代码如下


    program heap_dijkstra;
    type heaptype=record             {堆类型,其包含两个域,dist存储该点到源点的距离,point存储该点编号}
          dist,point:longint;
         end;
         link=^rec;                  {指针类型,基类型为记录,包含三个域,v为权值,s为起点,e为终点}
         rec=record                    
          e,v:longint;
          s:link;
         end;
    var heap:array[1..1000] of heaptype;    {堆}
        reflect:array[1..1000] of longint;  {堆中位置映射}
        visited:array[1..1000] of boolean;  {访问标记}
        tot,i,j,k,m,n,s,e,v:longint;        
        vertex:array[1..1000] of link;      {点集}
        temp:heaptype;
        p:link;
    procedure insert(s,e,v:longint);    {创建邻接表}
    var p:link;
    begin
     new(p);
     p^.e:=e;
     p^.v:=v;
     p^.s:=vertex[s];
     vertex[s]:=p;
    end;

    procedure up(head,j:longint);      {堆向上调整}
    var i:longint;
    begin
     while (j>>1)>=head do
      begin
       i:=j>>1;
       if heap[i].dist>heap[j].dist
        then
         begin
          temp:=heap[i];
          heap[i]:=heap[j];
          heap[j]:=temp;
          reflect[heap[i].point]:=i;
          reflect[heap[j].point]:=j;
          j:=i;
         end
        else
         break;
      end;
    end;

    procedure down(i,rear:longint);   {堆向下调整}
    var j:longint;
    begin
     while (i<<1)<=rear do
      begin
      j:=i<<1;
      if (j<rear) and (heap[j].dist>heap[j+1].dist) then inc(j);
      if heap[i].dist>heap[j].dist
       then
        begin
         temp:=heap[i];
         heap[i]:=heap[j];
         heap[j]:=temp;
         reflect[heap[i].point]:=i;
         reflect[heap[j].point]:=j;
         i:=j;
        end
       else
        break;
     end;
    end;

    begin
     assign(input,'D:/input/heap_dijkstra.txt');{呃呃,文件可以直接略过}
     reset(input);
     assign(output,'D:/output/heap_dijkstra.txt');
     rewrite(output);
     readln(n,m,k);
     for i:=1 to n do vertex[i]:=nil;
     for i:=1 to m do
      begin
       readln(s,e,v);
       insert(s,e,v);
      end;
     fillchar(visited,sizeof(visited),false);
     for i:=1 to k-1 do {初始化堆,因为源点k无需入堆,所以第k个位置断开,k之前存的不变而k及k之后的位置存储后一个点,K让出了一个空}
      begin
       heap[i].dist:=maxlongint; {堆位置为i的到源点距离}
       heap[i].point:=i;{映射   堆位置为i的存储的点编号为多少}
       reflect[i]:=i;   {映射   编号为i的点在堆中的位置为多少}
      end;
     for i:=k+1 to n do
      begin
       heap[i-1].dist:=maxlongint;
       heap[i-1].point:=i;
       reflect[i]:=i-1;
      end;
     p:=vertex[k];
     while p<>nil do {创建表,存储源点相连点的最短路径,肯定一步到达,且还会后续更新}
      begin
       if p^.v<heap[reflect[p^.e]].dist
        then
         begin
          heap[reflect[p^.e]].dist:=p^.v;
          up(1,reflect[p^.e]);
         end;
       p:=p^.s;
      end;
     visited[k]:=true;
     tot:=n-1;
     heap[n].dist:=0;
     heap[n].point:=k;
     reflect[k]:=n;
     while true do      {Dijkstra 主程序  }
      begin
       if (heap[1].dist=maxlongint) 
       or (visited[heap[1].point]) 
        then break; 
    {当堆首元素距离为maxlongint,或堆首都以访问肯定堆已经空}
       p:=vertex[heap[1].point];
       while p<>nil do
        begin
         if heap[1].dist+p^.v<heap[reflect[p^.e]].dist
          then
           begin
            heap[reflect[p^.e]].dist:=heap[1].dist+p^.v;
            up(1,reflect[p^.e]);
           end;
         p:=p^.s;
        end;
       {接下来出堆操作}
       visited[heap[1].point]:=true;
       temp:=heap[1];
       heap[1]:=heap[tot];
       heap[tot]:=temp;
       reflect[heap[1].point]:=1;
       reflect[heap[tot].point]:=tot;
       dec(tot);
       down(1,tot);
      end;
     for i:=1 to n do
      begin
       write(heap[reflect[i]].dist,' ');  
      end;
     close(input);
     close(output);
    end.

希望有用。 有错误请指出,O(∩_∩)O谢谢。;

每日一句

从蛹破茧而出的瞬间,是撕掉一层皮的痛苦彻心彻肺 很多蝴蝶都是在破茧而出的那一刻 被痛得死掉了。

这句话就如马云说的一样。。。

未来就在眼前,放弃只会失去一切希望。

未来就在手中

加油↖(^ω^)↗

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值