Dijkstra最短路径算法(针对加权有向图)

indexMinPQ.h

#ifndef _INDEX_MIN_PQ_H_
#define _INDEX_MIN_PQ_H_

#define INDEX_MIN_PQ_TEST  0

typedef struct
{
    int     index;
    double  cmpNum;
} INDEX_MIN_PQ_DATA;

typedef struct
{
    int                 n;
    int                 maxN;
    INDEX_MIN_PQ_DATA*  data;
} INDEX_MIN_PQ;

void  indexMinPQInit(INDEX_MIN_PQ* pIndexMinPQ, int maxN);
void  indexMinPQUninit(INDEX_MIN_PQ* pIndexMinPQ);
int   indexMinPQInert(INDEX_MIN_PQ* pIndexMinPQ, int index, double cmpNum);
int   indexMinPQDelMin(INDEX_MIN_PQ* pIndexMinPQ);
int   indexMinPQIsEmpty(INDEX_MIN_PQ* pIndexMinPQ);
int   indexMinPQContains(INDEX_MIN_PQ* pIndexMinPQ, int index);
int   indexMinPQChange(INDEX_MIN_PQ* pIndexMinPQ, int index, double cmpNum);

#endif

indexMinPQ.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "indexMinPQ.h"

//最小优先队列初始化
void  indexMinPQInit(INDEX_MIN_PQ* pIndexMinPQ, int maxN)
{
    if ( pIndexMinPQ == NULL )
    {
        return; 
    }

    pIndexMinPQ->data = (INDEX_MIN_PQ_DATA *)malloc(sizeof(INDEX_MIN_PQ_DATA) * maxN);
    if ( pIndexMinPQ->data == NULL )
    {
        printf("failed to malloc\r\n");
        return; 
    }

    pIndexMinPQ->maxN = maxN;
    pIndexMinPQ->n = 0;
}

//最小优先队列去初始化
void  indexMinPQUninit(INDEX_MIN_PQ* pIndexMinPQ)
{
    if ( pIndexMinPQ == NULL )
    {
        return; 
    }

    if ( pIndexMinPQ->data != NULL )
    {
        free(pIndexMinPQ->data); 
        pIndexMinPQ->data = NULL;
    }

    memset(pIndexMinPQ, 0, sizeof(INDEX_MIN_PQ));
}

//最小优先队列的元素比较,是否小于
static int indexMinPQisLess(INDEX_MIN_PQ* pIndexMinPQ, int x, int y)
{
    if ( pIndexMinPQ == NULL )
    {
        return 0; 
    }

    return pIndexMinPQ->data[x].cmpNum < pIndexMinPQ->data[y].cmpNum;
}

//最小优先队列的元素交换
static void indexMinPQExchange(INDEX_MIN_PQ* pIndexMinPQ, int x, int y)
{
    INDEX_MIN_PQ_DATA tmpData = {0};

    if ( pIndexMinPQ == NULL )
    {
        return; 
    }

    tmpData.index = pIndexMinPQ->data[x].index;
    tmpData.cmpNum = pIndexMinPQ->data[x].cmpNum;

    pIndexMinPQ->data[x].index = pIndexMinPQ->data[y].index;
    pIndexMinPQ->data[x].cmpNum = pIndexMinPQ->data[y].cmpNum;

    pIndexMinPQ->data[y].index = tmpData.index;
    pIndexMinPQ->data[y].cmpNum = tmpData.cmpNum;
}

//最小优先队列指定索引的上升有序化
static void indexMinPQSwim(INDEX_MIN_PQ* pIndexMinPQ, int k)
{
    while ( k > 1 && indexMinPQisLess(pIndexMinPQ, k, k/2) )
    {
        indexMinPQExchange(pIndexMinPQ, k/2, k);
        k = k/2;
    }
}

