迪杰斯特拉算法-最短路径

    迪杰斯特拉算法是很经典的最短路径算法,计算方式是从源点开始向外扩散,依次选点,直到点所有点选完之后,该源点到所有点的最短路径则计算完成。由于这个算法遍历了所有点,并且不断的在更新距离,用于选点,所以效率较低。
    要进行计算距离,首先要准备一个重要的矩阵数据,所有点连通性即距离,所有计算都是基于这个矩阵来进行计算的,下面开始讲解迪杰斯特拉的具体计算过程:

作为讲解计算过程示例图
以这个图为例,开始讲解:
以v0为源点,计算v0到各个顶点的最短距离,假设有两个集合:S,V,S集合是存放已经选择完成的点,V集合存放未计算完成的点,假设dist标记,如果某段路径x计算完成,就将dist[x] = 1(dist数组初始化的时候只有源点是1,其余都是-1),S集合最初只有源点V0,V集合中有除源点之外的所有点。

计算过程图示
1、V0只能到V1和V2两个点,且V0-V1近,则将V1加入S集合,更新最新路径:S加入V1后,可以到达V2,V3,V4三个点,距离分别为4,8,6。
2、将V2加入S集合,然后再更新最新距离,可达到V3,V4,V5,距离分别为,8,6,11,
依次进行,知道所有点加入S集合,在加点的同时,也在不断的更新dist数组,把相应的位置设置为1.并且还要更新一个前驱点集合,这是集合是将来用于寻找最短路径的关键信息。理论基本如此,以下是代码实现:

@interface PathNodeData : NSObject
{
    @public
    SPathNode *pathList;//过程路径
    NSInteger pathListNum;

    int nodeNumber;//节点数量
    SPathNode *points;//节点集合
    int distanceNum;//路径联通信息数量
    SMatrixNode *distances;//节点联通状态集合
    float *edgeMatrix;//节点距离矩阵

}
//以距离连接点矩阵初始化
- (instancetype)initWithMatrixData:(SPathAMatrix)pAndm;
/**
 *  计算路径
 *
 *  @param startIdx     起点
 *  @param endIdx       终点
 */
- (void)dijkstra:(uint64_t)startIdx andEnd:(uint64_t)endIdx;
#import "PathNodeData.h"

#define INF 9999.f

@implementation PathNodeData

- (instancetype)initWithMatrixData:(SPathAMatrix)pAndm{
    self = [super init];
    if (self) {
        nodeNumber = pAndm.pathNum;
        points = pAndm.paths;
        distanceNum = pAndm.matrixNum;
        distances = pAndm.matrixs;
        [self initData];
    }
    return self;
}


- (void)initData{
    edgeMatrix = malloc(sizeof(float)*nodeNumber*nodeNumber);
    for (int i = 0; i < nodeNumber; i++) {
        for (int j = 0; j < nodeNumber; j++) {
            edgeMatrix[i*nodeNumber+j] = INF;
        }
    }
    for (int i =0 ; i<distanceNum; i++) {
        SMatrixNode dist = distances[i];
        edgeMatrix[dist.row*nodeNumber+dist.column] = dist.value;
        edgeMatrix[dist.column*nodeNumber+dist.row] = dist.value;
    }
}

