【JavaScript 算法】拓扑排序:有向无环图的应用

news2024/11/13 9:36:21

在这里插入图片描述

🔥 个人主页:空白诗

在这里插入图片描述

文章目录

    • 一、算法原理
    • 二、算法实现
      • 方法一:Kahn算法
      • 方法二:深度优先搜索(DFS)
      • 注释说明:
    • 三、应用场景
    • 四、总结

在这里插入图片描述

拓扑排序(Topological Sorting)是一种线性排序方法,适用于有向无环图(DAG, Directed Acyclic Graph),它能够为图中的节点安排一个线性序列,使得对于图中的每一条有向边(u, v),顶点u在序列中出现在顶点v之前。拓扑排序在许多实际应用中都有重要作用,如任务调度、课程安排、编译依赖等。本文将详细介绍拓扑排序的原理、实现及其应用。


一、算法原理

拓扑排序的基本思想是:

  1. 选择一个入度为0的节点,将其输出到排序结果,并从图中删除该节点及其关联的所有边。
  2. 重复步骤1,直到所有节点都被输出,或者图中仍存在入度不为0的节点(此时图中存在环,无法进行拓扑排序)。

常用的两种实现拓扑排序的方法是Kahn算法和深度优先搜索(DFS)。


二、算法实现

方法一:Kahn算法

DFS

Kahn算法利用队列实现拓扑排序,通过不断删除入度为0的节点来构建拓扑序列。

/**
 * Kahn算法实现拓扑排序
 * @param {Object} graph - 图的邻接表表示
 * @return {string[]} - 拓扑排序结果
 */
function kahnTopologicalSort(graph) {
  const inDegree = {}; // 记录每个节点的入度
  const queue = []; // 存储入度为0的节点
  const result = []; // 存储拓扑排序结果

  // 初始化入度表
  for (const node in graph) {
    inDegree[node] = 0;
  }

  // 计算每个节点的入度
  for (const node in graph) {
    for (const neighbor of graph[node]) {
      inDegree[neighbor]++;
    }
  }

  // 将入度为0的节点加入队列
  for (const node in inDegree) {
    if (inDegree[node] === 0) {
      queue.push(node);
    }
  }

  // 处理队列中的节点
  while (queue.length > 0) {
    const node = queue.shift(); // 取出队首节点
    result.push(node); // 将节点加入拓扑排序结果

    // 减少相邻节点的入度
    for (const neighbor of graph[node]) {
      inDegree[neighbor]--;
      // 如果相邻节点的入度为0,加入队列
      if (inDegree[neighbor] === 0) {
        queue.push(neighbor);
      }
    }
  }

  // 检查是否存在环
  if (result.length !== Object.keys(graph).length) {
    throw new Error("图中存在环,无法进行拓扑排序");
  }

  return result;
}

// 示例
const graph = {
  A: ['C'],
  B: ['C', 'D'],
  C: ['E'],
  D: ['F'],
  E: ['H', 'F'],
  F: ['G'],
  G: [],
  H: []
};

console.log(kahnTopologicalSort(graph)); // 输出: [ 'A', 'B', 'D', 'C', 'E', 'F', 'H', 'G' ]

方法二:深度优先搜索(DFS)

DFS

DFS方法通过递归遍历图,将访问过的节点存入栈中,最终从栈顶依次取出节点构建拓扑序列。

/**
 * 深度优先搜索实现拓扑排序
 * @param {Object} graph - 图的邻接表表示
 * @return {string[]} - 拓扑排序结果
 */
function dfsTopologicalSort(graph) {
  const visited = new Set(); // 记录已访问的节点
  const stack = []; // 存储拓扑排序结果

  /**
   * 递归函数:DFS遍历节点
   * @param {string} node - 当前节点
   */
  function dfs(node) {
    if (visited.has(node)) return;
    visited.add(node); // 标记节点为已访问

    for (const neighbor of graph[node]) {
      dfs(neighbor); // 递归访问相邻节点
    }

    stack.push(node); // 当前节点处理完毕,加入栈中
  }

  // 遍历所有节点,进行DFS
  for (const node in graph) {
    dfs(node);
  }

  return stack.reverse(); // 返回栈的逆序,即拓扑排序结果
}

