算法
文章平均质量分 76
睿科知识云
中国航天科工信息系统项目管理高级工程师
取得法律职业资格证书
希望和大家一起学习一起进步
展开
-
弗洛伊德算法(求最短路径)
弗洛伊德算法(求最短路径)在一个加权图中,如果想找到各个顶点之间的最短路径,可以考虑使用弗洛伊德算法。弗洛伊德算法既适用于无向加权图,也适用于有向加权图。使用弗洛伊德算法查找最短路径时,只允许环路的权值为负数,其它路径的权值必须为非负数,否则算法执行过程会出错。弗洛伊德算法的实现思路弗洛伊德算法是基于动态规划算法实现的,接下来我们以在图 1 所示的有向加权图中查找各个顶点之间的最短路径为例,讲解弗洛伊德算法的实现思路。图 1 有向加权图图 1 中不存在环路,且所有路径(边)的权值都为正数,因此原创 2022-01-22 13:35:40 · 11400 阅读 · 6 评论 -
迪杰斯特拉算法(求最短路径)
迪杰斯特拉算法(求最短路径)迪杰斯特拉算法用于查找图中某个顶点到其它所有顶点的最短路径,该算法既适用于无向加权图,也适用于有向加权图。注意,使用迪杰斯特拉算法查找最短路径时,必须保证图中所有边的权值为非负数,否则查找过程很容易出错。迪杰斯特拉算法的实现思路图 1 是一个无向加权图,我们就以此图为例,给大家讲解迪杰斯特拉算法的实现思路。图 1 无向加权图假设用迪杰斯特拉算法查找从顶点 0 到其它顶点的最短路径,具体过程是:统计从顶点 0 直达其它顶点的权值,如下表所示:表 1 顶点 0原创 2022-01-21 15:22:25 · 34755 阅读 · 11 评论 -
最短路径算法
最短路径算法在给定的图存储结构中,从某一顶点到另一个顶点所经过的多条边称为路径。图 1 图存储结构例如在图 1 所示的图结构中,从顶点 A 到 B 的路径有多条,包括 A-B、A-C-B 和 A-D-B。当我们给图中的每条边赋予相应的权值后,就可以从众多路径中找出总权值最小的一条,这条路径就称为最短路径。图 2 无向带权图以图 2 为例,从顶点 A 到 B 的路径有 3 条,它们各自的总权值是:A-B:9A-C-B:2+6=8A-D-B:5+8=13经过对比,A-C-B 的总权值最小,原创 2022-01-21 15:06:48 · 1590 阅读 · 0 评论 -
prim算法(普里姆算法)详解
prim算法(普里姆算法)详解了解了什么是最小生成树后,本节为您讲解如何用普里姆(prim)算法查找连通网(带权的连通图)中的最小生成树。普里姆算法查找最小生成树的过程,采用了贪心算法的思想。对于包含 N 个顶点的连通网,普里姆算法每次从连通网中找出一个权值最小的边,这样的操作重复 N-1 次,由 N-1 条权值最小的边组成的生成树就是最小生成树。那么,如何找出 N-1 条权值最小的边呢?普里姆算法的实现思路是:将连通网中的所有顶点分为两类(假设为 A 类和 B 类)。初始状态下,所有顶点位于 B原创 2022-01-21 14:53:04 · 32528 阅读 · 6 评论 -
最小生成树
最小生成树数据结构提供了 3 种存储结构,分别称为线性表、树和图,如图 1 所示。图 1 3 种存储结构a) 是线性表,b) 是树,c) 是图。 在图存储结构中,a、b、c 等称为顶点,连接顶点的线称为边。线性表是最简单的存储结构,很容易分辨。树和图有很多相似之处,它们的区别是:树存储结构中不允许存在环路,而图存储结构中可以存在环路(例如图 1 c) 中,c-b-f-c、b-a-f-b 等都是环路)。本节要讲的最小生成树和图存储结构息息相关,接下来我们将结合图存储结构,给大家讲解什么是生成树,以原创 2022-01-21 14:47:03 · 512 阅读 · 0 评论 -
哈希查找算法
哈希查找算法哈希查找算法又称散列查找算法,是一种借助哈希表(散列表)查找目标元素的方法,查找效率最高时对应的时间复杂度为 O(1)。哈希查找算法适用于大多数场景,既支持在有序序列中查找目标元素,也支持在无序序列中查找目标元素。讲解哈希查找算法之前,我们首先要搞清楚什么是哈希表。哈希表是什么哈希表(Hash table)又称散列表,是一种存储结构,通常用来存储多个元素。和其它存储结构(线性表、树等)相比,哈希表查找目标元素的效率非常高。每个存储到哈希表中的元素,都配有一个唯一的标识(又称“索引”或者原创 2022-01-21 14:44:20 · 12220 阅读 · 0 评论 -
插值查找算法
插值查找算法插值查找算法又称插值搜索算法,是在二分查找算法的基础上改进得到的一种查找算法。插值查找算法只适用于有序序列,换句话说,它只能在升序序列或者降序序列中查找目标元素。作为“改进版”的二分查找算法,当有序序列中的元素呈现均匀分布时,插值查找算法的查找效率要优于二分查找算法;反之,如果有序序列不满足均匀分布的特征,插值查找算法的查找效率不如二分查找算法。所谓均匀分布,是指序列中各个相邻元素的差值近似相等。例如,{10, 20, 30, 40, 50} 就是一个均匀分布的升序序列,各个相邻元素的差值原创 2022-01-21 14:40:41 · 3144 阅读 · 1 评论 -
二分查找算法(折半查找算法)
二分查找算法(折半查找算法)二分查找又称折半查找、二分搜索、折半搜索等,是在分治算法基础上设计出来的查找算法,对应的时间复杂度为O(logn)。二分查找算法仅适用于有序序列,它只能用在升序序列或者降序序列中查找目标元素。二分查找算法的实现思路在有序序列中,使用二分查找算法搜索目标元素的核心思想是:不断地缩小搜索区域,降低查找目标元素的难度。以在升序序列中查找目标元素为例,二分查找算法的实现思路是:初始状态下,将整个序列作为搜索区域(假设为 [B, E]);找到搜索区域内的中间元素(假设所在位置原创 2022-01-21 14:37:05 · 2648 阅读 · 0 评论 -
顺序查找算法
顺序查找算法顺序查找算法又称顺序搜索算法或者线性搜索算法,是所有查找算法中最基本、最简单的,对应的时间复杂度为O(n)。顺序查找算法适用于绝大多数场景,既可以在有序序列中查找目标元素,也可以在无序序列中查找目标元素。顺序查找算法的实现思路所谓顺序查找,指的是从待查找序列中的第一个元素开始,查看各个元素是否为要找的目标元素。举个简单的例子,采用顺序查找算法在 {10,14,19,26,27,31,33,35,42,44} 序列中查找 33,整个查找过程如下图所示:图 1 顺序查找 33 的过程原创 2022-01-21 14:19:29 · 10819 阅读 · 1 评论 -
稳定排序算法有哪些
稳定排序算法有哪些相信您已经掌握了很多种排序算法,比如冒泡排序、插入排序、希尔排序、选择排序等。这些排序算法中,有些是 “稳定” 的,有些是 “不稳定” 的。给定的待排序序列中,经常会包含相同的元素,例如:3 1 2 4 2此序列中包含两个元素 2,为了区分它们,我们分别称它们为 “红 2” 和 “绿 2”。评价一个排序算法是否稳定,是指该算法完成排序的同时,是否会改变序列中相同元素的相对位置。例如,上面序列中红 2 和绿 2 的相对位置是:红 2 位于绿 2 的左侧,或者说绿 2 位于红 2原创 2022-01-21 14:12:31 · 10668 阅读 · 1 评论 -
桶排序算法
桶排序算法桶排序(又称箱排序)是一种基于分治思想、效率很高的排序算法,理想情况下对应的时间复杂度为 O(n)。接下来,我们系统地学习一下桶排序算法。桶排序算法的实现思路假设一种场景,对 {5, 2, 1, 4, 3} 进行升序排序,桶排序算法的实现思路是:准备 5 个桶,从 1~5 对它们进行编号;将待排序序列的各个元素放置到相同编号的桶中;从 1 号桶开始,依次获取桶中放置的元素,得到的就是一个升序序列。整个实现思路如下图所示:桶排序算法中,待排序的数据量和桶的数量并不一定是简单的“一原创 2022-01-20 12:40:16 · 5712 阅读 · 2 评论 -
基数排序算法
基数排序算法在学会计数排序算法的基础上,本节我们再学习一种排序算法,称为基数排序算法。基数排序算法适用于对多个整数或者多个字符串进行升序或降序排序,例如:121, 432, 564, 23, 1, 45, 788“zhangsan”、“lisi”、“wangwu”一个整数由多个数字组成,例如 123 由 1、2、3 这 3 个数字组成;一个字符串由多个字符组成,例如 “lisi” 由 “l”、“i”、“s”、“i” 这 4 个字符组成。基数排序算法的实现思路是:对于待排序序列中的各个元素,依次比较原创 2022-01-20 12:37:39 · 1006 阅读 · 0 评论 -
计数排序算法
计数排序算法通过统计序列中各个元素出现的次数,完成对整个序列的升序或降序排序,这样的排序算法称为计数排序算法。接下来,我们为您系统地讲解计数排序算法。计数排序算法的实现思路假设待排序序列为 {4, 2, 2, 8, 3, 3, 1},使用计数排序算法完成升序排序的过程为:找到序列中的最大值(用 max 表示)。对于 {4, 2, 2, 8, 3, 3, 1} 序列来说,最大值是 8。创建一个长度为 max+1、元素初值全部为 0 的数组(Python 中可以使用列表),为数组中 [1,m原创 2022-01-20 12:34:29 · 1212 阅读 · 0 评论 -
快速排序算法
快速排序算法提到排序算法,多数人最先想到的就是快速排序算法。快速排序算法是在分治算法基础上设计出来的一种排序算法,和其它排序算法相比,快速排序算法具有效率高、耗费资源少、容易实现等优点。快速排序算法的实现思路是:从待排序序列中任选一个元素(假设为 pivot)作为中间元素,将所有比 pivot 小的元素移动到它的左边,所有比 pivot 大的元素移动到它的右边;pivot 左右两边的子序列看作是两个待排序序列,各自重复执行第一步。直至所有的子序列都不可再分(仅包含 1 个元素或者不包含任何元素),整原创 2022-01-20 12:31:05 · 985 阅读 · 0 评论 -
归并排序算法
归并排序算法归并排序算法是在分治算法基础上设计出来的一种排序算法,它可以对指定序列完成升序(由小到大)或降序(由大到小)排序,对应的时间复杂度为O(nlogn)。归并排序算法实现排序的思路是:将整个待排序序列划分成多个不可再分的子序列,每个子序列中仅有 1 个元素;所有的子序列进行两两合并,合并过程中完成排序操作,最终合并得到的新序列就是有序序列。举个简单的例子,使用归并排序算法对 {7, 5, 2, 4, 1, 6, 3, 0} 实现升序排序的过程是:将 {7, 5, 2, 4, 1, 6,原创 2022-01-20 12:24:37 · 377 阅读 · 0 评论 -
希尔排序算法
希尔排序算法前面给大家介绍了插入排序算法,通过将待排序序列中的元素逐个插入到有序的子序列中,最终使整个序列变得有序。下图所示的动画演示了插入排序的整个过程:图 1 插入排序算法观察动画不难发现,插入排序算法是通过比较元素大小和交换元素存储位置实现排序的,比较大小和移动元素的次数越多,算法的效率就越差。希尔排序算法又叫缩小增量排序算法,是一种更高效的插入排序算法。和普通的插入排序算法相比,希尔排序算法减少了移动元素和比较元素大小的次数,从而提高了排序效率。希尔排序算法的实现思路是:将待排序序列划原创 2022-01-20 12:21:22 · 1864 阅读 · 8 评论 -
选择排序算法
选择排序算法对数据量较少的序列实现升序或降序排序,可以考虑使用选择排序算法,它对应的时间复杂度为O(n2)。排序排序算法对含有 n 个元素的序列实现排序的思路是:每次从待排序序列中找出最大值或最小值,查找过程重复 n-1 次。对于每次找到的最大值或最小值,通过交换元素位置的方式将它们放置到适当的位置,最终使整个序列变成有序序列。举个例子,我们使用选择排序算法对 {14, 33, 27, 10, 35, 19, 42, 44} 完成升序排序,需要经历以下几个步骤:遍历整个待排序序列,从中找到最小值原创 2022-01-20 12:16:31 · 1861 阅读 · 0 评论 -
插入排序算法
插入排序算法插入排序算法可以对指定序列完成升序(从小到大)或者降序(从大到小)排序,对应的时间复杂度为O(n2)。插入排序算法的实现思路是:初始状态下,将待排序序列中的第一个元素看作是有序的子序列。从第二个元素开始,在不破坏子序列有序的前提下,将后续的每个元素插入到子序列中的适当位置。举个简单的例子,用插入排序算法对 {14, 33, 27, 10, 35, 19, 42, 44} 实现升序排序的过程如下:将第一个元素 14 看作是一个有序的子序列 {14},将剩余元素逐个插入到此序列的适当位置:原创 2022-01-20 12:13:11 · 1072 阅读 · 0 评论 -
冒泡排序算法
冒泡排序算法冒泡排序是所有排序算法中最简单、最易实现的算法,有时也称为起泡排序算法。使用冒泡排序算法对 n 个数据进行排序,实现思路是:从待排序序列中找出一个最大值或最小值,这样的操作执行 n-1 次,最终就可以得到一个有序序列。举个例子,对 {14, 33, 27, 35, 10} 序列进行升序排序(由小到大排序),冒泡排序算法的实现过程是:从 {14, 33, 27, 35, 10} 中找到最大值 35;从 {14,33,27,10} 中找到最大值 33;从 {14, 27, 10} 中找到原创 2022-01-20 12:09:51 · 3067 阅读 · 0 评论 -
N皇后问题
N皇后问题N 皇后问题源自国际象棋,所有棋子中权力最大的称为皇后,它可以直着走、横着走、斜着走(沿 45 度角),可以攻击移动途中遇到的任何棋子。N 皇后问题的具体内容是:如何将 N 个皇后摆放在 N*N 的棋盘中,使它们无法相互攻击。举个简单的例子,将 4 个皇后摆放在 4*4 的棋盘中,下图给出了一种摆放方式,各个皇后无论是直着走、横着走还是斜着走,都无法相互攻击。图 1 N 皇后问题Q 表示放置皇后的位置。N 皇后问题可以用回溯算法解决,接下来就为您讲解具体的解决思路。回溯算法解决N皇后原创 2022-01-20 12:05:26 · 1394 阅读 · 0 评论 -
回溯算法详解
回溯算法详解在图 1 中找到从 A 到 K 的行走路线,一些读者会想到用穷举算法(简称穷举法),即简单粗暴地将从 A 出发的所有路线罗列出来,然后逐一筛选,最终找到正确的路线。图 1 找从A到K的行走路线图 1 中,从 A 出发的路线有以下几条:A-B-CA-B-DA-E-F-GA-E-F-HA-E-J-IA-E-J-K穷举法会一一筛选这些路线,最终找到 A-E-J-K 。本节要讲的回溯算法和穷举法很像,它也会把所有可能的方案都查看一遍,从中找到正确答案。不同之处在于,回溯算法查看每原创 2022-01-19 12:49:33 · 567 阅读 · 0 评论 -
01背包问题
01背包问题商店的货架上摆放着不同重量和价值的商品,一个小偷在商店行窃,他携带的背包只能装固定重量的商品。装哪些商品才能获得最大的收益呢?在限定条件内找到最佳的物品组合,这样的问题统称为背包问题。根据限定的条件不同,背包问题还可以细分:部分背包问题:所有物品是可再分的,即允许将某件物品的一部分(例如 1/3)放入背包;0-1 背包问题:所有物品不可再分,要么整个装入背包,要么放弃,不允许出现“仅选择物品的 1/3 装入背包”的情况;完全背包问题:不对每一件物品的数量做限制,同一件物品可以选择多个装原创 2022-01-19 12:47:47 · 19477 阅读 · 0 评论 -
动态规划算法
动态规划算法动态规划算法解决问题的过程和分治算法类似,也是先将问题拆分成多个简单的小问题,通过逐一解决这些小问题找到整个问题的答案。不同之处在于,分治算法拆分出的小问题之间是相互独立的,而动态规划算法拆分出的小问题之间相互关联,例如要想解决问题 A,必须先解决问题 B 和 C。贪心算法一节中,给大家举过一个例子,假设有 1、7、10 这 3 种面值的纸币,每种纸币使用的数量不限,要求用尽可能少的纸币拼凑出的总面值为 15。贪心算法最终给出的拼凑方案是需要 10+1+1+1+1+1 共 6 张纸币,而如果原创 2022-01-19 12:40:08 · 179 阅读 · 0 评论 -
部分背包问题
部分背包问题在限定条件下,如何从众多物品中选出收益最高的几件物品,这样的问题就称为背包问题。图 1 背包问题举个简单的例子,商店的货架上摆放着不同重量和价值的商品,一个小偷在商店行窃,他携带的背包只能装固定重量的商品,选择哪些商品才能获得最大的收益呢?这个问题就属于背包问题,限定条件是背包的承重,最终目标是令背包中存放的物品的总收益最高。根据不同的限定条件,背包问题还可以有更细致的划分:0-1 背包问题:每件物品都不可再分,要么整个装入背包,要么放弃,不允许出现类似“将物品的 1/3 装入背包”原创 2022-01-19 12:24:53 · 3785 阅读 · 1 评论 -
贪心算法详解
贪心算法算法规定了解决问题的具体步骤,即先做什么、再做什么、最后做什么。贪心算法是所有算法中最简单,最易实现的算法,该算法之所以“贪心”,是因为算法中的每一步都追求最优的解决方案。举个例子,假设有 1、2、5、10 这 4 种面值的纸币,要求在不限制各种纸币使用数量的情况下,用尽可能少的纸币拼凑出的总面值为 18。贪心算法的解决方案如下:率先选择一张面值为 10 的纸币,可以最大程度上减少需要拼凑的数额(剩余 8);选择一张面值为 5 的纸币,需要拼凑的数额降为 3;选择一张面值为 2 的纸币,需原创 2022-01-19 12:21:49 · 428 阅读 · 0 评论 -
汉诺塔问题(分治+源码+动画演示)
汉诺塔问题(分治+源码+动画演示)汉诺塔问题源自印度一个古老的传说,印度教的“创造之神”梵天创造世界时做了 3 根金刚石柱,其中的一根柱子上按照从小到大的顺序摞着 64 个黄金圆盘。梵天命令一个叫婆罗门的门徒将所有的圆盘移动到另一个柱子上,移动过程中必须遵守以下规则:每次只能移动柱子最顶端的一个圆盘;每个柱子上,小圆盘永远要位于大圆盘之上;图 1 给您展示了包含 3 个圆盘的汉诺塔问题:图 1 汉诺塔问题一根柱子上摞着 3 个不同大小的圆盘,那么在不违反规则的前提下,如何将它们移动到另一个柱子原创 2022-01-19 12:20:02 · 2107 阅读 · 0 评论 -
找数组的最大值和最小值
找数组的最大值和最小值程序中,我们经常使用数组(列表)存储给定的线性序列(例如 {1,2,3,4}),那么如何查找数组(序列)中的最大值或者最小值呢?查找数组(序列)中最大值或最小值的算法有很多,接下来我们以 {3,7,2,1} 序列为例讲解两种查找最值的算法,一种是普通算法,另一种是借助分治算法解决。普通算法普通算法的解决思路是:创建两个变量 max 和 min 分别记录数组中的最大值和最小值,它们的初始值都是数组中的第一个数字。从第 2 个数字开始遍历数组,每遇到一个比 max 大的数字,就将它原创 2022-01-19 12:16:07 · 19785 阅读 · 0 评论 -
分治算法详解
分治算法实际场景中,我们之所以觉得有些问题很难解决,主要原因是该问题涉及到大量的数据,如果只需要处理少量的数据,问题会变得非常容易解决。举一个简单的例子,设计一个排序算法实现对 1000 个整数进行排序。对于很多刚刚接触算法的初学者来说,直接实现对 1000 个整数进行排序是非常困难的。而同样的问题,如果转换成对 2 个整数进行排序,解决起来就很容易。分治算法中,“分治”即“分而治之”的意思。分治算法解决问题的思路是:先将整个问题拆分成多个相互独立且数据量更少的小问题,通过逐一解决这些简单的小问题,最原创 2022-01-19 12:13:00 · 544 阅读 · 0 评论 -
斐波那契数列(递归+源码+注释)
斐波那契数列(递归+源码+注释)公元 1202 年,意大利数学家莱昂纳多·斐波那契提出了具备以下特征的数列:前两个数的值分别为 0 、1 或者 1、1;从第 3 个数字开始,它的值是前两个数字的和;为了纪念他,人们将满足以上两个特征的数列称为斐波那契数列。如下就是一个斐波那契数列:1 1 2 3 5 8 13 21 34…下面的动画展示了斐波那契数列的生成过程:图 1 斐波那契数列很多编程题目要求我们输出指定长度的斐波那契数列,比如输出长度为 6 的斐波那契数列:1 1 2 3 5原创 2022-01-19 12:10:15 · 9166 阅读 · 0 评论 -
递归算法详解
递归算法编程语言中,我们习惯将函数(方法)调用自身的过程称为递归,调用自身的函数称为递归函数,用递归方式解决问题的算法称为递归算法。函数(方法)调用自身的实现方式有 2 种,分别是:1) 直接调用自身,例如:int funciton(/*...*/) { //...... //调用自身 function(/*...*/); //......}2) 间接调用自身,例如:int funciton1(/*...*/) { //...... //调用另原创 2022-01-19 12:06:49 · 1746 阅读 · 0 评论 -
时间复杂度和空间复杂度
时间复杂度和空间复杂度解决一个问题的算法可能有多种,这种情况下,我们就必须对这些算法进行取舍,从中挑选出一个“最好”的。算法本身是不分“好坏”的,所谓“最好”的算法,指的是最适合当前场景的算法。挑选算法时,主要考虑以下两方面因素:执行效率:根据算法所编写的程序,执行时间越短,执行效率就越高;占用的内存空间:不同算法编写出的程序,运行时占用的内存空间也不相同。如果实际场景中仅能使用少量的内存空间,就应该优先选择占用空间最少的算法。当问题对应的算法数量较少时(比如 2、3 种),我们可以编写出各个算法原创 2022-01-18 12:50:22 · 367 阅读 · 0 评论 -
算法是什么
算法是什么要想成为一名合格的程序员,除了至少掌握一门编程语言,更重要的是多动手实践,积累足够的代码量,提升自己“遇到问题,解决问题”的能力。任何一门编程语言的学习,本质就是学习它规定的语法,整个过程只能死记硬背,几乎没有捷径。但是,提高“解决问题”的能力是有捷径可寻的,比如掌握一些算法。提到“算法”,很多人都觉得它高深莫测、晦涩难懂。事实上的确存在一些算法,学员必须具备优秀的数学基础和编程能力才能驾驭。但对于一位刚刚接触算法的初学者来说,根本不用学习这些“高难度”的算法,掌握一些简单的算法就足以应付实原创 2022-01-18 12:46:21 · 791 阅读 · 0 评论