//最小优先队列指定索引的下沉有序化
static void indexMinPQSink(INDEX_MIN_PQ* pIndexMinPQ, int k)
{
    while ( (k*2) <= pIndexMinPQ->n )
    {
        void* tmp = NULL;
        int j = k * 2;

        //如果存在右孩子,则先找出两个孩子之间的最小值
        if ( (j < pIndexMinPQ->n) && indexMinPQisLess(pIndexMinPQ, j+1, j) )
        { 
            j++;
        }

        //之后在比较当前父亲与最小的孩子之间的最小值
        if ( !indexMinPQisLess(pIndexMinPQ, j, k) )
        {
            break; 
        }

        indexMinPQExchange(pIndexMinPQ, k, j);

        k = j;
    }
}

//向最小优先队列中插入元素
//1、首先将元素插入到堆末尾
//2、之后比较新的元素是否小于父元素,如果小于,则不断进行上浮处理,直到孩子不再小于
//   父亲为止,或者已经上俘到最顶端。
int indexMinPQInert(INDEX_MIN_PQ* pIndexMinPQ, int index, double cmpNum)
{
    if ( pIndexMinPQ->n >= pIndexMinPQ->maxN )
    {
        printf("already full.\r\n"); 
        return -1;
    }

    //数组索引0没有使用,直接从1开始,主要是
    //方便计算孩子、父亲索引之间的关系
    pIndexMinPQ->n++;
    pIndexMinPQ->data[pIndexMinPQ->n].index = index;
    pIndexMinPQ->data[pIndexMinPQ->n].cmpNum = cmpNum;

    indexMinPQSwim(pIndexMinPQ, pIndexMinPQ->n);

    return 0;
}

//删除最小优先队列的最小值
//1、头部的最小值取出后,将尾部的元素填充到头部
//2、进行尾部复位,及减小总元素个数
//3、对头部元素进行下降处理
int indexMinPQDelMin(INDEX_MIN_PQ* pIndexMinPQ)
{
    int retIndex = -1;

    if ( indexMinPQIsEmpty(pIndexMinPQ) )
    {
        printf("already empty.\r\n");
        return -1; 
    }

    //数组索引0没有使用,直接从1开始,主要是
    //方便计算孩子、父亲索引之间的关系
    retIndex = pIndexMinPQ->data[1].index; 
    indexMinPQExchange(pIndexMinPQ, 1, pIndexMinPQ->n);

    pIndexMinPQ->n--;

    indexMinPQSink(pIndexMinPQ, 1);

    return retIndex;
}

//检查最小优先队列是否为空
int indexMinPQIsEmpty(INDEX_MIN_PQ* pIndexMinPQ)
{
    if ( pIndexMinPQ == NULL )
    {
        return 1; 
    }

    return pIndexMinPQ->n <= 0;
}

//查找匹配最小优先队列数据index的数组索引
static int indexMinPQGetDataArrayIndex(INDEX_MIN_PQ* pIndexMinPQ, int index)
{
    int i = 0;

    if ( pIndexMinPQ == NULL )
    {
        return 0; 
    }

    //数组索引0没有使用,直接从1开始,主要是
    //方便计算孩子、父亲索引之间的关系
    for ( i = 1; i <= pIndexMinPQ->n; i++ )
    {
        if ( pIndexMinPQ->data[i].index == index ) 
        {
            return i; 
        }
    }

    return 0;
}

//检查最小优先队列是否含有该数据index
int indexMinPQContains(INDEX_MIN_PQ* pIndexMinPQ, int index)
{
    return indexMinPQGetDataArrayIndex(pIndexMinPQ, index) > 0;
}

//最小优先队列中指定数据的比较值进行了更改
int indexMinPQChange(INDEX_MIN_PQ* pIndexMinPQ, int index, double cmpNum)
{
    int dataArrayIndex = -1;

    if ( pIndexMinPQ == NULL )
    {
        return -1; 
    }

    dataArrayIndex = indexMinPQGetDataArrayIndex(pIndexMinPQ, index);
    if ( dataArrayIndex == 0 )
    {
        return -1; 
    }

    if ( cmpNum > pIndexMinPQ->data[dataArrayIndex].cmpNum )
    {
        pIndexMinPQ->data[dataArrayIndex].cmpNum = cmpNum;
        indexMinPQSink(pIndexMinPQ, dataArrayIndex);
    }
    else if ( cmpNum < pIndexMinPQ->data[dataArrayIndex].cmpNum )
    {
        pIndexMinPQ->data[dataArrayIndex].cmpNum = cmpNum;
        indexMinPQSwim(pIndexMinPQ, dataArrayIndex);
    }
    
    return 0;
}

