迪杰斯特拉算法

个人总结

Dijkstra算法的要点总结:
1.该算法需要两个重要的数据结合结构,集合S、T,S集合中存放已经找到最短路径的节点,T集合中则为S集合的补集,为还未找到阻断路径的节点集合
2.算法开始时将源点o放入S集合,并初始化各节点到源点的最短路径,如果之间不相通,距离为无穷大,否则,当前最短路径为到源点o的直接距离
3.整个算法过程为不断从T集合寻找当前最短路径的节点,并将其从T集合转移到S集合,直到T集合为空,算法结束
4.每次从T集合中提取当前最短路径的节点之后需要更新T集合中每个节点的当前最短路径,更新方法为:获取T中节点Ti,依次用S中的每个节点Si,将Si的最短路径长度加上Si到Ti的距离和与Ti直接到源点的距离做比较,如果距离和更小,则更新Ti的当前最短路径
5.总流程可表示为:集合S、T初始化----->提取T中最小路径节点放入S中------>更新T集合节点的当前最小路径 ,直到T集合为空,算法结束


定义

  Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。Dijkstra一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用OPEN, CLOSE表的方式,这里均采用永久和临时标号的方式。注意该算法要求图中不存在负权边。

问题描述

  在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径。( 单源最短路径

迪杰斯特拉算法

   迪杰斯特拉(Dijkstra)算法思想
   按路径长度递增次序产生最短路径算法:
  把V分成两组:
  (1)S:已求出最短路径的顶点的集合
  (2)V-S=T:尚未确定最短路径的顶点集合
  将T中顶点按最短路径递增的次序加入到S中,
  保证:(1)从源点V0到S中各顶点的最短路径长度都不大于
  从V0到T中任何顶点的最短路径长度
  (2)每个顶点对应一个距离值
  S中顶点:从V0到此顶点的最短路径长度
  T中顶点:从V0到此顶点的只包括S中顶点作中间
  顶点的最短路径长度
  依据:可以证明V0到T中顶点Vk的最短路径,或是从V0到Vk的
  直接路径的权值;或是从V0经S中顶点到Vk的路径权值之和
  (反证法可证)
   求最短路径步骤
  算法步骤如下:
  1. 初使时令 S={V0},T={其余顶点},T中顶点对应的距离值
  若存在,d(V0,Vi)为弧上的权值
  若不存在,d(V0,Vi)为∝
  2. 从T中选取一个其距离值为最小的顶点W且不在S中,加入S
  3. 对T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的
  距离值比不加W的路径要短,则修改此距离值
  重复上述步骤2、3,直到S中包含所有顶点,即S=T为止

迪杰斯特拉算法的原理

  首先,引进一个辅助向量D,它的每个分量D表示当前所找到的从始点v到每个终点vi的最短路径的长度。如D[3]=2表示从始点v到终点3的路径相对最小长度为2。这里强调相对就是说在算法过程中D的值是在不断逼近最终结果但在过程中不一定就等于最短路径长度。它的初始状态为:若从v到vi有弧,则D为弧上的权值;否则置D为∞。显然,长度为 D[j]=Min{D | vi∈V} 的路径就是从v出发的长度最短的一条最短路径。此路径为(v,vj)。 那么,下一条长度次短的最短路径是哪一条呢?假设该次短路径的终点是vk,则可想而知,这条路径或者是(v,vk),或者是(v,vj,vk)。它的长度或者是从v到vk的弧上的权值,或者是D[j]和从vj到vk的弧上的权值之和。 一般情况下,假设S为已求得最短路径的终点的集合,则可证明:下一条最短路径(设其终点为X)或者是弧(v,x),或者是中间只经过S中的顶点而最后到达顶点X的路径。因此,下一条长度次短的最短路径的长度必是D[j]=Min{D | vi∈V-S} 其中,D或者是弧(v,vi)上的权值,或者是D[k](vk∈S)和弧(vk,vi)上的权值之和。 迪杰斯特拉算法描述如下: 1)arcs表示弧上的权值。若不存在,则置arcs为∞(在本程序中为MAXCOST)。S为已找到从v出发的最短路径的终点的集合,初始状态为空集。那么,从v出发到图上其余各顶点vi可能达到的最短路径长度的初值为D=arcs[Locate Vex(G,v),i] vi∈V 2)选择vj,使得D[j]=Min{D | vi∈V-S} 3)修改从v出发到集合V-S上任一顶点vk可达的最短路径长度。

