十大基础算法是什么内容

老刘

十大基础算法到底是什么?别被名字吓到,其实就这点事

说真的,我刚接触编程那会儿,听到“十大基础算法”这几个字,脑子里浮现的画面是一群穿白大褂的人围着黑板推导公式。后来才发现,这玩意儿没那么玄乎——它们其实就是计算机解决问题的“套路”,就像你做饭有切菜、焯水、爆炒这些基本功一样。

今天咱就聊聊这十个看家本领,不整那些虚头巴脑的数学符号,我用大白话给你讲明白。

排序算法——别小看“排排坐”

你肯定遇到过这种情况:手机通讯录乱成一锅粥,找个人得翻半天。排序算法就是解决这个问题的。

冒泡排序最直观,也最“笨”——两两比较,大的往后挪,像气泡一样往上冒。我有个朋友写代码第一次用冒泡,排十万个数用了五秒,旁边的老工程师看了眼说:“你搁这烧CPU呢?”说白了,这玩意儿适合数据量小的时候用,图个简单。

十大基础算法是什么内容

快速排序就不一样了,选一个基准数,比它小的放左边,大的放右边,然后左右两边递归着来。这招快得离谱,正常情况下一百万个数眨眼就排完。但有个坑:如果数据本身已经排得差不多了,它反而变慢。

还有归并排序,这货稳得一批,不管数据啥德行,效率都差不多。代价是得多占一块内存。

你问实际中用哪个?JavaScrIPt的sort()底层用的就是快速排序的变种,Python的sort()混了归并和插入——说白了,工程师们早帮你选好了,你要做的只是别写出O(n²)的算法还不自知。

搜索算法——找东西的本事

二分查找是我最喜欢的算法之一,因为它太符合直觉了。你在电话簿里找“张三”,会从中间翻开吗?不会,你直接翻到“Z”附近。二分查找就是这思路:每次从中间切一刀,判断目标在左半边还是右半边,然后继续切。

前提是数据得排好序。乱序的话,这招失灵。

那遇到乱序咋办?线性搜索,说白了就是挨个儿看。看着很蠢对吧?但我告诉你,微信聊天记录的搜索就是线性搜索——因为你不可能每次发完消息都排序一遍。所以有时候,“笨办法”反而是最合适的。

图算法——朋友圈和导航的秘密

广度优先搜索,听起来高端,其实就一个词:“扩散”。你在微信里找某个人的联系方式,先翻自己的好友,没有?那就翻好友的好友。这就是广度优先——一层一层往外搜。

最短路径算法,我打赌你每天都在用。打开高德地图,从王府井到三里屯给你推荐三条路线,哪条最快?这就是Dijkstra算法在干活。说白了就是:从起点开始,不断更新到达各个点的时间,直到找到终点。

你可能会问:要是我有一百个地方要去,怎么安排路线最省事?这就是旅行商问题,不好意思,这属于NP难问题——数据量大到一定程度,神仙来了也算不出最优解,只能找一个“差不多好”的方案。外卖小哥的路线规划就是这么干的,别指望能绝对最优。

动态规划——把大问题拆成小问题

这名字起得挺唬人,但其实是个很朴素的思路:记住已经算过的结果,避免重复计算。

比如斐波那契数列,递归算的话,f(5)要算f(4)和f(3),f(4)又要算f(3)和f(2)……你发现没?f(3)被反复算了。动态规划就是建个备忘录,算完一次就记下来,下次直接用。

背包装问题也是典例。你出门旅行,背包容量有限,怎么装东西最值钱?贪心算法会说:“选最贵的!”——但最贵的可能占地方大,反而装不下其他东西。动态规划会穷举所有组合,然后选最优。代价是慢,数据量大到一定程度,它也扛不住。

实际中很多算法都是在“贪心”和“动态规划”之间找平衡,比如地图导航里,你看着像是最短路径,其实用的是加了启发式的A*算法——不完全穷举,但也不瞎猜。

分治算法——分而治之

这思路中国人太熟了,“全国一盘棋”嘛。把一个复杂问题拆成多个相似的小问题,分别解决,再合并结果。

归并排序就是典型的分治——把数组不断一分为二,分到只剩一个元素,然后两两合并。快速排序也是——选基准、分两边、各自排序。

分治的好处是逻辑清晰,容易并行。坏处是分和合的过程可能很麻烦。比如你要找出一堆数里最大的两个,分治能搞定,但合并时的比较次数比你想象的多。

贪心算法——局部最优,整体不一定

贪心的思路很简单:每一步都选当前看起来最好的,不回头看。

比如找零钱,你有1块、5块、10块、20块四种面额,找36块怎么找?贪心算法会说:“先拿20块,再拿10块,再拿5块,再拿1块”——完美。

