📄 dijkstra.cpp
字号:
}
} while (Temp != NULL && Temp != Tree);
mexPrintf( "\n" );
Temp = Tree;
do {
mexPrintf( "Children of " );
Temp->Print();
mexPrintf( ": " );
if (Temp->Child == NULL)
mexPrintf( "NONE\n" );
else Print(Temp->Child, Temp);
Temp = Temp->Right;
} while (Temp!=NULL && Temp != Tree);
if (theParent == NULL)
{
char ch;
mexPrintf( "\n\n\n" );
cin >> ch;
}
}
//===========================================================================
//===========================================================================
void FibHeap::_Exchange(FibHeapNode*& N1, FibHeapNode*& N2)
{
FibHeapNode *Temp;
Temp = N1;
N1 = N2;
N2 = Temp;
}
//===========================================================================
// Consolidate()
//
// Internal function that reorganizes heap as part of an ExtractMin().
// We must find new minimum in heap, which could be anywhere along the
// root list. The search could be O(n) since all nodes could be on
// the root list. So, we reorganize the tree into more of a binomial forest
// structure, and then find the new minimum on the consolidated O(lg n) sized
// root list, and in the process set each Parent pointer to NULL, and count
// the number of resulting subtrees.
//
// Note that after a list of n inserts, there will be n nodes on the root
// list, so the first ExtractMin() will be O(n) regardless of whether or
// not we consolidate. However, the consolidation causes subsequent
// ExtractMin() operations to be O(lg n). Furthermore, the extra cost of
// the first ExtractMin() is covered by the higher amortized cost of
// Insert(), which is the real governing factor in how costly the first
// ExtractMin() will be.
//===========================================================================
void FibHeap::_Consolidate()
{
FibHeapNode *x, *y, *w;
FibHeapNode *A[1+8*sizeof(long)]; // 1+lg(n)
int I=0, Dn = 1+8*sizeof(long);
short d;
// Initialize the consolidation detection array
for (I=0; I < Dn; I++)
A[I] = NULL;
// We need to loop through all elements on root list.
// When a collision of degree is found, the two trees
// are consolidated in favor of the one with the lesser
// element key value. We first need to break the circle
// so that we can have a stopping condition (we can't go
// around until we reach the tree we started with
// because all root trees are subject to becoming a
// child during the consolidation).
MinRoot->Left->Right = NULL;
MinRoot->Left = NULL;
w = MinRoot;
do {
//cout << "Top of Consolidate's loop\n";
//Print(w);
x = w;
d = x->Degree;
w = w->Right;
// We need another loop here because the consolidated result
// may collide with another large tree on the root list.
while (A[d] != NULL)
{
y = A[d];
if (*y < *x)
_Exchange(x, y);
if (w == y) w = y->Right;
_Link(y, x);
A[d] = NULL;
d++;
//cout << "After a round of Linking\n";
//Print(x);
}
A[d] = x;
} while (w != NULL);
// Now we rebuild the root list, find the new minimum,
// set all root list nodes' parent pointers to NULL and
// count the number of subtrees.
MinRoot = NULL;
NumTrees = 0;
for (I = 0; I < Dn; I++)
if (A[I] != NULL)
_AddToRootList(A[I]);
}
//===========================================================================
// The node y is removed from the root list and becomes a subtree of node x.
//===========================================================================
void FibHeap::_Link(FibHeapNode *y, FibHeapNode *x)
{
// Remove node y from root list
if (y->Right != NULL)
y->Right->Left = y->Left;
if (y->Left != NULL)
y->Left->Right = y->Right;
NumTrees--;
// Make node y a singleton circular list with a parent of x
y->Left = y->Right = y;
y->Parent = x;
// If node x has no children, then list y is its new child list
if (x->Child == NULL)
x->Child = y;
// Otherwise, node y must be added to node x's child list
else
{
y->Left = x->Child;
y->Right = x->Child->Right;
x->Child->Right = y;
y->Right->Left = y;
}
// Increase the degree of node x because it's now a bigger tree
x->Degree ++;
// Node y has just been made a child, so clear its mark
if (y->Mark) NumMarkedNodes--;
y->Mark = 0;
}
//===========================================================================
//===========================================================================
void FibHeap::_AddToRootList(FibHeapNode *x)
{
if (x->Mark) NumMarkedNodes --;
x->Mark = 0;
NumNodes--;
Insert(x);
}
//===========================================================================
// Remove node x from the child list of its parent node y
//===========================================================================
void FibHeap::_Cut(FibHeapNode *x, FibHeapNode *y)
{
if (y->Child == x)
y->Child = x->Right;
if (y->Child == x)
y->Child = NULL;
y->Degree --;
x->Left->Right = x->Right;
x->Right->Left = x->Left;
_AddToRootList(x);
}
//===========================================================================
// Cuts each node in parent list, putting successive ancestor nodes on the
// root list until we either arrive at the root list or until we find an
// ancestor that is unmarked. When a mark is set (which only happens during
// a cascading cut), it means that one child subtree has been lost; if a
// second subtree is lost later during another cascading cut, then we move
// the node to the root list so that it can be re-balanced on the next
// consolidate.
//===========================================================================
void FibHeap::_CascadingCut(FibHeapNode *y)
{
FibHeapNode *z = y->Parent;
while (z != NULL)
{
if (y->Mark == 0)
{
y->Mark = 1;
NumMarkedNodes++;
z = NULL;
}
else
{
_Cut(y, z);
y = z;
z = y->Parent;
}
}
}
class HeapNode : public FibHeapNode
{
double N;
long int IndexV;
public:
HeapNode() : FibHeapNode() { N = 0; };
virtual void operator =(FibHeapNode& RHS);
virtual int operator ==(FibHeapNode& RHS);
virtual int operator <(FibHeapNode& RHS);
virtual void operator =(double NewKeyVal );
virtual void Print();
double GetKeyValue() { return N; }; /* !!!! */
void SetKeyValue(double n) { N = n; };
long int GetIndexValue() { return IndexV; };
void SetIndexValue( long int v) { IndexV = v; };
};
void HeapNode::Print()
{
FibHeapNode::Print();
mexPrintf( "%f (%d)" , N , IndexV );
}
void HeapNode::operator =(double NewKeyVal)
{
HeapNode Temp;
Temp.N = N = NewKeyVal;
FHN_Assign(Temp);
}
void HeapNode::operator =(FibHeapNode& RHS)
{
FHN_Assign(RHS);
N = ((HeapNode&) RHS).N;
}
int HeapNode::operator ==(FibHeapNode& RHS)
{
if (FHN_Cmp(RHS)) return 0;
return N == ((HeapNode&) RHS).N ? 1 : 0;
}
int HeapNode::operator <(FibHeapNode& RHS)
{
int X;
if ((X=FHN_Cmp(RHS)) != 0)
return X < 0 ? 1 : 0;
return N < ((HeapNode&) RHS).N ? 1 : 0;
};
int IntCmp(const void *pA, const void *pB)
{
int A, B;
A = *((const int *) pA);
B = *((const int *) pB);
if (A < B) return -1;
if (A == B) return 0;
return 1;
}
void dodijk_sparse(
long int M,
long int N,
long int S,
double *D,
double *sr,
int *irs,
int *jcs,
HeapNode *A,
FibHeap *theHeap )
{
int finished;
long int i,startind,endind,whichneighbor,ndone,index,switchwith,closest,closesti;
long int *INDICES;
double closestD,arclength;
double INF,SMALL,olddist;
HeapNode *Min;
HeapNode Temp;
INF = mxGetInf();
SMALL = mxGetEps();
/* initialize */
for (i=0; i<M; i++)
{
if (i!=S) A[ i ] = (double) INF; else A[ i ] = (double) SMALL;
if (i!=S) D[ i ] = (double) INF; else D[ i ] = (double) SMALL;
theHeap->Insert( &A[i] );
A[ i ].SetIndexValue( (long int) i );
}
// Insert 0 then extract it. This will cause the
// Fibonacci heap to get balanced.
theHeap->Insert(&Temp);
theHeap->ExtractMin();
/*theHeap->Print();
for (i=0; i<M; i++)
{
closest = A[ i ].GetIndexValue();
closestD = A[ i ].GetKeyValue();
mexPrintf( "Index at i=%d =%d value=%f\n" , i , closest , closestD );
}*/
/* loop over nonreached nodes */
finished = 0;
ndone = 0;
while ((finished==0) && (ndone < M))
{
//if ((ndone % 100) == 0) mexPrintf( "Done with node %d\n" , ndone );
Min = (HeapNode *) theHeap->ExtractMin();
closest = Min->GetIndexValue();
closestD = Min->GetKeyValue();
if ((closest<0) || (closest>=M)) mexErrMsgTxt( "Minimum Index out of bound..." );
//theHeap->Print();
//mexPrintf( "EXTRACTED MINIMUM NDone=%d S=%d closest=%d closestD=%f\n" , ndone , S , closest , closestD );
//mexErrMsgTxt( "Exiting..." );
D[ closest ] = closestD;
if (closestD == INF) finished=1; else
{
/* add the closest to the determined list */
ndone++;
/* relax all nodes adjacent to closest */
startind = jcs[ closest ];
endind = jcs[ closest+1 ] - 1;
if (startind!=endind+1)
for (i=startind; i<=endind; i++)
{
whichneighbor = irs[ i ];
arclength = sr[ i ];
olddist = D[ whichneighbor ];
//mexPrintf( "INSPECT NEIGHBOR #%d olddist=%f newdist=%f\n" , whichneighbor , olddist , closestD+arclength );
if ( olddist > ( closestD + arclength ))
{
D[ whichneighbor ] = closestD + arclength;
Temp = A[ whichneighbor ];
Temp.SetKeyValue( closestD + arclength );
theHeap->DecreaseKey( &A[ whichneighbor ], Temp );
//mexPrintf( "UPDATING NODE #%d olddist=%f newdist=%f\n" , whichneighbor , olddist , closestD+arclength );
}
}
}
}
}
void mexFunction(
int nlhs,
mxArray *plhs[],
int nrhs,
const mxArray *prhs[]
)
{
double *sr,*D,*P,*SS,*Dsmall,*Psmall;
int *irs,*jcs;
long int M,N,S,MS,NS,i,j,in;
HeapNode *A = NULL;
FibHeap *theHeap = NULL;
if (nrhs != 2)
{
mexErrMsgTxt( "Only 2 input arguments allowed." );
}
else if (nlhs != 1)
{
mexErrMsgTxt( "Only 1 output argument allowed." );
}
M = mxGetM( prhs[0] );
N = mxGetN( prhs[0] );
if (M != N) mexErrMsgTxt( "Input matrix needs to be square." );
SS = mxGetPr(prhs[1]);
MS = mxGetM( prhs[1] );
NS = mxGetN( prhs[1] );
if ((MS==0) || (NS==0) || ((MS>1) && (NS>1))) mexErrMsgTxt( "Source nodes are specified in one dimensional matrix only" );
if (NS>MS) MS=NS;
plhs[0] = mxCreateDoubleMatrix( MS,M, mxREAL);
D = mxGetPr(plhs[0]);
Dsmall = (double *) mxCalloc( M , sizeof( double ));
if (mxIsSparse( prhs[ 0 ] ) == 1)
{
/* dealing with sparse array */
sr = mxGetPr(prhs[0]);
irs = mxGetIr(prhs[0]);
jcs = mxGetJc(prhs[0]);
// Setup for the Fibonacci heap
for (i=0; i<MS; i++)
{
if ((theHeap = new FibHeap) == NULL || (A = new HeapNode[M+1]) == NULL )
{
mexErrMsgTxt( "Memory allocation failed-- ABORTING.\n" );
}
theHeap->ClearHeapOwnership();
S = (long int) *( SS + i );
S--;
if ((S < 0) || (S > M-1)) mexErrMsgTxt( "Source node(s) out of bound" );
/* -------------------------------------------------------------------------------------------------
run the dijkstra code
------------------------------------------------------------------------------------------------- */
//mexPrintf( "Working on i=%d\n" , i );
dodijk_sparse( M,N,S,Dsmall,sr,irs,jcs,A,theHeap );
for (j=0; j<M; j++)
{
*( D + j*MS + i ) = *( Dsmall + j );
//mexPrintf( "Distance i=%d to j=%d =%f\n" , S+1 , j , *( Dsmall + j ) );
}
/* -------------------------------------------------------------------------------------------------
end of the dijkstra code
------------------------------------------------------------------------------------------------- */
delete theHeap;
delete[] A;
}
} else mexErrMsgTxt( "Function not implemented for full arrays" );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -