Dijkstra算法 学习笔记

来源:互联网 发布:藏宝库 源码代下载 编辑:程序博客网 时间:2024/06/06 07:14

Dijkstra算法是一种搜索图中两顶点之间最短路径的算法.它由Edsger W. Dijkstra 在1956设计,并于三年后发表[wiki].
Dijkstra[3]Dijkstra[3]

算法核心思想

Dijkstra算法的基本思路是 在一个加权有向图中,将图中所有顶点分为两组, 一组包含已经找到最短路径的顶点;另一组包含剩余未确定最短路径的顶点. 为了求得两个顶点之间的最短路径,Dijkstra算法从起始点为中心向外遍历,直到搜索到终点为止.

复杂度分析

Dijkstra算法使用穷举策略,虽然能保证得出最短路径,但计算效率低.

算法实现

Dijkstra算法的实现需要两种容器类数据结构: 一个是维护图信息,另一个保存路径信息. Dijkstra算法中图结构只是作为一个坐标空间, 并不需要对其作复杂操作.Dijkstra算法所需的图操作有: 添加顶点,添加边,设置边的权值,提取顶点,遍历与某个顶点相连的边和顶点.

代码样例

Rosetta提供了一个C语言版的Dijkstra算法代码[Rosetta]. Rosetta的C语言版代码[Rosetta]主要是为了演示的Dijkstra算法, 没有考虑诸如内存释放等细节, 现将其改写成C++版, 代码如下:
头文件

#ifndef YANG_A_GRAPH_DIJK_H_#define YANG_A_GRAPH_DIJK_H_/* * dijkstra.h * *  Created on: *      Author: *  Based on: *  https://rosettacode.org/wiki/Dijkstra%27s_algorithm * *  Copyright @ 2017. CHUNFENG YANG. All Rights Reserved. *  Permission to use, copy, modify, and distribute this software *  and its documentation for educational, research, and *  not-for-profit purposes, without fee and without a signed *  above copyright notice, this paragraph and the following two *  distributions. *  IN NO EVENT SHALL CHUNFENG YANG BE LIABLE TO ANY PARTY FOR *  DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL *  DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS *  SOFTWARE AND ITS DOCUMENTATION, EVEN IF CHUNFENG YANG HAS BEEN *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *  CHUNFENG YANG SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, *  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY *  AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND *  ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS *  PROVIDED "AS IS". CHUNFENG YANG HAS NO OBLIGATION TO PROVIDE *  MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * */#include <stdio.h>#include <stdlib.h>#include <limits.h>class Edge{public:    Edge();    virtual ~Edge();public:    void show();public:    int _vertex;    double _weight;};class Vertex{public:    Vertex();    virtual ~Vertex();public:    void addEdge(Edge*);    void setDist(double);    double getDist();    void setPrev(int);    int getPrev();    void setVisited(int);    int getVisited();    int edgeLength();    Edge* getEdge(int);    void show();public:    Edge **_edges;    int _edges_len;    int _edges_size;    double _dist;    int _prev;    int _visited;};class Graph{public:    Graph();    virtual ~Graph();public:    void addVertex(int i);    void addEdge(int a, int b, double w);    void dijkstra(int a, int b);    void print_path(int);    void show();    double distance(int i, int j);    int length();public:    Vertex **_vertices;    int _vertices_len;    int _vertices_size;};class Heap{public:    Heap();    Heap(int n);    virtual ~Heap();public:    void push(int v, double p);    int pop();    int minimize(int i, int j, int k);    int length();    void show();    void clean();public:    int *_data;    double *_prio;    int *_index;    int _len;    int _size;};#endif // YANG_A_GRAPH_DIJK_H_

源文件

/* * dijkstra.h * *  Created on: *      Author: *  Based on: *  https://rosettacode.org/wiki/Dijkstra%27s_algorithm * *  Copyright @ 2017. CHUNFENG YANG. All Rights Reserved. *  Permission to use, copy, modify, and distribute this software *  and its documentation for educational, research, and *  not-for-profit purposes, without fee and without a signed *  above copyright notice, this paragraph and the following two *  distributions. *  IN NO EVENT SHALL CHUNFENG YANG BE LIABLE TO ANY PARTY FOR *  DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL *  DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS *  SOFTWARE AND ITS DOCUMENTATION, EVEN IF CHUNFENG YANG HAS BEEN *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *  CHUNFENG YANG SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, *  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY *  AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND *  ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS *  PROVIDED "AS IS". CHUNFENG YANG HAS NO OBLIGATION TO PROVIDE *  MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * */#include "dijkstra.h"#include <float.h>////  Edge//Edge::Edge(){    _vertex = 0;    _weight = 0;}Edge::~Edge(){}void Edge::show(){    printf("vertex: %-8d  weight: %-3f  \n", _vertex, _weight);}//// Vertex//Vertex::Vertex(){    _edges = NULL;    _edges_len = 0;    _edges_size = 0;    _dist = 0;    _prev = 0;    _visited = 0;}Vertex::~Vertex(){    if (NULL != _edges)    {        for (int i = 0; i < _edges_len; i++)        {            Edge* pEdge = _edges[i];            free(pEdge);        }        free(_edges);        _edges = NULL;        return;    }}void Vertex::addEdge(Edge *e){    if (NULL == e)    {        return;    }    if (_edges_len >= _edges_size)    {        _edges_size = _edges_size ? _edges_size * 2 : 4;        _edges = (Edge **) realloc(_edges, _edges_size * sizeof(Edge *));        if (NULL == _edges)        {            _edges_size = 0;            _edges_len = 0;            _dist = 0;            _prev = 0;            _visited = 0;            return;        }    }    _edges[_edges_len++] = e;}Edge* Vertex::getEdge(int index){    if ((index < 0) || (index >= _edges_len))    {        return NULL;    }    if (NULL == _edges)    {        return NULL;    }    return _edges[index];}int Vertex::edgeLength(){    return _edges_len;}void Vertex::Vertex::setDist(double value){    _dist = value;}double Vertex::getDist(){    return _dist;}void Vertex::setPrev(int value){    _prev = value;}int Vertex::getPrev(){    return _prev;}void Vertex::setVisited(int value){    _visited = value;}int Vertex::getVisited(){    return _visited;}void Vertex::show(){    if (NULL == _edges)    {        return;    }    for (int i = 0; i < _edges_len; i++)    {        Edge* pEdge = _edges[i];        pEdge->show();    }    printf("dist = %f \t", _dist);    printf("prev = %d \t", _prev);}//// Heap//Heap::Heap(){    _len = 0;    _size = 0;    _data = NULL;    _prio = NULL;    _index = NULL;}Heap::Heap(int n){    _data = NULL;    _prio = NULL;    _index = NULL;    _len = 0;    _size = 0;    if (n >= 0)    {        _data = (int*) calloc(n + 1, sizeof(int));        _prio = (double*) calloc(n + 1, sizeof(double));        _index = (int*) calloc(n, sizeof(int));        if ((NULL == _data) || (NULL == _prio) || (NULL == _index))        {            clean();            return;        }        for (int i = 0; i < n; i++)        {            _data[i] = 0;            _prio[i] = 0;            _index[i] = 0;        }        _data[n] = 0;        _prio[n] = 0;    }    _size = n;}Heap::~Heap(){    if (NULL != _data)    {        free(_data);        _data = 0;    }    if (NULL != _prio)    {        free(_prio);        _prio = 0;    }    if (NULL != _index)    {        free(_index);        _index = 0;    }}int Heap::length(){    return _len;}void Heap::push(int v, double p){    if (v < 0)    {        return;    }    if ((NULL == _data) || (NULL == _prio) || (NULL == _index))    {        printf("ERROR: Heap::push: _data is NULL. \n");        return;    }    int i = _index[v] == 0 ? ++_len : _index[v];    int j = i / 2;    while (i > 1)    {        if (_prio[j] < p)            break;        _data[i] = _data[j];        _prio[i] = _prio[j];        _index[_data[i]] = i;        i = j;        j = j / 2;    }    _data[i] = v;    _prio[i] = p;    _index[v] = i;    return;}int Heap::pop(){    if ((NULL == _data) || (NULL == _prio) || (NULL == _index))    {        printf("Heap::pop: data pointers invalid \n");        return 0;    }    int v = _data[1];    int i = 1;    while (1)    {        int j = minimize(_len, 2 * i, 2 * i + 1);        if (j == _len)            break;        _data[i] = _data[j];        _prio[i] = _prio[j];        _index[_data[i]] = i;        i = j;    }    _data[i] = _data[_len];    _prio[i] = _prio[_len];    _index[_data[i]] = i;    _len--;    return v;}int Heap::minimize(int i, int j, int k){    int m = i;    if (j <= _len && _prio[j] < _prio[m])        m = j;    if (k <= _len && _prio[k] < _prio[m])        m = k;    return m;}void Heap::clean(){    free(_data);    free(_prio);    free(_index);    _data = NULL;    _prio = NULL;    _index = NULL;    _len = 0;    _size = 0;}void Heap::show(){    printf("Heap::show() \n");    printf("    len = %d\n", _len);    for (int i = 0; i < _len; i++)    {        printf("data[%d] = %d\n", i, _data[i]);        printf("dist[%d] = %f\n", i, _prio[i]);    }}//// Graph//Graph::Graph(){    _vertices = NULL;    _vertices_len = 0;    _vertices_size = 0;}Graph::~Graph(){    if (NULL != _vertices)    {        for (int i = 0; i < _vertices_len; i++)        {            free(_vertices[i]);        }        free(_vertices);        _vertices = 0;    }}void Graph::addVertex(int i){    if (i < 0)    {        return;    }    if (_vertices_size < i + 1)    {        int size = _vertices_size * 2 > i ? _vertices_size * 2 : i + 4;        _vertices = (Vertex **) realloc(_vertices, size * sizeof(Vertex *));        if (NULL == _vertices)        {            _vertices_len = 0;            _vertices_size = 0;            return;        }        for (int j = _vertices_size; j < size; j++)            _vertices[j] = NULL;        _vertices_size = size;    }    if (!_vertices[i])    {        _vertices[i] = (Vertex *) calloc(1, sizeof(Vertex));        _vertices_len++;    }    return;}void Graph::addEdge(int a, int b, double w){    if (NULL == _vertices)    {        printf("ERROR: Graph::addEdge: vertices pointer is NULL. \n");        return;    }    a = a - 0;    b = b - 0;    addVertex(a);    addVertex(b);    Vertex *v = _vertices[a];    if (v->_edges_len >= v->_edges_size)    {        v->_edges_size = v->_edges_size ? v->_edges_size * 2 : 4;        v->_edges = (Edge **) realloc(v->_edges,                v->_edges_size * sizeof(Edge *));    }    Edge *e = (Edge *) calloc(1, sizeof(Edge));    if (NULL == e)    {        _vertices[a] = NULL;        return;    }    e->_vertex = b;    e->_weight = w;    v->_edges[v->_edges_len++] = e;}void Graph::dijkstra(int a, int b){    if (_vertices_len <= 0)    {        return;    }    int i, j;    a = a - 0;    b = b - 0;    for (i = 0; i < _vertices_len; i++)    {        Vertex *v = _vertices[i];        v->setDist(FLT_MAX);        v->setPrev(0);        v->setVisited(0);    }    Vertex *v = _vertices[a];    v->setDist(0);    Heap *h = new Heap(_vertices_len);    if (NULL == h)    {        return;    }    h->push(a, v->getDist());    int len = h->length();    while (len)    {        i = h->pop();        if (i == b)            break;        v = _vertices[i];        v->setVisited(1);        for (j = 0; j < v->edgeLength(); j++)        {            Edge *e = v->getEdge(j);            Vertex *u = _vertices[e->_vertex];            if (!u->getVisited() && v->getDist() + e->_weight <= u->getDist())            {                u->setPrev(i);                u->setDist(v->getDist() + e->_weight);                h->push(e->_vertex, u->getDist());            }        }    }}int Graph::length(){    return _vertices_len;}double Graph::distance(int i, int j){    dijkstra(i, j);    Vertex *v = _vertices[j];    if (v->_dist == FLT_MAX)    {        printf("Vertex reached Maxium. \n no path\n");        return 0.0;    }    double len = v->_dist;    return len;}void Graph::show(){    printf("Graph::show()");    printf(" len = %d\n", _vertices_len);    if (NULL == _vertices)    {        printf("ERROR: Graph::show: vertices pointer is NULL. \n");        return;    }    for (int i = 0; i < _vertices_len; i++)    {        Vertex* pVertex = _vertices[i];        printf("Vertex -- %d \n", i);        pVertex->show();        printf("\n");    }}void Graph::print_path(int i){    printf("Path:  \n");    int n, j;    Vertex *v, *u;    i = i - 0;    v = _vertices[i];    if (v->_dist == FLT_MAX)    {        printf("Vertex reached Maxium. \n no path\n");        return;    }    double len = v->_dist;    for (n = 1, u = v; u->_dist; u = _vertices[u->_prev], n++)        ;    char *path = (char*) malloc(n + 1);    if (NULL == path)    {        return;    }    path[n] = '\0';    path[n - 1] = 0 + i;    for (j = 0, u = v; u->_dist; u = _vertices[u->_prev], j++)    {        if (NULL == u)        {            break;        }        path[n - j - 2] = 0 + u->_prev;    }    printf("Length: %f  \n Route: %s \n", len, path);    printf("%d", i);    for (j = 0, u = v; u->_dist; u = _vertices[u->_prev], j++)    {        if (NULL == u)        {            break;        }        path[n - j - 2] = 0 + u->_prev;        printf(" => %d", u->_prev);    }    printf(" \n", i);    free(path);}