#if INDEX_MIN_PQ_TEST
int main()
{
    INDEX_MIN_PQ indexMinPQObj = {0};

    indexMinPQInit(&indexMinPQObj, 10);

    indexMinPQInert(&indexMinPQObj, 0, 1.4);
    indexMinPQInert(&indexMinPQObj, 1, 5.9);
    indexMinPQInert(&indexMinPQObj, 2, 2.8);
    indexMinPQInert(&indexMinPQObj, 3, 7.1);
    indexMinPQInert(&indexMinPQObj, 4, 9.4);
    indexMinPQInert(&indexMinPQObj, 5, 2.2);
    indexMinPQInert(&indexMinPQObj, 6, 5.2);
    indexMinPQInert(&indexMinPQObj, 7, 1.6);
    indexMinPQInert(&indexMinPQObj, 8, 6.3);

    printf("have index %d : %s\r\n", 8, \
            indexMinPQContains(&indexMinPQObj, 8) ? "TRUE" : "FALSE");
    printf("have index %d : %s\r\n", 9, \
            indexMinPQContains(&indexMinPQObj, 9) ? "TRUE" : "FALSE");

    indexMinPQChange(&indexMinPQObj, 3, 0.4);
    indexMinPQChange(&indexMinPQObj, 6, 6.6);

    printf("[0] delete index %d.\r\n", indexMinPQDelMin(&indexMinPQObj));
    printf("[1] delete index %d.\r\n", indexMinPQDelMin(&indexMinPQObj));
    printf("[2] delete index %d.\r\n", indexMinPQDelMin(&indexMinPQObj));
    printf("[3] delete index %d.\r\n", indexMinPQDelMin(&indexMinPQObj));
    printf("[4] delete index %d.\r\n", indexMinPQDelMin(&indexMinPQObj));
    printf("[5] delete index %d.\r\n", indexMinPQDelMin(&indexMinPQObj));
    printf("[6] delete index %d.\r\n", indexMinPQDelMin(&indexMinPQObj));
    printf("[7] delete index %d.\r\n", indexMinPQDelMin(&indexMinPQObj));
    printf("[8] delete index %d.\r\n", indexMinPQDelMin(&indexMinPQObj));
    printf("[9] delete index %d.\r\n", indexMinPQDelMin(&indexMinPQObj));

    indexMinPQUninit(&indexMinPQObj);

    return 0;
}
#endif

directedEdge.h

#ifndef _DIRECTED_EDGE_H_
#define _DIRECTED_EDGE_H_

#define DIRECTED_EDGE_TEST  0

typedef struct
{
    int     from;       //加权有向边的一个顶点
    int     to;         //加权有向边的另一个顶点
    double  weight;     //加权有向边的权重
} DIRECTED_EDGE;

void    directedEdgeInit(DIRECTED_EDGE* pDiedge, int v, int w, double weight);
int     directedEdgeGetFrom(DIRECTED_EDGE* pDiedge);
int     directedEdgeGetTo(DIRECTED_EDGE* pDiedge);
int     directedEdgeIsValid(DIRECTED_EDGE* pDiedge);
double  directedEdgeGetWeight(DIRECTED_EDGE* pDiedge);
void    directedEdgeDump(DIRECTED_EDGE* pDiedge);

#endif

directedEdge.c

#include <stdio.h>
#include <stdlib.h>
#include "directedEdge.h"

//加权有向边初始化
void directedEdgeInit(DIRECTED_EDGE* pDiedge, int v, int w, double weight)
{
    if ( pDiedge == NULL )
    {
        return; 
    }

    pDiedge->from = v;
    pDiedge->to = w;
    pDiedge->weight = weight;
}

//获取加权有向边的起始点
int directedEdgeGetFrom(DIRECTED_EDGE* pDiedge)
{
    if ( pDiedge == NULL )
    {
        return -1; 
    }

    return pDiedge->from;
}

