数据结构和算法

DSA 主页 DSA 概述 DSA 环境设置 DSA 算法基础 DSA 渐近分析

数据结构

DSA 数据结构基础 DSA 数据结构和类型 DSA 数组数据结构

链接列表

DSA 链接列表数据结构 DSA 双向链接列表数据结构 DSA 循环链表数据结构

堆栈 &队列

DSA 堆栈数据结构 DSA 表达式解析 DSA 队列数据结构

搜索算法

DSA 搜索算法 DSA 线性搜索算法 DSA 二分搜索算法 DSA 插值搜索 DSA 跳跃搜索算法 DSA 指数搜索 DSA 斐波那契搜索 DSA 子列表搜索 DSA 哈希表

排序算法

DSA 排序算法 DSA 冒泡排序算法 DSA 插入排序算法 DSA 选择排序算法 DSA 归并排序算法 DSA 希尔排序算法 DSA 堆排序 DSA 桶排序算法 DSA 计数排序算法 DSA 基数排序算法 DSA 快速排序算法

图形数据结构

DSA 图形数据结构 DSA 深度优先遍历 DSA 广度优先遍历 DSA 生成树

树数据结构

DSA 树数据结构 DSA 树遍历 DSA 二叉搜索树 DSA AVL 树 DSA 红黑树 DSA B树 DSA B+ 树 DSA 伸展树 DSA 尝试 DSA 堆数据结构

递归

DSA 递归算法 DSA 使用递归的汉诺塔 DSA 使用递归的斐波那契数列

分而治之

DSA 分而治之 DSA 最大最小问题 DSA 施特拉森矩阵乘法 DSA Karatsuba 算法

贪婪算法

DSA 贪婪算法 DSA 旅行商问题(贪婪方法) DSA Prim 最小生成树 DSA Kruskal 最小生成树 DSA Dijkstra 最短路径算法 DSA 地图着色算法 DSA 分数背包问题 DSA 作业排序截止日期 DSA 最佳合并模式算法

动态规划

DSA 动态规划 DSA 矩阵链乘法 DSA Floyd Warshall 算法 DSA 0-1 背包问题 DSA 最长公共子序列算法 DSA 旅行商问题(动态方法)

近似算法

DSA 近似算法 DSA 顶点覆盖算法 DSA 集合覆盖问题 DSA 旅行商问题(近似方法)

随机算法

DSA 随机算法 DSA 随机快速排序算法 DSA Karger 最小割算法 DSA Fisher-Yates 洗牌算法

DSA 有用资源

DSA 问答 DSA 快速指南


Dijkstra 最短路径算法


Dijkstra 最短路径算法与 Prim 算法类似,因为它们都依赖于在局部寻找最短路径来实现全局解。然而,与 Prim 算法不同,Dijkstra 算法并非寻找最小生成树;它旨在寻找图中从一个顶点到其他顶点的最短路径。迪杰斯特拉算法既可以在有向图上运行,也可以在无向图上运行。

由于可以计算从单个源顶点到图中所有其他顶点的最短路径,因此迪杰斯特拉算法也称为单源最短路径算法。得到的输出称为最短路径生成树。

在本章中,我们将学习迪杰斯特拉算法的贪婪方法。

迪杰斯特拉算法

迪杰斯特拉算法旨在查找图中两个顶点之间的最短路径。这两个顶点可以是相邻的,也可以是图中距离最远的点。该算法从源开始。该算法的输入是图 G {V, E},其中 V 是顶点集,E 是边集,以及源顶点 S。输出是最短路径生成树。

算法

  • 声明两个数组 − distance[] 存储源顶点到图中其他顶点的距离,visited[] 存储已访问的顶点。

  • 将 distance[S] 设置为 0,distance[v] = ∞,其中 v 代表图中所有其他顶点。

  • 将 S 添加到 visited[] 数组,并找到 S 中距离最小的相邻顶点。

  • 假设 S 的相邻顶点 A 具有最小距离,并且尚未添加到 visited 数组中。选择 A 并将其添加到 visited 数组中,并将 A 的距离从 ∞ 更改为 A 的指定距离,即 d1,其中 d1 < ∞。

  • 对已访问顶点的相邻顶点重复此过程,直到形成最短路径生成树。

示例

为了更好地理解 Dijkstra 的概念,让我们借助示例图 ​​− 来分析该算法。

Dijkstras graph

步骤 1

除源节点 S 外,所有顶点的距离初始化为 ∞。

Vertex S A B C D E
Distance 0 ∞ ∞ ∞ ∞ ∞

现在源顶点 S 已被访问,将其添加到已访问数组中。

