一个vuepress配置问题,引发的js递归算法思考

这篇具有很好参考价值的文章主要介绍了一个vuepress配置问题,引发的js递归算法思考。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

这两天在尝试用语雀+ vuepress + github 搭建个人博客。

小破站地址 :王天的 web 进阶之路

语雀作为编辑器,发布文档推送 github,再自动打包部署,大概流程如下。
一个vuepress配置问题,引发的js递归算法思考

问题

我使用的elog插件批量导出语雀文档。elog采用的配置是所有文章平铺导出,没有按照语雀知识库目录生成markdown,这导致 vuepress 侧边栏无法和语雀一致,如下图。

一个vuepress配置问题,引发的js递归算法思考
上图,左侧是语雀知识库,右侧是导出到 vuepress 展示的效果,很明显没有目录这很影响阅读体验呀

解决

在查阅 vuepress 文档后,发现配置silderbar.ts可以自定义侧边栏目录,配置参数如下:

export default {
  theme: defaultTheme({
    // 可折叠的侧边栏
    sidebar: {
      "/web/": [
        {
          text: "王天的web进阶手册",
          collapsible: true, // 目录是否折叠
          children: ["/reference/cli.md", "/reference/config.md"], // 文档目录
        },
        {
          text: "王天的魔法工具箱",
          collapsible: true,
          children: [
            "/reference/bundler/vite.md",
            "/reference/bundler/webpack.md",
          ],
        },
      ],
    },
  }),
};

递归生成菜单

配置sidebar.ts 可以修改左侧菜单,但是一个个手动修改这忒麻烦了啊啊啊啊。那如何批量生产菜单配置项呢?

递归函数呀呀呀呀呀呀 🔥🔥🔥🔥

elog 在同步语雀文档时,会自动创建elog.cache.json缓存文件,在 vueprss 项目根目录中查看。

打开elog.cache.json文件,我们能看到语雀文档知识库的数据结构

"catalog": [
    {
      "type": "DOC",
      "title": "前言",
      "uuid": "17Os-_V_hcS37KOD",
      "url": "wqbpyf5083qc7ho8",
      "prev_uuid": "",
      "sibling_uuid": "dmQSRn6AXUBSg96x",
      "child_uuid": "",
      "parent_uuid": "",
      "doc_id": 141216125,
      "level": 0,
      "id": 141216125,
      "open_window": 1,
      "visible": 1
    }
  ]

catlog 属性是文档缓存数据,关键字段:

  • type:值为'DOC' 是文章、值为 TITLE 则为目录
  • uuid:文章 id
  • prent_uuid:父节点的 uuid

咱们根据以上参数,编写递归函数, 将elog.cache.json的一维数组,递归生成 vuepress 侧边栏配置数据
代码如下:

function genYuqueRoute() {
  // 参数1:遍历数组
  // 参数2:父菜单id
  const deep = (arrlist, parantId) => {
    let forList: any[] = [];
    arrlist.forEach((element) => {
      // 菜单id不一致,跳出循环调用
      if (element.parent_uuid !== parantId) return;
      // 如果是TITLE类型新增配置项
      if (element.type === "TITLE") {
        forList.push({
          text: element.title,
          collapsible: true,
          children: deep(arrlist, element.uuid),
        });
        // 如果是DOC 类型追加文件地址
      } else {
        forList.push(element.url + ".md");
      }
    });
    return forList;
  };
  return deep(catalog, "");
}

效果

一个vuepress配置问题,引发的js递归算法思考

敲重点啦!

递归函数本质上是一个在回调自身的函数,用于改造数据结构,重点在于跳出循环的机制,否则陷入死循环啦

DFS vs BFS ?

什么是 DFS 、BFS ?

  • DFS 深度优先搜索:可以用于找到一条路径、判断图中是否存在循环、拓扑排序、生成连通分量等。
  • BFS 广度优先搜索:可以用于找到最短路径、生成最小生成树、进行网络分析等。

:::danger
🧚🏻‍♀️ 简单理解为,横向 、竖向 遍历据状结构

  • 深度优先搜索,对数据结构的横向执行,从第一行遍历子节点、叶子节点,依次直到最后一行。
  • 广度优先搜索,对数据结构的竖向执行,把树结构平面铺开、以层级数为列数,从第一列依次执行。
    :::

