1. 程式人生 > >淺談前向星

淺談前向星

net inf 存在 then 停止 換上 sizeof col idt

現在才搞懂前向星的遍歷,原來是要從後往前的!之後的一切都是以此為基礎的。

1.前向星的遍歷

看到有一篇blog寫的不錯:http://blog.csdn.net/acdreamers/article/details/16902023

技術分享

1 2

2 3

3 4

1 3

4 1

1 5

4 5

那麽排完序後就得到:

編號: 1 2 3 4 5 6 7

起點u: 1 1 1 2 3 4 4

終點v: 2 3 5 3 4 1 5

得到:

head[1] = 1 len[1] = 3

head[2] = 4 len[2] = 1

head[3] = 5 len[3] = 1

head[4] = 6 len[4] = 2

但是利用前向星會有排序操作,如果用快排時間至少為O(nlog(n))

如果用鏈式前向星,就可以避免排序.

特別註意:head[i]保存的是以i為起點的所有邊中編號最大的那個,而把這個當作頂點i的第一條起始邊的位置.

這樣在遍歷時是倒著遍歷的,也就是說與輸入順序是相反的,不過這樣不影響結果的正確性.

比如以上圖為例,以節點1為起點的邊有3條,它們的編號分別是0,3,5 而head[1] = 5

我們在遍歷以u節點為起始位置的所有邊的時候是這樣的:

for(int i=head[u];~i;i=edge[i].next)

那麽就是說先遍歷編號為5的邊,也就是head[1],然後就是edge[5].next,也就是編號3的邊,然後繼續edge[3].next,也

就是編號0的邊,可以看出是逆序的.

type rec=record
 pre,en,w:longint;
end;
var n,x,y,w,tot,i,cc:longint;
    a:array[0..10000]of rec;
    head:array[0..10000]of longint;
    p:integer;
procedure adde(u,v,w:longint);
begin
 inc(tot);a[tot].en:
=v; a[tot].pre:=head[u];head[u]:=tot; a[tot].w:=w; end; begin readln(n); fillchar(head,sizeof(head),255); fillchar(a,sizeof(a),255); for i:=1 to n do begin readln(x,y,w); adde(x,y,w); writeln(Edge ,i,: ,a[i].en, ,a[i].pre, ,head[i]); end; while true do begin readln(x); p:=head[x]; while p>0 do begin writeln(a[p].en); p:=a[p].pre; end; writeln; end; end.

2.前向星的作用之dijkstra算法的空間優化(時間優化為堆實現)

{鏈式前向星存儲+dijkstra+堆優化}
type rec=record
 pre,en,w:longint;
end;
rec2=record
 id,val:longint;
end;
const inf=233333333;
      maxm=500000;
      maxn=10000;
var i,j,n,m,s,x,y,z,tot,nd:longint;
    d,head:array[-maxn..maxn]of longint;
    a:array[-maxm..maxm]of rec;
    dui:array[0..4*maxm]of rec2;
procedure swap(var a,b:rec2);
var t:rec2;
begin
 t:=a; a:=b; b:=t;
end;
procedure adde(u,v,w:longint);
begin
 inc(tot); a[tot].en:=v;
 a[tot].pre:=head[u];
 head[u]:=tot;
 a[tot].w:=w;
end;
procedure swap(var a,b:longint);
var t:longint;
begin t:=a;a:=b;b:=t;end;
procedure up(x:longint);//將一個結點“上浮”
begin
  while x>1 do begin //沒有上浮到最頂層
    if dui[x].val>dui[x div 2].val then break;//如果上方的結點小於此節點,則暫停上浮
    swap(dui[x],dui[x div 2]);//交換上方結點與此結點
    x:=x div 2;
  end;
end;
procedure down(x:longint);//將一個節點“下沈”
  var y:longint;
begin
  while x<nd do begin
    y:=x+x;//y是x的左兒子
    if y>nd then break;//x已經沈到底部
    if (y<nd)and(dui[y+1].val<dui[y].val) then inc(y);//如果x存在右兒子,且右兒子比左兒子小,則將y賦值到右兒子
    if dui[x].val<=dui[y].val then break;//若兩個兒子中的較小值仍然比x大,則停止下沈
    swap(dui[x],dui[y]);//下沈
    x:=y;
  end;
end;
function pop():longint;
begin
  pop:=dui[1].id;
  swap(dui[1],dui[nd]);//將最後的結點(保證其沒有兒子)與最頂端交換
  dec(nd);
  down(1);//下沈頂端
end;
procedure dijkstra(v0:longint);
var i,j,k,minn,u,v,p:longint;
    vis:array[-maxn..maxn]of boolean;
begin
 fillchar(vis,sizeof(vis),false);
 for i:=1 to n do d[i]:=inf;
 d[v0]:=0;
 dui[1].val:=0;
 dui[1].id:=v0;
 nd:=1;
 for i:=1 to n do begin
  u:=pop();
  while vis[u] and (nd>0) do u:=pop();
  vis[u]:=true;
  p:=head[u];
  while p>0 do begin
   v:=a[p].en;
   if (not vis[v]) and(d[u]+a[p].w<d[v]) then begin
    d[v]:=d[u]+a[p].w;
    inc(nd);
    dui[nd].id:=v;
    dui[nd].val:=d[v];
    up(nd);
   end;
   p:=a[p].pre;
  end;
 end;
end;
begin
 readln(n,m,s);
 for i:=1 to m do begin
  readln(x,y,z);
  adde(x,y,z);
 end;
 dijkstra(s);
 for i:=1 to n do
 if d[i]=inf then write(2147483647, )else write(d[i], );
 writeln;
end.

淺談前向星