问题
I am trying to implement Dijkstra algorithm.
foreach distance d
d = INFINITY
d[source] = 0
create_heap_based_on_Distances();
while(true)
bestedge = heap[0]
remove_minimum_from_heap //it will be heap[0]
foreach adjacency of bestedge
if (weight + bestedge_distance < current_distance)
{
current_distance = weight + bestedge_distance
// Now I have to update heap, how can I do that?
}
if (heap_empty) break
So, in the relaxation, how can I update the heap, so it would have the correct order? I don't have the heap's index for that node in that step. Does that mean I have to create a new array like nodes[edge] = heapIndex
, so I could get a heap's index for that node? But it seems very inefficient as I need then to update insert_to_heap
, remove_minimum
functions.
C or JAVA code is okay.
回答1:
Does that mean I have to create a new array like nodes[edge] = heapIndex, so I could get a heap's index for that node?
Yes.
But it seems very inefficient as I need then to update insert_to_heap, remove_minimum functions.
Array updates are very cheap, both in theory and in practice, and you only have to do a few of those per heap operation, so this is not inefficient at all. Also, the memory usage of such an array is very cheap compared to the storage cost of a graph data structure.
回答2:
Does that mean I have to create a new array like nodes[edge] = heapIndex,
so I could get a heap's index for that node?
I don't what the exactly mean of node[edge]. In my opinion, it should be a Map(a array indeed) f that f[node]=HeapIndex(It gives the index of that node in Heap). Storage of the node[edge] is not efficient.
Then how to implement the MapHeap? I have implemented a efficient MapHeap, but not so much note in the code:
template<class DT>
struct MapHeap
{
DT f[HEAP_SIZE+5];//store the distance
int mp1[HEAP_SIZE+5];//val -> index
// I assume the val is unique.
// In the dijk, the val is the nodeId,so it must be unique.
// mp1[nodeId] gives the index of that node in my heap
int mp2[HEAP_SIZE+5];//index -> val
int nv;// number of node in my heap now
MapHeap():nv(0)
{
memset(mp1,-1,sizeof(mp1));
memset(mp2,-1,sizeof(mp2));
}
void print(int n)
{
for(int i=1;i<=n;i++) printf("%d ",f[i]);
puts("");
for(int i=1;i<=n;i++) printf("%d ",mp1[i]);
puts("");
for(int i=1;i<=n;i++) printf("%d ",mp2[i]);
puts("");
}
void print(){print(nv);}
bool resize(int n)
{
if (nv<0||nv>HEAP_SIZE) return 0;
for(int i=n+1;i<=nv;i++)
{
mp1[mp2[i]]=-1;
mp2[i]=-1;
}
nv=n;
return 1;
}
DT top()//get the smallest element
{
if (nv<1) return DT(-1);
return f[1];
}
DT get(int idx)
{
if (idx<1||idx>nv) return DT(-1);
return f[idx];
}
// it's for unpdating the heap. It should be pravite method.
// Because I write this code for competition, so I just ignore the accsee controling
void movedown(int now,int val,const DT &x)//this node is larger than son
{
for(;now*2<=nv;)
{
int a=now*2;
int b=now*2+1;
if (b<=nv&&f[b]<f[a]) a=b;
if (f[a]>=x) break;
f[now]=f[a];
mp1[mp2[a]]=now;
mp2[now]=mp2[a];
now=a;
}
f[now]=x;
mp1[val]=now;
mp2[now]=val;
}
void moveup(int now,int val,const DT &x)//this node is smaller than father
{
for(;now>1;now>>=1)
{
int par=now>>1;
if (f[par]<=x) break;
f[now]=f[par];
mp1[mp2[par]]=now;
mp2[now]=mp2[par];
}
f[now]=x;
mp1[val]=now;
mp2[now]=val;
}
bool pop(int idx=1)//pop a element, pop the smallest element by default
{
if (idx<1||idx>nv) return 0;
DT &x=f[nv];
int v1=mp2[nv];
int v2=mp2[idx];
mp1[v1]=idx;
mp2[idx]=v1;
mp1[v2]=-1;
mp2[nv]=-1;
nv--;
if (idx!=nv+1) movedown(idx,v1,x);
x=0;
return 1;
}
bool push(const DT &x,int val)//push a node, and with the value of val(in dijk, the val is the nodeId of that node)
{
int now=++nv;
if (now>HEAP_SIZE) return 0;
moveup(now,val,x);
return 1;
}
};
来源:https://stackoverflow.com/questions/16217261/dijkstra-with-a-heap-how-to-update-the-heap-after-relaxation