Ⅰ <算法图解>
二分查找、大O分析法;数组和链表;递归、快速排序;分治、动态规划、贪婪算法;散列表(键值对组成的数据结构);图算法(模拟网络的方法):广度优先搜索、迪杰斯特拉算法(计算网络中两点之间最短距离);K近邻(KNN,用于创建推荐系统、OCR引擎、预测股价、物件分类)。
二分查找的时间复杂度为log2n,多少个2相乘等于n。
有序数组,定义low和high,非一个元素,猜中,大了,小了。
选择排序:o(n方),快速排序:o(nlogn),存储最小的值,存储最小元素的索引,找出最小的值,加到新数组中。
循环,程序的性能更好,递归,程序更容易理解。栈有两种操作:压入和弹出。
每个递归函数都有两部分:基线条件和递归条件,递归条件指的是函数调用自己,基线条件指的是函数不再调用自己,避免无限循环。
编程概念,调用栈,计算机在内部使用被称为调用栈的栈,递归是调用自己的函数。
调用栈可能占用大量内存,解决方案是编写循环代码,或者使用尾递归,但并非所有的语言都支持尾递归。
分治-递归式问题解决办法:步骤:找出基线条件,确定如何缩小问题的规模,使其符合基线条件。
涉及数组的递归函数,基线条件通常是数组为空或只包含一个元素。
快速排序-D&C算法:步骤:设置基线条件,数组小于2,选择基准值,将数组分成两个子数组:小于和大于基准值的元素,对这两个子数组进行快速排序,递归调用。
合并排序:o(nlogn),快速排序:o(nlogn):层数o(logn)乘每层需要的时间o(n),但最差情况为o(n方)。
散列表-基本数据结构之一:内部机制:实现、冲突、散列函数。
散列表无序,数据结构:数组、列表、(栈、不能用于查找)、散列表(包含额外逻辑)。
数组和链表都直接映射到内存,但散列表使用散列函数来确定元素存储位置。
散列函数:不同的输入映射到不同的索引,输出不同的数字,散列表是散列函数和数组的结合,也称散列映射、映射、字典、关联数组。
缓存的数据存储在散列表中,访问页面时,先检查散列表是否存储了页面。
如果两个键映射到了同一个位置引发冲突,可以在这个位置存储一个链表,好的散列函数可以减少冲突。
填装因子为散列表元素/位置总数,因子越低,发生冲突的可能性越小,性能越高。
广度优先搜索(BFS)的含义:解决最短路径问题的算法。
步骤:使用图来建立问题模型,使用广度优先搜索算法(是否有路径,哪个路径最短)。
所有算法中,图算法是最有用的。
队列(数据结构):类似于栈,不能随机访问队列中元素,只支持入队和出队(压入和弹出),先加入的先出队,即先进先出(FIFO),而栈是后进先出(LIFO)。
有向图:关系是单向的,无向图:没有箭头,直接相连的节点互为邻居。
拓扑排序:根据图创建一个有序列表。
迪杰斯特拉算法:适用于加权图(提高或降低某些边的权重),找出加权图中的最短路径。
只适用于有向无环图,如果有负权边,不能使用迪杰斯特拉算法,因为算法假设处理过的节点,没有前往终点的最短路径,故,有负权边的可用贝尔曼-福特算法。
在未处理的节点找到开销最小的节点,遍历当前节点的所有邻居,如果经当前节点前往该邻居更近,就更新邻居开销,同时将该邻居的父节点设置为当前节点,将当前节点标记为处理过,找出接下来要处理的节点,并循环。
贪婪算法:每步都选择局部最优解,最终就是全局最优解,易于实现,运行快,是个不错的近似算法。
集合类似于列表,但是不包含重复的元素。
贪婪算法:o(n方),NP完全问题:需要计算所有的解,从中选出最小距离,计算量大,最佳做法是使用近似算法。
动态规划:约定条件下找到最优解,在问题可分解为彼此独立且离散的子问题时,就可使用动态规划来解决。
动态规划解决方案涉及网络,每个单元格都是子问题,需考虑如何将问题分解为子问题。
最长公共序列。
K最近邻算法(KNN):电影推荐系统。
特征抽取:指标打分,计算距离(相似程度),N维。
KNN的基本工作:分类和回归。
应用:OCR光学字符识别(optical character recognition),提取线段、点、曲线特征,找出与新图像最近的邻居;语音识别,人脸识别。
垃圾邮件过滤器:朴素贝叶斯分类器。
二叉查找树(binary search tree):有序树状数据结构。
二叉查找树插入和删除操作快于有序数组,但不能随机访问(没有索引)。
红黑树是处于平衡状态的特殊二叉树,不平衡时,如向右倾斜时性能不佳。
B树是一种特殊的二叉树。
反向索引:一个散列表,将单词映射到包含他的页面,常用于创建搜索引擎。
并行算法:速度的提升非线性,因为并行性管理开销和负载均衡。
分布式算法:特殊的并行算法,maprece(映射和归并函数),映射:任务多时自动分配多台计算机完成,将一个数组转换成另一个数组,归并是将一个数组转换成一个元素。
线性规划:在给定约束条件下最大限度的改善指定指标,使用simplex算法,图算法为线性规划子集。
Ⅱ Dijkstra算法时间复杂度
我们可以用大O符号将Dijkstra算法的运行时间表示为边数m和顶点数n的函数。
Dijkstra算法最简单的实现方法是用一个链表或者数组来存储所有顶点的集合Q,所以搜索Q中最小元素的运算(Extract-Min(Q))只需要线性搜索Q中的所有元素。这样的话算法的运行时间是O(n2)。
对于边数少于n2稀疏图来说,我们可以用邻接表来更有效的实现Dijkstra算法。同时需要将一个二叉堆或者斐波纳契堆用作优先队列来寻找最小的顶点(Extract-Min)。当用到二叉堆的时候,算法所需的时间为O((m+n)log n),斐波纳契堆能稍微提高一些性能,让算法运行时间达到O(m + n log n)。相关问题和算法
在Dijkstra算法的基础上作一些改动,可以扩展其功能。例如,有时希望在求得最短路径的基础上再列出一些次短的路径。为此,可先在原图上计算出最短路径,然后从图中删去该路径中的某一条边,在余下的子图中重新计算最短路径。对于原最短路径中的每一条边,均可求得一条删去该边后子图的最短路径,这些路径经排序后即为原图的一系列次短路径。
OSPF(open shortest path first, 开放最短路径优先)算法是Dijkstra算法在网络路由中的一个具体实现。
与Dijkstra算法不同,Bellman-Ford算法可用于具有负花费边的图,只要图中不存在总花费为负值且从源点 s 可达的环路(如果有这样的环路,则最短路径不存在,因为沿环路循环多次即可无限制的降低总花费)。
与最短路径问题有关的一个问题是旅行商问题(traveling salesman problem),它要求找出通过所有顶点恰好一次且最终回到源点的最短路径。该问题是NP难的;换言之,与最短路径问题不同,旅行商问题不太可能具有多项式时间算法。
如果有已知信息可用来估计某一点到目标点的距离,则可改用A*算法,以减小最短路径的搜索范围。
Ⅲ dijkstra算法是什么
迪杰斯特拉算法用来解决从顶点v0出发到其余顶点的最短路径,该算法按照最短路径长度递增的顺序产生所以最短路径。
对于图G=(V,E),将图中的顶点分成两组:第一组S:已求出的最短路径的终点集合(开始为{v0})。第二组V-S:尚未求出最短路径的终点集合(开始为V-{v0}的全部结点)。
堆优化
思考
该算法复杂度为n^2,我们可以发现,如果边数远小于n^2,对此可以考虑用堆这种数据结构进行优化,取出最短路径的复杂度降为O(1);每次调整的复杂度降为O(elogn);e为该点的边数,所以复杂度降为O((m+n)logn)。
实现
1、将源点加入堆,并调整堆。
2、选出堆顶元素u(即代价最小的元素),从堆中删除,并对堆进行调整。
3、处理与u相邻的,未被访问过的,满足三角不等式的顶点
1):若该点在堆里,更新距离,并调整该元素在堆中的位置。
2):若该点不在堆里,加入堆,更新堆。
4、若取到的u为终点,结束算法;否则重复步骤2、3。
Ⅳ 弗洛伊德与地杰斯特拉算法的区别
最大的区别是算法的时间复杂度
弗洛伊德算法的复杂度最低也是N的三次方 如果是竞赛的话你用弗洛伊德很不幸 你会超时
但是地杰斯特拉算法的复杂度就很低了可以达到期望logn级别 比N的三次方的算法就快了很多
还有一个区别就是在做最短路问题的时候迪杰斯特拉算法不适用于边有负权值的图
当碰到边有负权时 你可以选择SPFA算法 这是迪杰斯特拉算法的优化版 对稀疏图有不错的效果
顺带一提 SPFA是中国人优化的
Ⅳ 克鲁斯卡尔和迪杰斯特拉算法区别
克鲁斯卡尔算法和迪杰斯特拉算法是两种常用的图算法,主要区别如下:
1. 目标不同: - 克鲁斯卡尔算法用于求解最小生成树问题(即连接所有节点的边的权重之和最小),适用于无向加权图。 - 迪杰斯特拉算法用于求解单源最短路径问题(即从一个源节点到其他所有节点的最短路径),适用于有向或无向带权图。
2. 边的处理方式不同: - 克鲁斯卡尔算法通过不断选择权重最小的边,并将边加入最小生成树中,直到连接所有节点。 - 迪杰斯特拉算法通过不断选择当前距离源节点最近的节点,并更新其邻居节点的距离,直到求解出所有节点到源节点的最短路径。
3. 数据结构和时间复杂度不同: - 克鲁斯卡尔算法通常使用并查集来判定边的两个节点是否处于同一个连通分量中,时间复杂度为O(ElogE)。 - 迪杰斯特拉算法通常使用优先队列(如最小堆)来实现比较和选择当前距离源节点最近的节点,时间复杂度为O((|V|+|E|)log|V|)。总结来说,克鲁斯卡尔算法解决的是最小生成树问题,迪杰斯特拉算法解决的是单源最短路径问题。两者的核心思想和操作方式有所不同,适用场景也不同。
Ⅵ Dijkstra算法
迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉在1959年提出的。它是一种求解有权图中最短路径的算法,主要特点是采用贪心算法的策略,从起始点开始,每次遍历到距离始点最近且未访问过的顶点的邻接节点,直到扩展到终点为止。
迪杰斯特拉算法求的是单源最短路问题。其实现过程如下:
示例中我们可以发现,这里的迪杰斯特拉算法只适用于边权均为正的图。Dijkstra模板题如下:
给定一个有n个点m条边的有向图,图中可能存在重边和自环,所有边权均为正值。请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出-1。输入格式:第一行包含整数n和m。接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。输出格式:输出一个整数,表示1号点到n号点的最短距离。如果路径不存在,则输出-1。数据范围:[公式],[公式],图中涉及边长均不超过10000。输入样例:3 3 1 2 2 2 3 1 1 3 4 输出样例:3
分析:由本题的点和边的数据范围可知,这是一个稠密图,因此使用邻接矩阵来存储图。(朴素Dijkstra正是用来处理稠密图的)注意:本题有重边和自环。由于边权为正,所以自环一定不会在最短路中。而对于重边,我们存下最短边即可。
代码实现:时间复杂度为[公式]。对于稀疏图(m与n数据范围接近时),Dijkstra还有另外一种形式:堆优化Dijkstra。优化主要在寻找距离最小的点的操作上。堆有两种实现方式,之前已经有写过手写堆,这里使用另外一种堆的实现方式:优先队列。由于是稀疏图,存储方式需要改成邻接表形式。其思路和朴素Dijkstra一致。
代码实现:时间复杂度为[公式]。
以上就是朴素Dijkstra算法和堆优化Dijkstra算法。都是用于单源正权边最短路。未必优化版的就是更好的,朴素版适合稠密度,堆优化版适合稀疏图。