但换一种场景,你有1块、3块、4块,找6块,贪心会说:“先拿4块,再拿1块,再拿1块”——三张。实际上最优方案是两张3块。所以贪心算法不一定能得到全局最优解,但它快啊。

哈夫曼编码是贪心的成功案例,给字符分配最短的二进制码,压缩文件时用的就是它。最小生成树的Prim算法和Kruskal算法也是贪心,但它们的贪心策略能保证全局最优——这种就叫“有证明的贪心”。

回溯算法——不行就退回去

你想走一条迷宫,遇到死胡同就退回去换条路继续走。这就是回溯。

N皇后问题——在N×N的棋盘上放N个皇后,不能互相攻击。回溯就是:先放第一个,再放第二个,如果发现冲突就换位置,实在不行就退回去重新放第一个。

听着好像很慢是吧?但很多问题的搜索空间太大了,穷举根本不可能,回溯剪枝一下就成了实际可用的算法。数独求解器正则表达式匹配,底层的核心都是回溯。

字符串匹配算法——找文本里的关键词

你按Ctrl+F找文章里的某个词,背后就是字符串匹配算法在工作。

最简单的BF算法(又叫暴力匹配)就是:从文本每个位置开始,挨个字符和目标字符串比较。数据量小还行,大了就慢死。

KMP算法稍微聪明点——它利用已经比过的信息,不回溯主串的指针。说人话就是:匹配失败后,目标字符串自己往回退一截,主串继续往前走。发明这个算法的那三位大佬,Knuth、Morris、Pratt,当时被一堆人认为是解决了一个看似简单但实际棘手的问题。

实际应用里,文本编辑器的查找功能、甚至基因序列比对,都会用到KMP的变体。

树和图的遍历——其实就两种走法

树是一种递归结构,每个节点都有子节点。遍历树只有两种方式:深度优先(DFS)和广度优先(BFS)。

DFS的例子:走迷宫时一直往右拐,直到走不通才回头。BFS的例子:一层一层扫描。

深度优先常用递归实现,代码看起来优雅,但递归深度太大可能导致栈溢出。广度优先用队列,没有栈溢出问题,但占内存。

二叉树的三种遍历顺序——前序、中序、后序,其实就是访问根节点的时机不同。你觉得好像没啥用?编译器的语法分析、表达式求值、数据库的B+树索引,全是基于这些基础遍历思想在干活。

哈希算法——快得离谱的查找

哈希表的查找时间复杂度是O(1),意思是不管数据多大,查一次的时间基本不变。这怎么做到的?很简单:把数据的关键字通过一个函数映射到一个位置。

比如你的工号是1001,哈希函数可以取模1000,得到1,那就把这条记录存在索引为1的位置。查的时候再算一次,直接取。

听起来完美?但问题来了——如果另一条记录的工号是2001呢?取模也是1。这就叫“哈希冲突”。

解决冲突的方法有:拉链法(同一个位置存一个链表)、开放地址法(往后找空位)。Java的HashMap用的就是拉链法,当链表太长时还自动转成红黑树。

布隆过滤器是哈希的一个变种,它告诉你某个元素“一定不存在”或“可能存在”。用在大数据场景里,比如防止缓存穿透。缺点是可能产生误报,但永远不会漏报。

那么问题来了:这么多算法,我该先学哪个?

如果你是刚接触编程,我的建议是别贪多。从排序搜索开始,因为这两个你天天在用。然后搞懂哈希表,因为面试必问。接着是树遍历回溯,这两个能帮你建立递归思维。

很多人在网上刷了几个月的算法题,但写到第三个星期就开始怀疑人生——因为他们把算法当成了“解题套路”在背,而不是理解背后的思想。

说句大实话,我在工作中遇到过最复杂的算法场景,也不过是写了一个简单的深度优先搜索去匹配家谱数据。大部分情况下,框架和库已经帮你封装好了。你要做的不是从零实现这些算法,而是知道“这个问题该用哪种思路解决”、“那个库背后用的是啥原理”。

算法不是考卷上的题目,是你脑子里的一张地图。 知道有哪些路可以走,什么时候该拐弯,就够了。

行了,不废话了,去写点代码试试吧。

文章版权声明:文章内容均来源于各大短视频平台搜集以及修改和删减新增,如有侵权或者违规,请联系站长进行删除,如需转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
AddoilApplauseBadlaughBombCoffeeFabulousFacepalmFecesFrownHeyhaInsidiousKeepFightingNoProbPigHeadShockedSinistersmileSlapSocialSweatTolaughWatermelonWittyWowYeahYellowdog
验证码
评论列表 (暂无评论,11人围观)

还没有评论,来说两句吧...

目录[+]