408数据结构学习笔记——图的应用(一)

简介: 408数据结构学习笔记——图的应用

1.最小生成树

1.1.最小生成树的概念

  1. 边的权值之和最小的生成树,称为最小生成树
  2. 最小生成树不唯一
  3. 连通图本身就是一棵树,则它就是最小生成树
  1. 最小生成树需连通图,非连通图只能是生成森林

1.2.Prim算法

从某一个顶点开始构建最小生成树,依次加入当前剩余顶点中代价最小的顶点,直到加入所有顶点

时间复杂度:O(|gif.gif|)

适用:稠密图(E大)

每一轮开始都循环遍历所有节点,找到当前代价最低且并没有加入树的结点,再次遍历,更新各个结点的代价

1.3.Kruskal算法(库鲁斯卡尔)

每次选择代价最小的一条边,使该边的两个顶点相通,但是,如果原本就相通的两个顶点的边就不选,直到所有顶点相通

时间复杂度:O(gif.gif)

适用:稀疏图(E小)

共执行e轮,每轮判断两个结点是否属于同一个结点

2.最短路径

2.1.BFS

BFS能求无权图的单源最短路径:用额外两个数组分别存储该顶点的前驱和距离源顶点的距离

#define MaxVertexNum 100
void BFS(Graph G, int v){
    Queue Q;
    InitQueue(Q);
    EnQueue(v);
    int q, p;
    //dist数组用来存放当前顶点到源顶点的距离,pre存放当前顶点的前驱顶点
    int dist[MaxVertexNum] = { 0 }, pre[MaxVertexNum] = { 0 };
    bool visited[MaxVertexNum] = { false };
    //源顶点的前驱置为-1
    pre[v] = -1;
    //源顶点标记已访问
    visited[v] = true;
    //cur标记当前距离顶点的距离
    int cur = 0;
    while(!IsEmpty(Q)){
        DeQueue(Q, p);
        cur++;
        for (q = FirstNeighbor(G, p); q >= 0; q = NextNeighbor(G, p, q)){
            if (!visited[q]) {
                //将q设置为已标记
                visited[q] = true;
                //入队q
                EnQueue(Q, p);
                //更新q距离源顶点的距离
                dist[q] = cur;
                //更新q的前驱
                pre[q] = p;
            }//if
        }//for
    }//while
}

BFS算法求最短路径的局限:仅能求无权图或者各条边权值都相同的图

2.2.Dijkstra算法

2.2.1.Dijkstra算法的基本概念

在求最短路径(单源)的过程中,需要新建四个数组:path(存储到此点路径的上个结点)、dist(距离源点的最短距离)、顶点集S和final(标记是否已经找到最短路径)

3b3241654581441095c15400a1e2bc43.png

9bf093bb8f8749e7978d880a4c8ad6cc.png


b940a1977ff2401fb4915ee29109da63.png

第一轮以0为源点,更新以0为起点到各个顶点的数据,如果当前还没有道路能通往该顶点(2,3),则前驱为-1,且距离为 ∞,并把源点0的final标记为已找到

                                         第一轮

fab81a2d1b6d5d255455088d9c966f3.png

第二轮以当前未找到最短路径且当前路径最低的顶点,即顶点4,将其final改为已找到。以0→4的路径更新各个顶点数据。

第二轮

8401d7d228357ac78dfbd507b0808ce.png

第三轮以当前未找到最短路径且当前路径最低的顶点,即顶点1,将其final改为已找到。以0→4→3的路径更新各个顶点数据

第三轮

945e54b92b79a74c1cbfbc126308601.png

第四轮以当前未找到最短路径且当前路径最低的顶点,即顶点3,将其final改为已找到。以0→4→3→1的路径更新各个顶点数据。

第四轮

29348516adc42792d8148b221f3cb2c.png

第四轮以当前未找到最短路径且当前路径最低的顶点,即顶点5,将其final改为已找到。

第五轮

df12255a471521957d24ea3a3f9bce1.png

2.2.2.Dijkstra的时间复杂度

每轮都需要遍历两边数组(顶点集),第一遍查找当前距离最短且未被标记的顶点,第二遍更新以该顶点为路径的信息,一共要执行n - 1轮,因此,时间复杂度为O(|V|^{2}),即O(

gif.gif)(与Prime算法的思想很类似)

2.2.3.Dijkstra的不适用情况

当图中边的权值存在负值时,Dijkstra算法并不适用