将深度搜索、广度搜索代入到生活场景更容易理解。

咱们先看一个家庭关系树状图,爷爷奶奶是一级属性、父母叔伯二级、孙子孙女三级属性、重孙们是四级属性,以此类推。形成一个家庭关系树状图。

假如奶奶过八十大寿,按辈分来,首先是父母叔伯这一辈祝寿,其次是孙子孙女辈分,最后重孙们,以此类推,这个竖向执行的祝寿过程就是广度优先搜索

那过年走亲戚的话,咱们没有俺辈分,去分批的吧?至少我们老家不是的,都是一去一家子呢。那这个横线执行的过程,就是深度优先搜索。

深度优先搜索(DFS)示例代码:

从 A 节点依次取出数据

// 图的邻接表表示
const graph = {
  A: ["B", "C"],
  B: ["D", "E"],
  C: ["F", "G"],
  D: [],
  E: [],
  F: [],
  G: [],
};

// 使用深度优先搜索遍历图
function dfs(graph, start) {
  const visited = new Set(); // 存储已访问节点的集合

  function traverse(node) {
    visited.add(node); // 将当前节点标记为已访问
    console.log(node); // 打印遍历的节点

    const neighbors = graph[node]; // 获取当前节点的邻居节点
    for (const neighbor of neighbors) {
      // 遍历当前节点的邻居节点
      if (!visited.has(neighbor)) {
        // 如果邻居节点未被访问过
        traverse(neighbor); // 递归遍历邻居节点
      }
    }
  }

  traverse(start); // 从起始节点开始进行深度优先搜索
  return visited; // 返回所有已访问的节点
}

输出结果:

dfs(graph, "A"); // 对图进行深度优先搜索,从起始节点 'A' 开始,并打印遍历结果
// A
// B
// D
// E
// C
// F
// G

在上述代码中,图使用邻接表表示,dfs 函数使用递归方式实现了深度优先搜索。从起始节点 'A' 开始,递归访问其邻居节点,并在访问时输出节点的值。

广度优先搜索(BFS)示例代码:

// 广度搜索 BFS
let graph = {
  A: ["B", "C"],
  B: ["A", "C", "D"],
  C: ["A", "D", "E"],
  D: ["B", "C", "E"],
  E: ["C", "D", "F"],
  F: ["E", "W"],
  W: ["C"],
};

function bfs(graph, startPoint) {
  let queue = []; // 用于存储待访问节点的队列
  let result = []; // 存储遍历结果的数组

  queue.push(startPoint); // 将起始节点添加到队列
  result.push(startPoint); // 将起始节点添加到遍历结果

  while (queue.length > 0) {
    // 当队列不为空时进行循环
    let point = queue.shift(); // 取出队列中的第一个节点作为当前节点
    let nodes = graph[point]; // 获取当前节点的所有邻居节点
    for (let node of nodes) {
      // 遍历当前节点的邻居节点
      if (result.includes(node)) continue; // 如果邻居节点已经在遍历结果中,则跳过
      result.push(node); // 将邻居节点添加到遍历结果中
      queue.push(node); // 将邻居节点添加到队列中,以便后续访问其邻居节点
    }
  }

  return result; // 返回遍历结果
}

console.log(bfs(graph, "B")); // 执行广度优先搜索,从起始节点 'B' 开始,并输出遍历结果

在上述代码中,图使用邻接表表示,bfs 函数使用队列实现了广度优先搜索。从起始节点 'A' 开始,将其加入队列并标记为已访问,然后依次从队列中取出节点,并访问其邻居节点,同时将邻居节点加入队列中,直到队列为空。

案例

深度优先搜索(DFS)和广度优先搜索(BFS)在前端项目中有许多实际的应用场景。下面有两个常见的前端开发项目案例

1、组件树遍历

在前端开发中,经常会有需要对组件树进行遍历的场景,例如渲染组件、查找组件等。下面是一个使用 DFS 进行组件树遍历的示例:

function dfs_component_traversal(component) {
  console.log(component); // 处理当前组件

  if (component.children) {
    for (const child of component.children) {
      dfs_component_traversal(child); // 递归遍历子组件
    }
  }
}

以上的代码展示了一个使用深度优先搜索进行组件树遍历的函数。我们可以根据组件的层级关系,从根组件开始递归地遍历每个组件及其子组件,以实现对整个组件树的遍历和操作。