- (void)dijkstra:(uint64_t)startIdx andEnd:(uint64_t)endIdx {
    int startIndex = 0,endIndex = 0;
    for (int i = 0; i<nodeNumber; i++) {
        if (points[i].idd == startIdx) {
            startIndex = i;
        }
        if (points[i].idd == endIdx) {
            endIndex = i;
        }
    }
    int v,w,k = -1,min;
    int *final = malloc(sizeof(int)*nodeNumber); // final[i]=1表示"顶点vs"到"顶点i"的最短路径已成功获取。
    int *pathMatrix = malloc(sizeof(int)*nodeNumber);//储存最短路径下标
    int *shortPathTabel = malloc(sizeof(int)*nodeNumber);//用于储存各点路径权值和
    // 初始化
    for (v = 0; v < nodeNumber; v++)
    {
        final[v] = 0;              // 顶点v的最短路径还没获取到。
        pathMatrix[v] = -1;              // 初始化路径数组为0。
        shortPathTabel[v] = edgeMatrix[startIndex*nodeNumber+v];// 顶点i的最短路径为"顶点vs"到"顶点i"的权。
    }
    // 对"顶点vs"自身进行初始化
    shortPathTabel[startIndex] = 0;
    final[startIndex] = 1;

    // 遍历nodeNumber-1次;每次找出一个顶点的最短路径。
    for (v = 1; v < nodeNumber; v++){
        // 寻找当前最小的路径;
        // 即,在未获取最短路径的顶点中,找到离vs最近的顶点(k)。
        min = INF;
        for (w = 0; w < nodeNumber; w++)
        {
            if (!final[w] && shortPathTabel[w]<min)
            {
                min = shortPathTabel[w];
                k = w;
            }
        }
        // 标记"顶点k"为已经获取到最短路径
        final[k] = 1;

        // 修正当前最短路径和前驱顶点
        // 即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。
        for (w = 0; w < nodeNumber; w++)
        {
            if (!final[w] && (min+edgeMatrix[k*nodeNumber+w]  < shortPathTabel[w]))
            {
                shortPathTabel[w] = min+edgeMatrix[k*nodeNumber+w];
                pathMatrix[w] = k;
            }
        }

        //指定终点路径算完,终止循环,不终止的话会把所有点到源点路径计算完。
        if (k == endIndex) {
            break;
        }
    }
    [self getShortMax:pathMatrix Start:startIndex End:endIndex];

    free(final);
    free(pathMatrix);
    free(shortPathTabel);
    final = nil;
    pathMatrix = nil;
    shortPathTabel = nil;
}

- (void)getShortMax:(int *)p Start:(int)strIdx End:(int)endIdx{
    NSMutableArray *pathArray = [NSMutableArray array];
    int whileTag = endIdx;
    [pathArray addObject:@(endIdx)];
    while (YES) {
        whileTag = p[whileTag];
        if (whileTag < 0) {
            [pathArray addObject:@(strIdx)];
            break;
        }
        [pathArray addObject:@(whileTag)];
    }
    if (pathList!=nil) {
        free(pathList);
        pathList = nil;
    }
    pathList = malloc(sizeof(SPathNode)*pathArray.count);

    for (int i =0 ; i<pathArray.count; i++) {
        SPathNode pn = points[[pathArray[i] intValue]];
        pathList[pathArray.count-1-i] = pn;
    }
    pathListNum = pathArray.count;
}
- (void)dealloc{
    free(points);
    free(distances);
    free(pathList);
    free(edgeMatrix);
    points = nil;
    distances = nil;
    pathList = nil;
    edgeMatrix = nil;
}

代码中各部分注释很明确,下面对于读取最短路径作一个简短的说明,pathMatrix这个数组中存放着最短路径下标,但是直接读取是得不到的,首先将传进来的目标点,也就是终点作为数组下标,p[whileTag]得到一个下一个下标,whileTag = p[whileTag] ,然后同上,用现在的whileTag去获取p[whileTag],直到p[whileTag]的值为负(因为我初始化P数组的时候默认都为-1),则终止循环,过程中这些whileTag是需要保存的,他们按顺序排下来就是终点到起点的最短路径。
如果,你在程序中没有使用

 //指定终点路径算完,终止循环,不终止的话会把所有点到源点路径计算完。
        if (k == endIndex) {
            break;
        }

则程序会自动计算源点到所有点最短路径,则pathMatrix也不会存为负的情况(除非某个点是独立的,没有路径通向它),这样吧终点作为whileTag循环取下标,直到取得的p[whileTag]的值是你的起点,也要终止循环,整理下标。

以上则是迪杰斯特拉算法,初看可能不会立刻明白,结合程序以及LOG一些数组信息,则会慢慢理解......
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值