Dijkstra算法讲解与C/C++实现

  Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。
  Dijkstra算法是很有代表性的最短路算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。
  其基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。
  初始时,S中仅含有源。设u是G的某一个顶点,把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组dist记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶点u,将u添加到S中,同时对数组dist作必要的修改。一旦S包含了所有V中顶点,dist就记录了从源到所有其它顶点之间的最短路径长度。
  例如,对下图中的有向图,应用Dijkstra算法计算从源顶点1到其它顶点间最短路径的过程列在下表中。
   迪杰斯特拉算法_第1张图片

   主题好好理解上图!
  以下是具体的实现(C/C++):
  /***************************************
  * About: 有向图的Dijkstra算法实现
  * Author: Tanky Woo
  ***************************************/
  #include
  using namespace std;
  const int maxnum = 100;
  const int maxint = 999999;
  // 各数组都从下标1开始
  int dist[maxnum]; // 表示当前点到源点的最短路径长度
  int prev[maxnum]; // 记录当前点的前一个结点
  int c[maxnum][maxnum]; // 记录图的两点间路径长度
  int n, line; // 图的结点数和路径数
  // n -- n nodes
  // v -- the source node
  // dist[] -- the distance from the ith node to the source node
  // prev[] -- the previous node of the ith node
  // c[][] -- every two nodes' distance
  void Dijkstra(int n, int v, int *dist, int *prev, int c[maxnum][maxnum])
  {
  bool s[maxnum]; // 判断是否已存入该点到S集合中
  for(int i=1; i<=n; ++i)
  {
  dist[i] = c[v][i];
  s[i] = 0; // 初始都未用过该点
  if(dist[i] == maxint)
  prev[i] = 0;
  else
  prev[i] = v;
  }
  dist[v] = 0;
  s[v] = 1;
  // 依次将未放入S集合的结点中,取dist[]最小值的结点,放入结合S中
  // 一旦S包含了所有V中顶点,dist就记录了从源点到所有其他顶点之间的最短路径长度
  // 注意是从第二个节点开始,第一个为源点
  for(int i=2; i<=n; ++i)
  {
  int tmp = maxint;
  int u = v;
  // 找出当前未使用的点j的dist[j]最小值
  for(int j=1; j<=n; ++j)
  if((!s[j]) && dist[j]
  {
  u = j; // u保存当前邻接点中距离最小的点的号码
  tmp = dist[j];
  }
  s[u] = 1; // 表示u点已存入S集合中
  // 更新dist
  for(int j=1; j<=n; ++j)
  if((!s[j]) && c[u][j]
  {
  int newdist = dist[u] + c[u][j];
  if(newdist < dist[j])
  {
  dist[j] = newdist;
  prev[j] = u;
  }
  }
  }
  }
  // 查找从源点v到终点u的路径,并输出
  void searchPath(int *prev,int v, int u)
  {
  int que[maxnum];
  int tot = 1;
  que[tot] = u;
  tot++;
  int tmp = prev[u];
  while(tmp != v)
  {
  que[tot] = tmp;
  tot++;
  tmp = prev[tmp];
  }
  que[tot] = v;
  for(int i=tot; i>=1; --i)
  if(i != 1)
  cout << que[i] << " -> ";
  else
  cout << que[i] << endl;
  }
  int main()
  {
  freopen("input.txt", "r", stdin);
  // 各数组都从下标1开始
  // 输入结点数
  cin >> n;
  // 输入路径数
  cin >> line;
  int p, q, len; // 输入p, q两点及其路径长度
  // 初始化c[][]为maxint
  for(int i=1; i<=n; ++i)
  for(int j=1; j<=n; ++j)
  c[i][j] = maxint;
  for(int i=1; i<=line; ++i)
  {
  cin >> p >> q >> len;
  if(len < c[p][q]) // 有重边
  {
  c[p][q] = len; // p指向q
  c[q][p] = len; // q指向p,这样表示无向图
  }
  }
  for(int i=1; i<=n; ++i)
  dist[i] = maxint;
  for(int i=1; i<=n; ++i)
  {
  for(int j=1; j<=n; ++j)
  printf("%8d", c[i][j]);
  printf("\n");
  }
  Dijkstra(n, 1, dist, prev, c);
  // 最短路径长度
  cout << "源点到最后一个顶点的最短路径长度: " << dist[n] << endl;
  // 路径
  cout << "源点到最后一个顶点的路径为: ";
  searchPath(prev, 1, n);
  }
  输入数据:
  5
  7
  1 2 10
  1 4 30
  1 5 100
  2 3 50
  3 5 10
  4 3 20
  4 5 60
  输出数据:
  999999 10 999999 30 100
  10 999999 50 999999 999999
  999999 50 999999 20 10
  30 999999 20 999999 60
  100 999999 10 60 999999
  源点到最后一个顶点的最短路径长度: 60
  源点到最后一个顶点的路径为: 1 -> 4 -> 3 -> 5

你可能感兴趣的:(数据结构与算法)