//获取加权有向边的终止点
int directedEdgeGetTo(DIRECTED_EDGE* pDiedge)
{
    if ( pDiedge == NULL )
    {
        return -1; 
    }

    return pDiedge->to;
}

//获取加权有向边的权重值
double directedEdgeGetWeight(DIRECTED_EDGE* pDiedge)
{
    if ( pDiedge == NULL )
    {
        return 0.0; 
    }

    return pDiedge->weight;
}

//检测加权有向边是否有效
int directedEdgeIsValid(DIRECTED_EDGE* pDiedge)
{
    if ( pDiedge == NULL )
    {
        return 0; 
    }

    return (pDiedge->to != pDiedge->from);
}

void directedEdgeDump(DIRECTED_EDGE* pDiedge)
{
    if ( pDiedge == NULL )
    {
        return; 
    }

    printf("from %d to %d, weight is %f\r\n", \
            directedEdgeGetFrom(pDiedge), directedEdgeGetTo(pDiedge), \
            directedEdgeGetWeight(pDiedge));
}

#if DIRECTED_EDGE_TEST
int main()
{
    DIRECTED_EDGE diedge = {0};

    directedEdgeInit(&diedge, 3, 4, 8.8);
    directedEdgeDump(&diedge);

    directedEdgeInit(&diedge, 2, 6, 3.5);
    directedEdgeDump(&diedge);

    directedEdgeInit(&diedge, 1, 0, 2.7);
    directedEdgeDump(&diedge);

    return 0;
}
#endif


edgeWeightedDigraph.h

#ifndef _EDGE_WEIGHTED_DIGRAPH_H_
#define _EDGE_WEIGHTED_DIGRAPH_H_

#include "directedEdge.h"

#define EDGE_WEIGHTED_DIGRAPH_TEST  0

#define CHECK_NULL_AND_RET(x) { if((x) == NULL) return -1; }

typedef struct _ADJ_ENTRY
{
    DIRECTED_EDGE       diedge;
    struct _ADJ_ENTRY*  pNext;
} ADJ_ENTRY;

typedef struct
{
    struct _ADJ_ENTRY*  entryHead;
} ADJ_HEAD;

typedef struct
{
    int         V;             //顶点数
    int         E;             //边数
    ADJ_HEAD*   adjTable;      //邻接表
} EDGE_WEIGHTED_DIGRAPH;

void edgeWeightedDigraphInit(EDGE_WEIGHTED_DIGRAPH* pGraph, int V);
void edgeWeightedDigraphUninit(EDGE_WEIGHTED_DIGRAPH* pGraph);
int  V(EDGE_WEIGHTED_DIGRAPH* pGraph);
int  E(EDGE_WEIGHTED_DIGRAPH* pGraph);
void addEdge(EDGE_WEIGHTED_DIGRAPH* pGraph, DIRECTED_EDGE* pDiedge);
void showGraph(EDGE_WEIGHTED_DIGRAPH* pGraph);

#endif

edgeWeightedDigraph.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "edgeWeightedDigraph.h"
#include "directedEdge.h"

//加权有向图对象初始化
void edgeWeightedDigraphInit(EDGE_WEIGHTED_DIGRAPH* pGraph, int V)
{
    if ( pGraph == NULL )
    {
        return; 
    }

    pGraph->V = V;
    pGraph->E = 0;

    pGraph->adjTable = (ADJ_HEAD *)malloc(sizeof(ADJ_HEAD) * V);
    if ( pGraph->adjTable == NULL )
    {
        return; 
    }
}

//加权有向图去初始化
void edgeWeightedDigraphUninit(EDGE_WEIGHTED_DIGRAPH* pGraph)
{
    if ( pGraph == NULL )
    {
        return; 
    }

    if ( pGraph->adjTable == NULL )
    {
        free(pGraph->adjTable);
        pGraph->adjTable = NULL;
    }

    memset(pGraph, 0, sizeof(EDGE_WEIGHTED_DIGRAPH));
}

//获取加权有向图的顶点数
int V(EDGE_WEIGHTED_DIGRAPH* pGraph)
{
    if ( pGraph == NULL )
    {
        return -1; 
    }

    return pGraph->V;
}