2.3.Floyd算法

2.3.1.Floyd算法的基本概念

Floyd算法用于计算有向图/无向图的任意两个结点的最短路径

Floyd算法需要新建两个二维数组,A(保存当前最短路径长度)和path(最短路径的前驱)

68526d555e1f4f17b4947f08dc15d1ad.png

c8e1e0fbf9b64ab2b2e79029588aef58.png

初始化A和path数组,不允许任何中转

A

V0 V1 V2 V3 V4
V0 0 1 10
V1 0 1 5
V2 1 0 7
V3 0 1
V4 0

path

V0 V1 V2 V3 V4
V0 -1 -1 -1 -1 -1
V1 -1 -1 -1 -1 -1
V2 -1 -1 -1 -1 -1
V3 -1 -1 -1 -1 -1
V4 -1 -1 -1 -1 -1

第一轮:允许在V0中转

A

V0 V1 V2 V3 V4
V0 0 1 10
V1 0 1 5
V2 1 0 7
V3 0 1
V4 0

path

V0 V1 V2 V3 V4
V0 -1 -1 -1 -1 -1
V1 -1 -1 -1 -1 -1
V2 -1 -1 -1 -1 -1
V3 -1 -1 -1 -1 -1
V4 -1 -1 -1 -1 -1

第二轮:允许在V0、V1中转,更新V2→V3、V2→V4

A

V0 V1 V2 V3 V4
V0 0 1 10
V1 0 1 5
V2 1 0 2 6
V3 0 1
V4 0

path

V0 V1 V2 V3 V4
V0 -1 -1 -1 -1 -1
V1 -1 -1 -1 -1 -1
V2 -1 -1 -1 1 1
V3 -1 -1 -1 -1 -1
V4 -1 -1 -1 -1 -1

第三轮:允许在V0、V1、V2中转,更新V0→V1、V0→V4、V0→V3

A

V0 V1 V2 V3 V4
V0 0 2 1 3 8
V1 0 1 5
V2 1 0 2 6
V3 0 1
V4 0

path

V0 V1 V2 V3 V4
V0 -1 2 -1 2 2
V1 -1 -1 -1 -1 -1
V2 -1 -1 -1 1 1
V3 -1 -1 -1 -1 -1
V4 -1 -1 -1 -1 -1

第四轮:允许在V0、V1、V2、V3中转,更新V0→V4、V1→V4、V2→V4

A

V0 V1 V2 V3 V4
V0 0 2 1 3 4
V1 0 1 2
V2 1 0 2 3
V3 0 1
V4 0

path

V0 V1 V2 V3 V4
V0 -1 2 -1 2 3
V1 -1 -1 -1 -1 3
V2 -1 -1 -1 1 3
V3 -1 -1 -1 -1 -1
V4 -1 -1 -1 -1 -1

第五轮:允许在V0、V1、V2、V3中转

A

V0 V1 V2 V3 V4
V0 0 2 1 3 4
V1 0 1 2
V2 1 0 2 3
V3 0 1
V4 0

path

V0 V1 V2 V3 V4
V0 -1 2 -1 2 3
V1 -1 -1 -1 -1 3
V2 -1 -1 -1 1 3
V3 -1 -1 -1 -1 -1
V4 -1 -1 -1 -1 -1

2.3.2.Floyd算法的复杂度

空间复杂度:创建两个二维数组O(n2)

时间复杂度:三个for循环O(n3)