// 示例
console.log(dfsTopologicalSort(graph)); // 输出: [ 'B', 'D', 'A', 'C', 'E', 'H', 'F', 'G' ]

注释说明:

  1. Kahn算法

    • inDegree:记录每个节点的入度。
    • queue:存储入度为0的节点。
    • result:存储拓扑排序结果。
    • 初始化入度表,并计算每个节点的入度。
    • 将入度为0的节点加入队列,处理队列中的节点,更新相邻节点的入度。
    • 最终检查是否存在环,返回拓扑排序结果。
  2. DFS方法

    • visited:记录已访问的节点。
    • stack:存储拓扑排序结果。
    • 递归遍历节点,将访问过的节点存入栈中,最终返回栈的逆序。

三、应用场景

  1. 任务调度:根据任务之间的依赖关系,确定任务的执行顺序。
  2. 课程安排:根据课程的先修关系,确定课程的学习顺序。
  3. 编译依赖:根据文件的依赖关系,确定编译的顺序。
  4. 数据处理:根据数据的依赖关系,确定处理的顺序。

四、总结

拓扑排序是一种用于有向无环图(DAG)的线性排序方法,通过Kahn算法和DFS方法可以实现拓扑排序,广泛应用于任务调度、课程安排、编译依赖和数据处理等场景。理解和掌握拓扑排序算法,对于解决实际问题具有重要意义。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1937167.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

测试数据科学家深度学习基础知识的 45 个问题(以及解决方案)

测试数据科学家深度学习基础知识的 45 个问题(以及解决方案) 一、介绍 早在2009年, 深度学习还只是一个新兴领域。只有少数人认为这是一个富有成效的研究领域。今天,它被用于开发应用程序,这些应用程序在一段时间前被认为是困难或不可能做到的。 语音识别、图像识别、在数…

<Qt> 初识Qt

目录 一、项目文件解析 widget.h main.cpp widget.cpp widget.ui .pro文件 二、QT 实现Hello World程序 (一)按钮控件 1. 纯代码 2. 图形化 (二)标签控件 1. 纯代码 2. 图形化 三、内存泄漏问题 四、qdebug()的使用…

MySQL(事务、索引)MyBatis

目录 事务 概述 四大特性(ACID) 索引 结构 语法 MyBatis 数据库连接池 lombok 基本操作--增删改查 根据主键删除 新增 更新 查询(根据ID查询) 查询(条件查询) XML映射文件 动态SQL 动态条…

Web安全:未验证的重定向和转发.

Web安全:未验证的重定向和转发. 未验证的重定向和转发漏洞是一种常见的Web安全漏洞,它允许攻击者将用户重定向到一个恶意的URL,而不是预期的安全URL。这种漏洞通常发生在应用程序处理重定向和转发请求时,未能对目标URL进行适当的…

RDMA 高性能架构基本原理与设计方案

在进行本文的学习学习之前,我们先对RDMA是什么做一个简单的科普与认识:一文带你了解什么是RDMA-CSDN博客 目录: 目录: 一、RDMA和传统网络方案的比较 1.1 传统网络方案: 1.1.1 缺点一:以太网卡&#xff0…

单机、集群、分布式服务器比较:

1. 单机服务器的瓶颈: 单机服务器:一台服务器独立运行一个工程所需的全部的业务模块 受限于服务器硬件资源,所承受用户并发量受限,32位linux操作系统最大并发量为两万任一模块的变动和修改,都会导致整个项目代码重新编…

移动端如何离线使用GPT

在移动端离线使用GPT,只需要一个app:H2O AI Personal GPT 是H2OAI上架的一款app,可离线使用,注重数据隐私,所有数据都只存储在本地。对H2OAI感兴趣的伙伴,可移步:https://h2o.ai 该app支持的模…

华为od 100问 持续分享6-入职体检

我是一名软件开发培训机构老师,我的学生已经有上百人通过了华为OD机试,学生们每次考完试,会把题目拿出来一起交流分享。 重要:2024年5月份开始,考的都是OD统一考试(D卷),题库已经整…

如何学习Kafka:糙快猛的大数据之路(快速入门到实践)