//获取加权有向图的边数
int E(EDGE_WEIGHTED_DIGRAPH* pGraph)
{
    if ( pGraph == NULL )
    {
        return -1; 
    }

    return pGraph->E;
}

//邻接表添加条目
static int adjAdd(EDGE_WEIGHTED_DIGRAPH* pGraph, int x, DIRECTED_EDGE* pDiedge)
{
    ADJ_HEAD  *pAdjHead = NULL;
    ADJ_ENTRY *pNewAdjEntry = NULL;

    if ( pGraph == NULL || pDiedge == NULL )
    {
        return -1; 
    }

    if ( x >= V(pGraph) || x < 0 )
    {
        return -1; 
    }

    pNewAdjEntry = (ADJ_ENTRY *)malloc(sizeof(ADJ_ENTRY));
    CHECK_NULL_AND_RET(pNewAdjEntry);
    memset(pNewAdjEntry, 0, sizeof(ADJ_ENTRY));
    pNewAdjEntry->diedge = *pDiedge;

    pAdjHead = (pGraph->adjTable + x);

    pNewAdjEntry->pNext = pAdjHead->entryHead;
    pAdjHead->entryHead = pNewAdjEntry;

    return 0;
}

//向加权有向图中添加边
void addEdge(EDGE_WEIGHTED_DIGRAPH* pGraph, DIRECTED_EDGE* pDiedge)
{
    if ( pGraph == NULL || pDiedge == NULL )
    {
        return; 
    }

    if ( adjAdd(pGraph, directedEdgeGetFrom(pDiedge), pDiedge) == 0 )
    {
        pGraph->E++;
    }
}

//打印加权有向图信息
void showGraph(EDGE_WEIGHTED_DIGRAPH* pGraph)
{
    int i = 0;

    if ( pGraph == NULL )
    {
        return; 
    }

    printf("point count: %d\r\n", V(pGraph));
    printf("edge  count: %d\r\n", E(pGraph));
    printf("-----------------------------------------\r\n");

    for ( i = 0; i < V(pGraph); i++ )
    {
        ADJ_ENTRY* pCurEntry = NULL;

        for ( pCurEntry = (pGraph->adjTable + i)->entryHead; \
            pCurEntry != NULL; pCurEntry = pCurEntry->pNext )
        {
            directedEdgeDump(&pCurEntry->diedge);
        }
    }

    printf("-----------------------------------------\r\n");
}

#if EDGE_WEIGHTED_DIGRAPH_TEST
int main()
{
    DIRECTED_EDGE diedge = {0};
    EDGE_WEIGHTED_DIGRAPH graph = {0};

    edgeWeightedDigraphInit(&graph, 10);

    directedEdgeInit(&diedge, 0, 1, 0.5);
    addEdge(&graph, &diedge);

    directedEdgeInit(&diedge, 1, 2, 1.5);
    addEdge(&graph, &diedge);

    directedEdgeInit(&diedge, 2, 3, 2.8);
    addEdge(&graph, &diedge);

    directedEdgeInit(&diedge, 0, 4, 9.6);
    addEdge(&graph, &diedge);

    directedEdgeInit(&diedge, 4, 7, 0.3);
    addEdge(&graph, &diedge);

    showGraph(&graph);

    edgeWeightedDigraphUninit(&graph);

    return 0;
}
#endif

dijkstraSP.c

//Dijkstra最短路径算法(针对加权有向图)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>
#include "directedEdge.h"
#include "edgeWeightedDigraph.h"
#include "indexMinPQ.h"

#define POSITIVE_INFINITY DBL_MAX 

//最短路径使用的数据结构
int             g_start = -1;       //起始点
double*         g_distTo = NULL;    //记载图中每个顶点到起始点的最短路径权值
DIRECTED_EDGE*  g_edgeTo = NULL;    //记载图中每个顶点连接起始点的最短路径上的最后一条边
INDEX_MIN_PQ    g_minPQ = {0};      //使用最小优先队列临时记载待处理的顶点