2.4.最短路径小结

  1. 无权图:BFS、Dijkstra算法、Floyd算法
  2. 带权图:Dijkstra算法、Floyd算法
  3. 带负权值图:Floyd算法
  4. 带负权值回路图:无

 5.时间复杂度:

  1. BFS:O(|V^2|)(邻接矩阵)或者O(|V|+|E|)(邻接表)
  2. Dijkstra:O(|V^|2)
  3. Floyd:O(|V|^3)

  6.通常应用场景:

  1. BFS:无权图单源最短路径
  2. Dijkstra:有权图单源最短路径(也可以求任意两点路径,重复V次,O(|V|^3)
  3. Floyd:有权图各个顶点间最短路径


相关文章
|
3天前
|
存储 算法 C语言
通义灵码在考研C语言和数据结构中的应用实践 1-5
通义灵码在考研C语言和数据结构中的应用实践,体验通义灵码的强大思路。《趣学C语言和数据结构100例》精选了五个经典问题及其解决方案,包括求最大公约数和最小公倍数、统计字符类型、求特殊数列和、计算阶乘和双阶乘、以及求斐波那契数列的前20项和。通过这些实例,帮助读者掌握C语言的基本语法和常用算法,提升编程能力。
|
27天前
|
算法 安全 测试技术
golang 栈数据结构的实现和应用
本文详细介绍了“栈”这一数据结构的特点,并用Golang实现栈。栈是一种FILO(First In Last Out,即先进后出或后进先出)的数据结构。文章展示了如何用slice和链表来实现栈,并通过golang benchmark测试了二者的性能差异。此外,还提供了几个使用栈结构解决的实际算法问题示例,如有效的括号匹配等。
golang 栈数据结构的实现和应用
|
1月前
|
存储 Java
【数据结构】优先级队列(堆)从实现到应用详解
本文介绍了优先级队列的概念及其底层数据结构——堆。优先级队列根据元素的优先级而非插入顺序进行出队操作。JDK1.8中的`PriorityQueue`使用堆实现,堆分为大根堆和小根堆。大根堆中每个节点的值都不小于其子节点的值,小根堆则相反。文章详细讲解了如何通过数组模拟实现堆,并提供了创建、插入、删除以及获取堆顶元素的具体步骤。此外,还介绍了堆排序及解决Top K问题的应用,并展示了Java中`PriorityQueue`的基本用法和注意事项。
40 5
【数据结构】优先级队列(堆)从实现到应用详解
|
18天前
|
消息中间件 存储 Java
数据结构之 - 深入探析队列数据结构: 助你理解其原理与应用
数据结构之 - 深入探析队列数据结构: 助你理解其原理与应用
23 4
|
1月前
|
存储 机器学习/深度学习
【数据结构】二叉树全攻略,从实现到应用详解
本文介绍了树形结构及其重要类型——二叉树。树由若干节点组成,具有层次关系。二叉树每个节点最多有两个子树,分为左子树和右子树。文中详细描述了二叉树的不同类型,如完全二叉树、满二叉树、平衡二叉树及搜索二叉树,并阐述了二叉树的基本性质与存储方式。此外,还介绍了二叉树的实现方法,包括节点定义、遍历方式(前序、中序、后序、层序遍历),并提供了多个示例代码,帮助理解二叉树的基本操作。
59 13
【数据结构】二叉树全攻略,从实现到应用详解
|
19天前
|
存储 算法 分布式数据库
【初阶数据结构】理解堆的特性与应用:深入探索完全二叉树的独特魅力
【初阶数据结构】理解堆的特性与应用:深入探索完全二叉树的独特魅力
|
1月前
|
存储 Java 索引
【数据结构】链表从实现到应用,保姆级攻略
本文详细介绍了链表这一重要数据结构。链表与数组不同,其元素在内存中非连续分布,通过指针连接。Java中链表常用于需动态添加或删除元素的场景。文章首先解释了单向链表的基本概念,包括节点定义及各种操作如插入、删除等的实现方法。随后介绍了双向链表,说明了其拥有前后两个指针的特点,并展示了相关操作的代码实现。最后,对比了ArrayList与LinkedList的不同之处,包括它们底层实现、时间复杂度以及适用场景等方面。
61 10
【数据结构】链表从实现到应用,保姆级攻略
|
28天前
|
存储 数据安全/隐私保护 Python
Python常用数据结构——字典的应用
Python常用数据结构——字典的应用
20 2
|
1月前
|
JSON 前端开发 JavaScript
一文了解树在前端中的应用,掌握数据结构中树的生命线
该文章详细介绍了树这一数据结构在前端开发中的应用,包括树的基本概念、遍历方法(如深度优先遍历、广度优先遍历)以及二叉树的先序、中序、后序遍历,并通过实例代码展示了如何在JavaScript中实现这些遍历算法。此外,文章还探讨了树结构在处理JSON数据时的应用场景。
一文了解树在前端中的应用,掌握数据结构中树的生命线
|
1月前
|
存储 JSON NoSQL
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
这篇文章是关于Redis基本数据结构的学习笔记,包括了String、Hash、Set、List和SortedSet的介绍和常用命令。文章解释了每种数据结构的特点和使用场景,并通过命令示例演示了如何在Redis中操作这些数据结构。此外,还提供了一些练习示例,帮助读者更好地理解和应用这些数据结构。
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】