在大数据开发的世界里,Kafka 无疑是一个不可或缺的重要角色。作为一个分布式流处理平台,它以其高吞吐量、可靠性和可扩展性而闻名。 目录 糙快猛学习法则Kafka 是什么?我的 Kafka 学习故事第一步: 快速上手第二步: 生产和消费消息第三步: 编写简单的生产者和消费者程序 深入Ka…

达梦数据库 DISQL连接数据库与执行SQL、脚本的方法

DISQL连接数据库与执行SQL、脚本的方法 1.DISQL介绍2.DISQL连接数据库的方法2.1 本地连接2.2 远程连接2.3 CONN连接 3.执行SQL、脚本的方法3.1 通过DISQL登录后在字符界面3.2 启动DISQL时运行脚本3.3 进入DISQL后,通过start命令运行脚本3.4 使用EDIT命令编辑脚本 1.…

(02)Unity使用在线AI大模型(调用Python)

目录 一、概要 二、改造Python代码 三、制作Unity场景 一、概要 查看本文需完成(01)Unity使用在线AI大模型(使用百度千帆服务)的阅读和实操,本文档接入指南的基础上使用Unity C#调用百度千帆大模型,需要…

【开发踩坑】使用PageHelper工具正常sql后面多无关语句

背景 SQL日志打印出现了脏东西: 本来结束的 where muc.code ?;后面凭空多出了一个 LIMIT语句 ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your …

【Spark On Hive】—— 基于电商数据分析的项目实战

文章目录 Spark On Hive 详解一、项目配置1. 创建工程2. 配置文件3. 工程目录 二、代码实现2.1 Class SparkFactory2.2 Object SparkFactory Spark On Hive 详解 本文基于Spark重构基于Hive的电商数据分析的项目需求,在重构的同时对Spark On Hive的全流程进行详细的…

Unity点击生成节点连线

Unity点击生成节点连线 效果 2.主要代码 Test_Line 控制类 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems;public class Test_Line : MonoBehaviour {public GameObject qiu_prefab;public List<Game…

基于 CNN(二维卷积Conv2D)+LSTM 实现股票多变量时间序列预测(PyTorch版)

前言 系列专栏:【深度学习&#xff1a;算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域&#xff0c;讨论了各种复杂的深度神经网络思想&#xff0c;如卷积神经网络、循环神经网络、生成对…

android13读取cpu频率,并调整频率

总纲 android13 rom 开发总纲说明 目录 1.前言 2.频率类型 3.获取cpu可以调节的频率 4.获取当前频率 5.设置频率 6.最后我们写个脚本,来实现,可以通过参数获取所有cpu的频率,以及设置最大最小频率 6.1 获取cpu频率 6.2 设置最大cpu频率 6.3 设置最小 7.彩蛋 1.前…

敏捷开发笔记(第12章节)--接口隔离原则(ISP)

目录 1&#xff1a;PDF上传链接 12.1&#xff1a;接口污染 12.2&#xff1a;分离客户就是分离接口 12.3&#xff1a;接口隔离原则&#xff08;ISP&#xff09; 12.4&#xff1a;类接口与对象接口 12.4.1&#xff1a;使用委托分离接口 12.4.2&#xff1a;使用多重继承分离接口 …

基于JAVA+SpringBoot+Vue+uniApp的校园日常作品商品分享小程序

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、SpringCloud、Layui、Echarts图表、Nodejs、爬…

为什么精酿人士选择FENDI CLUB啤酒

FENDI CLUB啤酒作为云仓酒庄平台的精酿啤酒自有品牌&#xff0c;平台提供以技术咨询与服务为核心的全产业链精酿产品解决方案&#xff0c;帮助啤酒代理商提高产品质量&#xff0c;树立优质品牌&#xff0c;推广精酿文化&#xff0c;促进精酿发展&#xff0c;力争成为中国本土品…

Leetcode3208. 交替组 II

Every day a Leetcode 题目来源&#xff1a;3208. 交替组 II 解法1&#xff1a;环形数组 把数组复制一份拼接起来&#xff0c;和 3101 题一样&#xff0c;遍历数组的同时&#xff0c;维护以 i 为右端点的交替子数组的长度 cnt。 如果 i ≥ n 且 cnt ≥ k&#xff0c;那么 i…