//创建加权有向图
//当前构建的加权有向图示例为:
//
//0 --(1.2)--> 1 --(5.6)--> 2
//             |
//             | --(1.5)--> 3 --(0.6)--> 4 --(0.2)--> 8
//             |                                      ^
//             | -----(7.8)------> 5 -----(5.3)-------|
//             |                                      ^
//             | --(2.3)--> 6 --(2.8)--> 7 --(4.3)----|
//
void createGraph(EDGE_WEIGHTED_DIGRAPH* pGraph)
{
    int    i = 0;
    int    froms[]   = {0,   1,   1,   1,   1,   3,   4,   5,   6,   7};
    int    tos[]     = {1,   2,   3,   5,   6,   4,   8,   8,   7,   8};
    double weights[] = {1.2, 5.6, 1.5, 7.8, 2.3, 0.6, 0.2, 5.3, 2.8, 4.3};
    DIRECTED_EDGE diedge = {0};

    if ( pGraph == NULL )
    {
        return; 
    }

    edgeWeightedDigraphInit(pGraph, 9);

    for ( i = 0; i < sizeof(froms)/sizeof(froms[0]); i++ )
    {
        directedEdgeInit(&diedge, froms[i], tos[i], weights[i]);
        addEdge(pGraph, &diedge);
    }
}

//销毁加权有向图
void destroyGraph(EDGE_WEIGHTED_DIGRAPH* pGraph)
{
    if ( pGraph == NULL )
    {
        return; 
    }

    edgeWeightedDigraphUninit(pGraph);
}

//算法初始化
int dijkstraSPInit(EDGE_WEIGHTED_DIGRAPH* pGraph, int start)
{
    int i = 0;
    int v = V(pGraph);

    if ( pGraph == NULL )
    {
        return -1; 
    }

    g_distTo = (double *)malloc(sizeof(double) * v);
    if ( g_distTo == NULL )
    {
        return -1; 
    }
    memset(g_distTo, 0, sizeof(double) * v);

    g_edgeTo = (DIRECTED_EDGE *)malloc(sizeof(DIRECTED_EDGE) * v);
    if ( g_edgeTo == NULL )
    {
        free(g_distTo);
        g_distTo = NULL;
        return -1; 
    }
    memset(g_edgeTo, 0, sizeof(DIRECTED_EDGE) * v);

    for ( i = 0; i < v; i++)
    {
        g_distTo[i] = POSITIVE_INFINITY;
    }

    indexMinPQInit(&g_minPQ, v);

    g_start = start;

    return 0;
}

//算法去初始化
void dijkstraSPUninit()
{
    if ( g_distTo != NULL )
    {
        free(g_distTo);
        g_distTo = NULL; 
    }

    if ( g_edgeTo != NULL )
    {
        free(g_edgeTo); 
        g_edgeTo = NULL;
    }

    indexMinPQUninit(&g_minPQ);

    g_start = -1;
}