visited = {S}

步骤 2

顶点 S 有三个相邻顶点,它们的距离各不相同,其中距离最小的顶点是 A。因此,A 已被访问,dist[A] 从 ∞ 更改为 6。

S → A = 6
S → D = 8
S → E = 7
Vertex S A B C D E
Distance 0 6 ∞ ∞ 8 7
Visited = {S, A}
Visited s to a

步骤 3

visited 数组中有两个已访问的顶点,因此必须检查这两个已访问顶点的相邻顶点。

顶点 S 还有两个相邻顶点待访问:D 和 E。顶点 A 有一个相邻顶点 B。

计算 S 到 D、E、B 的距离,并选择最小距离 −

S → D = 8 and S → E = 7.
S → B = S → A + A → B = 6 + 9 = 15
Vertex S A B C D E
Distance 0 6 15 ∞ 8 7
Visited = {S, A, E}
Visited_S_A_E

步骤 4

计算所有已访问数组的相邻顶点(S、A、E)的距离,并选择距离最小的顶点。

S → D = 8
S → B = 15
S → C = S → E + E → C = 7 + 5 = 12
Vertex S A B C D E
Distance 0 6 15 12 8 7
Visited = {S, A, E, D}
Visited_s_a_e_d

步骤 5

重新计算未访问顶点的距离,如果找到比现有距离最小的距离,则替换距离数组中的值。

S → C = S → E + E → C = 7 + 5 = 12
S → C = S → D + D → C = 8 + 3 = 11

dist[C] = minimum (12, 11) = 11

S → B = S → A + A → B = 6 + 9 = 15
S → B = S → D + D → C + C → B = 8 + 3 + 12 = 23

dist[B] = minimum (15,23) = 15

Vertex S A B C D E
Distance 0 6 15 11 8 7
Visited = { S, A, E, D, C}
Visited_S_A_E_D_C

步骤 6

图中剩余的未访问顶点是 B,其最小距离为 15,被添加到输出生成树中。

Visited = {S, A, E, D, C, B}
Visited_S_A_E_D_C_B

使用迪杰斯特拉算法,得到最短路径生成树作为输出。

示例

该程序实现了迪杰斯特拉最短路径问题,该问题以成本邻接矩阵作为输入,并将最短路径和最小成本作为输出打印出来。