Testing Code

#include "dijkstra.h"int main(){    Graph g;    g.add_edge('a', 'b', 7);    g.add_edge('a', 'c', 9.1);    g.add_edge('a', 'f', 14);    g.add_edge('b', 'c', 10);    g.add_edge('b', 'd', 15);    g.add_edge('c', 'd', 11);    g.add_edge('c', 'f', 2);    g.add_edge('d', 'e', 6);    g.add_edge('e', 'f', 9);    for( int i = 50; i < 1000000; i++ )    {        g.add_edge(i, i+1, 9);    }    g.dijkstra('a', 'e');    g.print_path('e');    printf("Graph length = %d \n", g.length());    return 0;}

Gaph

   a  b  c  d  e  f  a  0  7  9       14b     0 10 15c        0 11     2d           0  6e              0  9f                 0

Searching process:

heap1: {a}heap2: {ab(7), ac(9), d(~), e(~), af{14}}
heap1: {ab(7), ac(9), af(14)}heap2: {bd{15}, cd(11)}
heap1:{abd(22),acd(20),af(14)}heap2:{de(6)}
heap1:{abde(28), acde(26), af(14)}heap2:{ef(9)}

Testing Result

Path:Length: 26.1 Route: acde
Created with Raphaël 2.1.0a(起始点) 遍历与a 关联的顶点 得到ab(7), ac(9), af(14) 遍历与d,f 关联的顶点 得到abde(28), acde(26), af(14)遇到e? e(终点)yes

[wiki] https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
[Rosetta] https://rosettacode.org/wiki/Dijkstra%27s_algorithm
[3] http://math.mit.edu/~rothvoss/18.304.3PM/Presentations/1-Melissa.pdf

原创粉丝点击