//顶点的松驰处理
//
//* 边的松驰处理
//如下图示例所示,当前起始点为S,假设之前顶点W
//到起始点S的权重为8,顶点V到起始点S的权重为1,
//这时候对V-W边进行处理,发现 V到S的权重 + V-W边的权重 < W到S的权重,
//这时候更新W到S的权重为2+1,以及更新W到S的最短路径的最后一条边为W-V,
//这就是对V-W边进行松驰处理。
//
// W--(2)--> V --(1)--> S
// |                    ^
// |--------(8)---------|
//
//* 顶点的松驰处理
//假设上面示例中,顶点V刚确定好到起始点S的最短路径(也可以说V-S边做
//了边松驰处理),此时由于顶点V的到起始点S的权重值已经有了更新,所以
//需要对顶点V相关联的所有边都进行检查,查看是否相关联的边可以进行边
//松驰处理,对于这种操作就叫做对顶点V进行松驰处理。
//
int relax(EDGE_WEIGHTED_DIGRAPH* pGraph, int v)
{
    ADJ_ENTRY *pCurAdjEntry = NULL;

    if ( pGraph == NULL )
    {
        return -1; 
    }

    if ( v < 0 || v >= V(pGraph) )
    {
        return -1; 
    }

    //遍历当前顶点相关联的所有边
    for ( pCurAdjEntry = pGraph->adjTable[v].entryHead; \
        pCurAdjEntry != NULL; \
        pCurAdjEntry = pCurAdjEntry->pNext )
    {
        int    edgeTo = directedEdgeGetTo(&pCurAdjEntry->diedge);
        double edgeWeight = directedEdgeGetWeight(&pCurAdjEntry->diedge);

        //检测当前顶点相关联边的另一端顶点到起始点的权重是否大于当前顶点到起始点权重与当前关联边权重之和。
        //如果条件成立,则表示需要对该边进行松驰处理。
        if ( g_distTo[edgeTo] > g_distTo[v] + edgeWeight ) 
        {
            //更新关联边另一端顶点到起始点的最短路径权重,并记载到最短路径
            //的最后一条边。
            g_distTo[edgeTo] = g_distTo[v] + edgeWeight;
            g_edgeTo[edgeTo] = pCurAdjEntry->diedge;

            //由于关联边做了松驰操作,也就是说该边的另一端顶点到最短路径的
            //权重值有了变化,所以需要把该顶点加入到优先队列中,因为该顶点
            //受牵连的边都需要进行松驰检测。
            if ( indexMinPQContains(&g_minPQ, edgeTo) )
            {
                indexMinPQChange(&g_minPQ, edgeTo, edgeWeight);
            }
            else
            {
                indexMinPQInert(&g_minPQ, edgeTo, edgeWeight);
            }
        }
    }

    return 0;
}

//Dijkstra最短路径算法的主处理流程
//采用图的广度优先搜索处理方式,不断针对离起始点最短路径最近的顶
//点进行顶点松驰处理,直到不存在有效边时处理完成。
void dijkStraSP(EDGE_WEIGHTED_DIGRAPH* pGraph)
{
    if ( pGraph == NULL )
    {
        return; 
    }

    //将起始点加到的最短路径中,其中起始点到自身的权重为0
    g_distTo[g_start] = 0.0;

    //将起始点及到自身的权重值插入到优先队列中,准备进行当前
    //顶点的松驰处理。
    indexMinPQInert(&g_minPQ, g_start, 0.0);

    //采用图的广度优先搜索处理方式,不断从优先队列中找到
    //离最短路径最近的顶点,之后对该顶点进行松驰处理,处
    //理完成后,该顶点需要从优先队列中删除,之后继续处理
    //离最短路径次近的顶点,并进行顶点松驰处理,直到优先
    //队列中没有待处理的顶点。
    while ( !indexMinPQIsEmpty(&g_minPQ) )
    {
        relax(pGraph, indexMinPQDelMin(&g_minPQ)); 
    }
}

//显示任意顶点到起始点的最短路径信息
void showShortPathFromStartToV(int v)
{
    DIRECTED_EDGE* pCurEdge = &g_edgeTo[v];

    printf("from %d to %d (total weight %f):\r\n", g_start, v, g_distTo[v]);

    printf("---------------------------------\r\n");

    //由于g_edgeTo中记载的是每个顶点到起始点最短路径上的最后一条边,所以
    //这里使用倒序的流程显示从顶点V到起始点的路径信息,如果确实需要显示从
    //起始点到顶点V的路径信息则可以采用先入栈再出栈的方式实现,这里为了简
    //化没有那样处理。
    while ( directedEdgeIsValid(pCurEdge) )
    {
        int    edgeFrom = directedEdgeGetFrom(pCurEdge);
        int    edgeTo   = directedEdgeGetTo(pCurEdge);
        double edgeWeight = directedEdgeGetWeight(pCurEdge);

        printf("%d <-- %d (weight %f)\r\n", edgeFrom, edgeTo, edgeWeight); 

        pCurEdge = &g_edgeTo[edgeFrom];
    }

    printf("---------------------------------\r\n");
}

int main()
{
    EDGE_WEIGHTED_DIGRAPH graph = {0};

    createGraph(&graph);
    showGraph(&graph);

    dijkstraSPInit(&graph, 0);

    dijkStraSP(&graph);
    showShortPathFromStartToV(8);

    dijkstraSPUninit(&graph);

    destroyGraph(&graph);

    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值