动态规划+广度优先搜索,实战经验总结

 

在实际生产中,遇到一个技术问题,在整个攻坚的过程中,回看的时候,才发现自己写了一个广度优先搜索的动态规划。这里把过程记录下来,源代码是贴不出来了,但是可以把解决的思路记录下来。

需求:写一个查询接口,去数据库查表,把所有查询出来的数据,整合到一个数据结构中,返回给前端展示。这个接口查询的数据,是树形结构,树有6层,每个层级之间的节点,不会互相调用,都是上一层调用下一层,这样的关系。有一个鲜明的特点是,第一层,假设是A层,第二层,假设是B层,那么A1可以调用B1、B2、B3;A2可以调用B1、B3、B4,以此类推,一直到最后一层,都是这样的关系,下一层的同一个节点,会被上一层,重复多次调用。记住这里重复的问题。

 

遇到的问题:

一开始的时候,我是按照惯性,依次循环遍历每个层级,在每一层循环中,把遍历到的每个节点都去数据库查一遍。整个数据库的查询,耗时长达107s。

循环的层级太多,是一个问题;大量的呈指数级上升的重复查询,也是一个问题。

 

解决办法:

深度优先-改广度优先

每一层级的查询,代码相似度都很高,如果按照惯性,肯定是写深度优先查找,这样逻辑是顺畅的,但是有一个问题,深度优先搜索,都是循环嵌套循环,一层一层嵌进去,这样代码无法复用,所以为了代码块的复用,我把深度优先改成了广度优先搜索。把当前的循环层级,在整个循环体外面,设一个变量dic_(数据类型存储介质),把当前循环的每个元素,进行去重,存入dic_,待循环结束,拿着dic_,开始下一层的循环,不断复用即可。这样,就没有嵌套的多层循环了,时间复杂度O(5*n),广度优先搜索,跟深度优先比较起来,时间复杂度也降下来。同时解决了代码复用以及时间复杂度降低两个维度的问题。

动态规划

在整个循环体中,设置中间存储介质,把所有遍历过的节点都存进去,在循环的时候,增加一层拦截判断,如果该节点,已经被遍历过,就continue,继续遍历下一个节点数据,这样,就是动态规划的实现。在循环中,设置中间存储单元,这是动态规划的本质。这样就避免了大量重复的数据库查询,效率瞬间提升十几倍。到这一步做完,整个数据库查询的耗时从107s,降到8.24s。

 

到此,动态规划的厉害,可见一斑。果然,名不虚传,经此一遭,深刻认识到了算法的强大。还是要好好学习啊。

posted @ 2022-05-23 18:16  dream-子皿  阅读(126)  评论(0编辑  收藏  举报