这个算法可以帮助我们在前端项目中处理组件之间的关系,例如渲染组件、查找相关组件等。通过对组件树的深度遍历,我们可以有序地处理组件及其子组件,并执行相应的操作。

2、页面导航

在前端开发中,页面导航是一个常见的需求。我们可以使用广度优先搜索来实现页面导航功能,以确保按照层级关系有序地展示页面。

function bfs_page_navigation(page) {
  const queue = [page]; // 使用队列作为辅助数据结构来进行广度优先搜索

  while (queue.length > 0) {
    const current = queue.shift(); // 移除队列头部元素作为当前页面
    console.log(current); // 处理当前页面

    for (const child of current.children) {
      queue.push(child); // 将子页面加入队列
    }
  }
}

以上代码展示了一个使用广度优先搜索进行页面导航的函数。在这个函数中,我们使用队列作为辅助数据结构来进行广度优先搜索。通过不断将子页面加入队列,并按照队列中的顺序处理每个页面,可以实现按照层级关系有序地导航页面。

3、DFS + BFS 综合案例

const root = {
  value: 1,
  children: [
    {
      value: 2,
      children: [],
    },
    {
      value: 3,
      children: [
        {
          value: 7,
          children: [
            {
              value: 8,
              children: [],
            },
          ],
        },
      ],
    },
    {
      value: 4,
      children: [
        {
          value: 6,
          children: [],
        },
      ],
    },
  ],
};

// 在深度优先搜索 - 堆
// 我们首先处理当前节点,然后递归地处理每个子节点、直到叶子节点(没有子节点的节点),最后依次遍历完成
const digui = (node) => {
  console.log(node.value);
  if (node.children) {
    for (const children of node.children) {
      digui(children);
    }
  }
};
// 广度优先搜索-栈,把多维树结构,取出来平铺,依次访问。
// 在广度优先搜索中,我们使用队列来保存待访问的节点,确保按照层级顺序进行遍历。
// 每次从队列中取出队头节点,处理该节点后,将其邻居节点(子节点)入队,以便后续遍历。这样,就可以依次访问所有节点,并保持层级顺序。

function breadthFirstSearch(root) {
  if (!root) {
    return;
  }

  const queue = []; // 创建一个空队列,用于存放待访问的节点
  queue.push(root); // 将根节点入队

  while (queue.length !== 0) {
    // 当队列不为空时循环执行以下步骤
    const current = queue.shift(); // 出队队头节点作为当前节点
    console.log(current.value); // 进行二次加工或其他操作,这里简单地输出节点的值

    for (const child of current.children) {
      // 遍历当前节点的邻居节点(子节点)
      queue.push(child); // 将未访问过的邻居节点入队
    }
  }
}
console.log(digui(root));

console.log(breadthFirstSearch(root));

总结

递归函数本质上是一个在回调自身的函数,用于改造数据结构,重点在于跳出循环的机制,否则陷入死循环啦

深度优先搜索(DFS)的原理很简单:我们从起始节点开始,沿着一条路径不断向下探索,直到达到终点或者无法继续为止。如果遇到终点,就找到了一条路径;如果无法继续,则回溯到上一个节点,然后尝试探索其他路径。这个过程会递归地进行,或者使用栈来存储节点的顺序。

相比之下,广度优先搜索(BFS)的原理稍微有些不同:我们从起始节点开始,逐层地访问其邻居节点。也就是说,我们首先访问起始节点的邻居节点,然后是邻居节点的邻居节点,依此类推,直到遍历完所有节点或者找到目标节点为止。为了遍历节点的顺序,我们使用队列数据结构。

读者朋友好呀,我是王天~

尝试做过很多事情,汽修专业肄业生,半路出道的野生程序员、前端讲师、新手作者,最终还是喜欢写代码、乐于用文字记录热衷分享~

如文章有错误或者不严谨的地方,期待给于指正,万分感谢。

如果喜欢或者 有所启发,欢迎 star,对作者也是一种鼓励。

微信:「wangtian3111」,加我进王天唯一的读者群。

个人博客:https://itwangtian.com文章来源地址https://www.toymoban.com/news/detail-710728.html