#include<stdio.h>
#include<limits.h>
#include<stdbool.h>
int min_dist(int[], bool[]);
void greedy_dijsktra(int[][6],int);
int min_dist(int dist[], bool visited[]){ // 寻找最小距离
   int minimum=INT_MAX,ind;
   for(int k=0; k<6; k++) {
      if(visited[k]==false && dist[k]<=minimum) {
         minimum=dist[k];
         ind=k;
      }
   }
   return ind;
}
void greedy_dijsktra(int graph[6][6],int src){
   int dist[6];
   bool visited[6];
   for(int k = 0; k<6; k++) {
      dist[k] = INT_MAX;
      visited[k] = false;
   }
   dist[src] = 0; // 源顶点 dist 设置为 0
   for(int k = 0; k<6; k++) {
      int m=min_dist(dist,visited);
      visited[m]=true;
      for(int k = 0; k<6; k++) {

         // 更新相邻顶点的距离
         if(!visited[k] && graph[m][k] && dist[m]!=INT_MAX && dist[m]+graph[m][k]<dist[k])
            dist[k]=dist[m]+graph[m][k];
      }
   }
   printf("Vertex		dist from source vertex
");
   for(int k = 0; k<6; k++) {
      char str=65+k;
      printf("%c			%d
", str, dist[k]);
   }
}
int main(){
   int graph[6][6]= {
      {0, 1, 2, 0, 0, 0},
      {1, 0, 0, 5, 1, 0},
      {2, 0, 0, 2, 3, 0},
      {0, 5, 2, 0, 2, 2},
      {0, 1, 3, 2, 0, 1},
      {0, 0, 0, 2, 1, 0}
   };
   greedy_dijsktra(graph,0);
   return 0;
}

输出

Vertex		dist from source vertex
A			   0
B			   1
C			   2
D			   4
E			   2
F			   3
#include<iostream>
#include<climits>
using namespace std;
int min_dist(int dist[], bool visited[]){ // 寻找最小距离
   int minimum=INT_MAX,ind;
   for(int k=0; k<6; k++) {
      if(visited[k]==false && dist[k]<=minimum) {
         minimum=dist[k];
         ind=k;
      }
   }
   return ind;
}
void greedy_dijsktra(int graph[6][6],int src){
   int dist[6];
   bool visited[6];
   for(int k = 0; k<6; k++) {
      dist[k] = INT_MAX;
      visited[k] = false;
   }
   dist[src] = 0; // 源顶点 dist 设置为 0
   for(int k = 0; k<6; k++) {
      int m=min_dist(dist,visited);
      visited[m]=true;
      for(int k = 0; k<6; k++) {

         // 更新相邻顶点的距离
         if(!visited[k] && graph[m][k] && dist[m]!=INT_MAX && dist[m]+graph[m][k]<dist[k])
            dist[k]=dist[m]+graph[m][k];
      }
   }
   cout<<"Vertex		dist from source vertex"<<endl;
   for(int k = 0; k<6; k++) {
      char str=65+k;
      cout<<str<<"			"<<dist[k]<<endl;
   }
}
int main(){
   int graph[6][6]= {
      {0, 1, 2, 0, 0, 0},
      {1, 0, 0, 5, 1, 0},
      {2, 0, 0, 2, 3, 0},
      {0, 5, 2, 0, 2, 2},
      {0, 1, 3, 2, 0, 1},
      {0, 0, 0, 2, 1, 0}
   };
   greedy_dijsktra(graph,0);
   return 0;
}

输出

Vertex		dist from source vertex
A			   0
B			   1
C			   2
D			   4
E			   2
F			   3
public class Main {
   static int min_dist(int dist[], boolean visited[]) { // 寻找最小距离
      int minimum = Integer.MAX_VALUE;
      int ind = -1;
      for (int k = 0; k < 6; k++) {
         if (!visited[k] && dist[k] <= minimum) {
            minimum = dist[k];
            ind = k;
         }
      }
      return ind;
   }
   static void greedy_dijkstra(int graph[][], int src) {
      int dist[] = new int[6];
      boolean visited[] = new boolean[6];
      for (int k = 0; k < 6; k++) {
         dist[k] = Integer.MAX_VALUE;
         visited[k] = false;
      }
      dist[src] = 0; // 源顶点 dist 设置为 0
      for (int k = 0; k < 6; k++) {
         int m = min_dist(dist, visited);
         visited[m] = true;
         for (int j = 0; j < 6; j++) {
            // 更新相邻顶点的距离
            if (!visited[j] && graph[m][j] != 0 && dist[m] != Integer.MAX_VALUE
                  && dist[m] + graph[m][j] < dist[j])
               dist[j] = dist[m] + graph[m][j];
         }
      }
      System.out.println("Vertex		dist from source vertex");
      for (int k = 0; k < 6; k++) {
         char str = (char) (65 + k);
         System.out.println(str + "			" + dist[k]);
      }
   }
   public static void main(String args[]) {
      int graph[][] = { { 0, 1, 2, 0, 0, 0 }, { 1, 0, 0, 5, 1, 0 }, { 2, 0, 0, 2, 3, 0 },
            { 0, 5, 2, 0, 2, 2 }, { 0, 1, 3, 2, 0, 1 }, { 0, 0, 0, 2, 1, 0 } };
      greedy_dijkstra(graph, 0);
   }
}

输出

Vertex		dist from source vertex
A			0
B			1
C			2
D			4
E			2
F			3
import sys
def min_dist(dist, visited):  # 寻找最小距离
    minimum = sys.maxsize
    ind = -1
    for k in range(6):
        if not visited[k] and dist[k] <= minimum:
            minimum = dist[k]
            ind = k
    return ind
def greedy_dijkstra(graph, src):
    dist = [sys.maxsize] * 6
    visited = [False] * 6
    dist[src] = 0  # 源顶点 dist 设置为 0
    for _ in range(6):
        m = min_dist(dist, visited)
        visited[m] = True
        for k in range(6):
            #  更新相邻顶点的距离
            if not visited[k] and graph[m][k] and dist[m] != sys.maxsize and dist[m] + graph[m][k] < dist[k]:
                dist[k] = dist[m] + graph[m][k]
    print("Vertex		dist from source vertex")
    for k in range(6):
        str_val = chr(65 + k)  # 将索引转换为对应的字符
        print(str_val, "			", dist[k])
# Main code
graph = [
    [0, 1, 2, 0, 0, 0],
    [1, 0, 0, 5, 1, 0],
    [2, 0, 0, 2, 3, 0],
    [0, 5, 2, 0, 2, 2],
    [0, 1, 3, 2, 0, 1],
    [0, 0, 0, 2, 1, 0]
]
greedy_dijkstra(graph, 0)

输出

Vertex		dist from source vertex
A 			 0
B 			 1
C 			 2
D 			 4
E 			 2
F 			 3