美文网首页
活学活用 DFS

活学活用 DFS

作者: 青叶小小 | 来源:发表于2021-03-24 13:21 被阅读0次

一、前言

今天小伙伴给我截了个图,吐糟公司的恶心的需求,需要将一个大的、嵌套列表展开(平铺)成一级列表,然后,哼哧哼哧写完后,给我看。不给我看还不要紧,一给我看,我立马小怒,这是干了多年开发写出来的代码么?废话不多说,先上图片:

N级嵌套.jpeg

二、深度优先搜索 DFS(Depth First Search)

如果各位大一学习过《数据结构》,我记得应该是清华大学出版的(当初是个紫色的封面),现在可能已经改了N版。该书我们在学习完二叉树后,就是学习栈、堆,再然后就是学习 DFS / BFS,之后就是图(Graph)。

因为图比较难(分为无向图和有向图),因此,才先学习 DFS / BFS,图的用处很广(小到社区便利设施搭建,大到城市道路规划、高铁站等),因此,掌握了 DFS,至少对理解图是很有用的,而很多算法题,也涉及到 DFS。

那说了这么多,什么是 DFS ?先来看个图:

dfs.png

如果我们要完整的遍历该结构(所有路径,每个节点只能访问一次),方法是:

  • A -> B -> E (深度优先);
  • A -> B -> C -> D (广度优先);

两种优先的思想:

  • 深度优先很简单:先沿着一条路遍历下去,直到没有路;
  • 广度优先则是:先遍历当前节点的所有子节点(A的子节点就是 B、C、D);然后,再依次遍历子节点的子节点;

很明显,上面这个图,我们用 DFS 更简单,也更快速:

  1. A -> B -> E;
  2. C -> F -> G -> H -> D;

遇到 A时结束;

三、基于 DFS 优化代码逻辑

我们先来通过代码截图,来了解该数据结构:

  • projects 是个列表,每个元素都是 sites;
  • sites 也是个列表,每个元素都是 countries;
  • countries也是列表,每个元素含有 locals 和 currencies;

将列表展开,最终组合为一个列表,每个对象都含有:

[
    {
        project: project.name,
        siteId: site.siteId,
        countryCode: country.countryCode,
        localCode: local.localCode,
        currencyCode: currency.currencyCode,
        host: site.host
    },
    ......
]

思想嘛,就是从头开始遍历,一直遍历到叶子节点,即 country,那么简单了,我给出了 DFS 的 demo,并没有帮他去写这段逻辑(不想因为是拿来主义)。

<!DOCTYPE html>
<html>
<head>
    <title>test</title>
</head>
<body>

    <script type="text/javascript">
         // DFS
        function combines (obj, kvs = [], list, comb = {}) {
            // 如果 kvs 为 0,表明已经到了叶子节点
            // 加入到 list 中,返回上一级,继续 DFS
            if (kvs.length === 0) {
                list.push(Object.assign({}, comb));
                return;
            }

            // 从 kvs 中取出首元素(KV)
            const keyAndValue = kvs.shift();
            let k = Object.keys(keyAndValue)[0], v = keyAndValue[k];

            const data = obj[k];
            if (Array.isArray(data)) {
                // 深度遍历
                for (let i = 0; i < data.length; i ++) {
                    comb[v] = data[i][v];
                    combines(data[i], kvs, list, comb);
                }
            }
            // 返回到上一级时,我们需要将该 kv 放回到数组首位置
            // 否则上一级的下一个元素遍历时,kvs 就空了(因为 kvs 是索引传递,不是值拷背传递)
            kvs.unshift(keyAndValue);
        }

        // 构造测试数据
        var ks = ['project', 'site', 'city'];
        function genData (index) {
            let list = [];
            for (let i = 0; i < 10; i ++) {
                var obj = {};
                obj[ks[index] + 'Id'] = Math.random();
                if (index+1 < ks.length) {
                    obj[ks[index+1] + 's'] = genData(index+1);
                }
                list[i] = obj;
            }
            return list;
        }

        // 构造大对象,分别嵌套 ks
        var o = {projects: genData(0)};

        // 平铺成一级列表 list
        var list = []
        // 将 o 转化为 list
        combines(o, [{projects: 'projectId'},{sites: 'siteId'},{citys: 'cityId'}], list)
        console.log(list);
    </script>
</body>
</html>

当然,该算法只是给了朋友去参考,实际,怎么也得动手稍微修改一个 combines 的 kvs,来满足他自己的需求。

这里的 DFS 还是最简单,最基本的,并没有考虑数据重复后,要『剪枝』的情况,因为,朋友的实际项目不存在构造出来的数据是重复的。

要想真正学习 DFS 并掌握,还是有一定难度的,多看看算法方面的题,多想多练才能逐渐掌握!

相关文章

  • 活学活用 DFS

    一、前言 今天小伙伴给我截了个图,吐糟公司的恶心的需求,需要将一个大的、嵌套列表展开(平铺)成一级列表,然后,哼哧...

  • 各种DFS

    DFS邻接矩阵遍历图 DFS邻接表遍历图 DFS回溯(不走重复路径) DFS背包(可重复选) DFS背包(不可重复选)

  • HDFS shell操作

    创建目录hdfs dfs -mkdir 查看所有目录hdfs dfs -ls / 上传文件hdfs dfs -pu...

  • Binary Tree(2)

    BFS vs DFS for Binary Tree What are BFS and DFS for Binar...

  • Clone Graph (Leetcode 133)

    DFS Approach: 注意,对于DFS,对map的赋值要在DFS loop开始以前。这样可以避免由于grap...

  • hdfs的命令行使用

    语法:hdfs dfs 参数 hdfs dfs -ls / 查看根路径下面的文件或文件夹 hdfs dfs -mk...

  • DFS与N皇后问题

    DFS与N皇后问题 DFS 什么是DFS DFS是指深度优先遍历也叫深度优先搜索。 它是一种用来遍历或搜索树和图数...

  • DFS及其应用

    内容概要: DFS类的实现 DFS求解连通分量 DFS求解点对之间的一个路径 DFS判定无环图和二分图 相关概念 ...

  • 684. 冗余连接

    主要掌握并查集/dfs/拓扑排序.dfs里要注意从后面开始查,特别是dfs函数如何设计以及

  • 剑指 Offer II 102. 加减的目标值

    首先想到的dfs 好家伙 1500ms。感觉差点就超时了= =。。dfs总是这样= =。。 优化写法 另类的dfs...

网友评论

      本文标题:活学活用 DFS

      本文链接:https://www.haomeiwen.com/subject/gqjkcltx.html