到了这里,关于一个vuepress配置问题,引发的js递归算法思考的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 由select for update锁等待问题引发的深入思考

    关于 MySQL 的加锁机制,其实十分复杂,不同的隔离级别,是否是主键或索引,锁的粒度等等。很多工作了很多年的 MySQL DBA 也不能把各种加锁场景一一讲清楚。有时候一个简单的锁等待场景都值得深入研究,大家更多的是知其然而不知其所以然。本文介绍的是一个很常见的锁

    2024年03月09日
    浏览(35)
  • 「算法小记」-1:Ackermann函数/阿克曼函数的一点思考解法【递归/非递归/堆栈方法】(C++ )

    😎 作者介绍:我是程序员洲洲,一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号:程序员洲洲。 🎈 本文专栏:本文收录于洲洲的《算法小记》系列专栏,该专栏记录了许

    2024年02月08日
    浏览(47)
  • 一次网络不通 “争吵” 引发的思考

    \\\"你到底在说什么啊,我 K8s 的 ecs 节点要访问 clb 的地址不通和本地网卡有什么关系...\\\" 气愤语气都从电话那头传了过来,这时电话两端都沉默了。过了好一会传来地铁小姐姐甜美的播报声打断了刚刚的沉寂「乘坐地铁必须全程佩戴口罩,下一站西湖文化广场...」。 pod 需要访

    2024年02月12日
    浏览(37)
  • 【区块链】Ankr被黑引发的思考

    三明治交易、夹子机器人、抢跑、抢新、抢购、秒杀,相信这些词你都听说过了,区块链上的各种套利操作,基本上都有一个大前提,就是监听链上最新的未打包交易,才能在第一时间抢占先机。 前段时间Ankr被黑,黑客从中获利约500万美元,然而,让人惊讶的是,另一个套

    2024年02月02日
    浏览(47)
  • 由C# yield return引发的思考

        当我们编写 C# 代码时,经常需要处理大量的数据集合。在传统的方式中,我们往往需要先将整个数据集合加载到内存中,然后再进行操作。但是如果数据集合非常大,这种方式就会导致内存占用过高,甚至可能导致程序崩溃。     C# 中的 yield return 机制可以帮助我们

    2024年02月07日
    浏览(44)
  • 阿里云无影云电脑初体验及引发的思考

    有幸尝试阿里无影云电脑,记录下使用过程,并对云电脑进行思考。 ​ 阿里云无影云桌面( Elastic Desktop Service)的原产品名为弹性云桌面,融合了无影产品技术后更名升级。它可以为您提供易用、安全、高效的云上桌面服务,帮助您快速构建、高效管理桌面办公环境,提供安全

    2024年02月05日
    浏览(42)
  • ChatGPT引发的人机交互发展历程与升级思考

    ChatGPT自从去年12月火爆以来一直热度不减,最近正好研读了科技之巅,书中详细阐述了人机交互、人工智能、算力算法等技术的发展历史,本文主要围绕ChatGPT引发的人机交互方面的思考。 在讨论人机交互之前,首先需要说明的一点,目前计算机发展的结果已经从原来作为科

    2023年04月24日
    浏览(51)
  • 周星驰进军web3引发怎样的思考?

    谁能想到,向来低调的 周星驰 首次注册社交账号,竟是为了发布一条招人信息,挑选的还不是新片男女主角,而是Web3人才,一脚跨界到了互联网科技领域。 从年初就开始爆火的概念——Web3,到底是什么?能给我们带来什么?周星驰可能会往哪个方向创业? 要理解Web3,可能

    2023年04月08日
    浏览(42)
  • 由黑塞(Hessian)矩阵引发的关于正定矩阵的思考

    最近看论文,发现论文中有通过黑塞(Hessian)矩阵提高电驱系统稳定性的应用。所以本篇主要从Hessian矩阵的性质出发,对其中正定矩阵的判定所引发的想法进行记录。 (其实看论文出现黑塞很惊奇,因为前不久刚读了作家黑塞的《德米安:彷徨少年时》,所以在这一领域的黑塞

    2024年02月06日
    浏览(48)
  • 大页内存配置引发的数据库性能问题

    问题背景:         用户来电报故障,他们一套正常运行的Oracle数据库,突然出现了10分钟左右的性能卡顿问题,期间全部的业务操作都变慢,他们通过查看问题期间的awr报告,发现数据库在问题时间出现大量的libary cache等待事件,但每秒的硬解析并不高,不知道是什么原

    2024年02月21日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包