【数据结构与算法 | 图篇】拓扑排序

news2024/11/17 8:28:01

1. 概念

拓扑排序是是一种针对有向无环图进行的排序方法。它将图中所有顶点排成一个线性序列,使得对于图中的每一条有向边(u, v),顶点u在序列中都出现在顶点v之前。

适用范围:

  • 拓扑排序只适用于有向无环图。

结果非唯一:

  • 对于同一个图,可能存在多个合法的拓扑排序序列。

不存在拓扑排序的情况:

  • 如果图中含有环,则无法进行拓扑排序,因为环内的节点无法确定先后。

2. 思路1(基于队列):

初始化:

找到所有入度为0的节点,并将它们加入到队列。

迭代过程:

从队列中取出一个节点并输出;对于该节点指向的所有邻接节点,减少它们的入度值。如果某个邻接节点的入度变为0,则将其入队。

结束条件:

队列为空时停止。如果输出的节点数量等于图中总节点数,则拓扑排序成功;否则说明图中有环。

3. Java代码实现

@Test
    public void test() {
        Vertex v1 = new Vertex("网页基础");
        Vertex v2 = new Vertex("JAVA基础");
        Vertex v3 = new Vertex("数据库");
        Vertex v4 = new Vertex("JAVA WEB");
        Vertex v5 = new Vertex("Spring框架");
        Vertex v6 = new Vertex("微服务框架");
        Vertex v7 = new Vertex("实战项目");
        // JDK版本太低,用不了of方法
        v1.edges = new ArrayList<>();
        v1.edges.add(new Edge(v4));

        v2.edges = new ArrayList<>();
        v2.edges.add(new Edge(v4));

        v3.edges = new ArrayList<>();
        v3.edges.add(new Edge(v5));

        v4.edges = new ArrayList<>();
        v4.edges.add(new Edge(v5));

        v5.edges = new ArrayList<>();
        v5.edges.add(new Edge(v6));

        v6.edges = new ArrayList<>();
        v6.edges.add(new Edge(v7));

        v7.edges = new ArrayList<>();

        // 拓扑排序:
        List<Vertex> list = new ArrayList<>();
        list.add(v1);
        list.add(v2);
        list.add(v3);
        list.add(v4);
        list.add(v5);
        list.add(v6);
        for(Vertex v : list){
            for(Edge i : v.edges){
                i.linked.InDegree++;
            }
        }
        Deque<Vertex> queue = new LinkedList<>();
        // 将入度为0的节点入队
        for (Vertex v : list){
            if(v.InDegree == 0){
                queue.offer(v);
            }
        }
        while(!queue.isEmpty()){
            Vertex poll = queue.poll();
            System.out.print(poll.name + "  ");
            for(Edge i : poll.edges){
                i.linked.InDegree--;
                if(i.linked.InDegree == 0){
                    queue.offer(i.linked);
                }
            }
        }
    }


public class Vertex {
    // 顶点的名字,用来区分顶点
    String name;
    // 与该顶点有关的边的集合
    List<Edge> edges;
    // 判断是否已经被遍历
    boolean visited = false;
    // 入度
    int InDegree;
    public Vertex(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

节点情况如下:

de5a8ff3ac5d48ef95a9cc4c07fe9966.png

4. 有环的情况判断1:

如果输出的节点数量等于图中总节点数,则拓扑排序成功;否则说明图中有环.

举个例子:假如"微服务框架"和"实战项目"两个节点间存在环,思想是如果入度为0就输出。网页基础和java基础先输出,然后是数据库和java web,然后是Spring框架,Spring框架被输出后,微服务框架的入度减1,此时微服务框架的入度为1,且删不了,所以连带 着微服务框架和实战也就都输出不了。此时输出的节点数肯定是小于图中总的节点数。

5. 思路2(基于队列)

通过深度优先搜索遍历图中的所有节点,如果遇到一个没有被访问过的节点,就递归的访问它的所有邻接节点,然后将该节点添加到结果列表的开头。

6. 代码实现

@Test
    public void test() {
        Vertex v1 = new Vertex("网页基础");
        Vertex v2 = new Vertex("JAVA基础");
        Vertex v3 = new Vertex("数据库");
        Vertex v4 = new Vertex("JAVA WEB");
        Vertex v5 = new Vertex("Spring框架");
        Vertex v6 = new Vertex("微服务框架");
        Vertex v7 = new Vertex("实战项目");
        // JDK版本太低,用不了of方法
        v1.edges = new ArrayList<>();
        v1.edges.add(new Edge(v4));

        v2.edges = new ArrayList<>();
        v2.edges.add(new Edge(v4));

        v3.edges = new ArrayList<>();
        v3.edges.add(new Edge(v5));

        v4.edges = new ArrayList<>();
        v4.edges.add(new Edge(v5));

        v5.edges = new ArrayList<>();
        v5.edges.add(new Edge(v6));

        v6.edges = new ArrayList<>();
        v6.edges.add(new Edge(v7));

        v7.edges = new ArrayList<>();

        List<Vertex> list = new ArrayList<>();
        list.add(v1);
        list.add(v2);
        list.add(v3);
        list.add(v4);
        list.add(v5);
        list.add(v6);
        list.add(v7);
        Deque<String> stack = new LinkedList<>();
        for(Vertex v : list){
            dfs(v, stack);
        }
        System.out.println(stack);
    }
    public static void dfs(Vertex v, Deque<String> stack){
        // 发现这个节点已经被拓扑排序遍历过,返回
        if(v.status == 2){
            return;
        }
        // 发现这个节点未放入栈中,此时遍历到了,发现有环
        if(v.status == 1){
            throw new RuntimeException("出现环");
        }
        // v.status = 1表示这个节点正在处理中
        v.status = 1;
        for(Edge i : v.edges){
            dfs(i.linked, stack);
        }
        v.status = 2;
        stack.push(v.name);
    }


public class Vertex {
    // 顶点的名字,用来区分顶点
    String name;
    // 与该顶点有关的边的集合
    List<Edge> edges;
    // 判断是否已经被遍历
    boolean visited = false;
    // 入度
    int InDegree;
    // 0表示未访问,1表示访问中,2表示在拓扑排序
    int status;
    public Vertex(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

7. 有环情况的判断2:

基于队列实现判断有环的这个情况就更简单了。

还是假如"微服务框架"和"实战项目"两个节点间存在环,此时一直递归,"微服务框架"的状态被标记为了1,然后继续递归它的邻接点,也就是遍历"实战项目"该节点,如果正常情况下,可以更新状态放入栈以后可以开始返回了,但如果有环(有从"微服务框架"指向"实战项目"的有向边,也有"实战项目"指向"微服务框架"的有向边),此时"实战项目"该节点存在邻接点"微服务框架",递归"微服务框架"该顶点,发现这个顶点的状态是1(并没有处理完拓扑排序),说明有环.

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

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

相关文章

阿里云ubuntu系统安装mysql8.0

一、安装mysql8.0 1.已安装其他版本的mysql&#xff0c;需要删除 若没有不需要此操作 1 #卸载MySQL5.7版本 2 apt remove -y mysql-client5.7* mysql-community-server5.7* 4 # 卸载5.7的仓库信息 5 dpkg-l | grep mysql | awk iprint $2} | xargs dpkg -P2.更新仓库 apt u…

FASTSPEECH 2论文阅读

FASTSPEECH 2: FAST AND HIGH-QUALITY END-TOEND TEXT TO SPEECH 现状 非自回归模型可以在质量相当的情况下显著快于先前的自回归模型合成模型。但FastSpeech模型训练依赖与自回归教师模型进行时长预测&#xff08;提供更多的信息作为输入&#xff09;和知识蒸馏&#xff08;…

【开端】Java中判断一个对象是否是空内容

一、绪论 在Java中&#xff0c;我们常常使用的到的就是封装&#xff0c;为什么要封装&#xff0c;封装有什么好处。首先在系统开发过程中&#xff0c;其实很多功能和场景都共性的。那么为了避免重复造轮子&#xff0c;我们这时就使用到了封装。封装可以一次造轮子&#xff0c;无…

数据集搜索

1. 数据集和数据集的分类 数据集是一组数据的集合&#xff0c;通常用于机器学习、统计分析、数据挖掘等领域&#xff0c;帮助算法训练、模型验证和评估。可以是各种形式的数据&#xff0c;如表格、图像、机器学习相关的文件等。 根据在机器学习中的应用&#xff0c;数据集可以…

1. MongoDB概念解析

1. 概念解析 在 MongoDB 中基本的概念是文档、集合、数据库。 SQL 术语/概念MongoDB 术语/概念解释/说明databasedatabase数据库tablecollection数据库表/集合rowdocument数据记录行/文档columnfield数据字段/域indexindex索引table joins表连接,MongoDB不支持primary keypri…

1.3 数据库的发展历史与演变

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; 工&#x1f497;重&#x1f497;hao&#x1f497;&#xff1a;野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题.…

鸿萌数据恢复服务: 如何修复 SQL Server 数据库错误 829?

天津鸿萌科贸发展有限公司从事数据安全服务二十余年&#xff0c;致力于为各领域客户提供专业的数据恢复、数据备份、网络及终端数据安全等解决方案与服务。 同时&#xff0c;鸿萌是众多国际主流数据恢复软件(Stellar、UFS、R-Studio、ReclaiMe Pro 等)的授权代理商&#xff0c…

pandas 笔记crosstab

用来计算两个&#xff08;或更多&#xff09;因子的交叉表&#xff08;即频率表、列联表或透视表&#xff09;。这个功能特别适用于统计分析和数据探索阶段&#xff0c;帮助理解不同变量之间的关系 1 基本用法 pd.crosstab(index, columns, valuesNone, rownamesNone, colnam…

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(二)---ROS2与UE5进行图像数据传输

前言 本系列教程旨在使用UE5配置一个具备激光雷达深度摄像机的仿真小车&#xff0c;并使用通过跨平台的方式进行ROS2和UE5仿真的通讯&#xff0c;达到小车自主导航的目的。本教程默认有ROS2导航及其gazebo仿真相关方面基础&#xff0c;Nav2相关的学习教程可以参考本人的其他博…

HarmonyOS-MPChart以X轴或y轴为区间设置不同颜色

本文是基于鸿蒙三方库mpchart OpenHarmony-SIG/ohos-MPChart 的使用&#xff0c;以X轴为区间设置不同的曲线颜色。 mpchart本身的绘制功能是不支持不同区间颜色不同的曲线的&#xff0c;那么当我们的需求曲线根据x轴的刻度区间绘制不同颜色&#xff0c;就需要自定义绘制方法了。…

LVS (Linux virual server)

LVS简介 LVS&#xff08;Linux Virtual Server&#xff09;是一个基于Linux平台的开源负载均衡系统。它通过将多个服务器组成一个虚拟服务器集群&#xff0c;实现了高效的负载均衡和流量分发。 LVS的核心思想是利用IP负载均衡技术和内容请求分发机制&a…

传知代码-【CLIP】文本也能和图像配对

代码以及视频讲解 本文所涉及所有资源均在传知代码平台可获取 概述 模态&#xff1a;数据的一种形式&#xff0c;如图像、文本、声音、点云等。 多模态学习&#xff0c;就是利用模型同时处理多个模态数据&#xff0c;有助于提高模型的准确性和泛化能力。在自动驾驶场景中&am…

利用住宅代理应对机器人流量挑战:识别、使用与检验指南

引言 什么是机器人流量&#xff1f;其工作原理是什么&#xff1f; 机器人流量来自哪里&#xff1f; 合法使用机器人时如何避免被拦截&#xff1f; 如何检验恶意机器人流量&#xff1f; 总结 引言 你是否曾经遇到过访问某个网站时&#xff0c;被要求输入验证码或完成一些其…

源代码加密的意义和办法?

一、源代码加密的意义1、防止恶意修改&#xff1a;未加密的源代码容易被恶意用户或竞争对手获取并修改&#xff0c;以植入恶意代码或病毒&#xff0c;损害软件的功能性和安全性。加密后的源代码即使被非法获取&#xff0c;也无法修改或理解&#xff0c;从而防止了被破坏的风险。…

品味白酒的四大步骤,体验不一样的美酒人生

在华夏千年的文化传承中&#xff0c;白酒如同一部厚重的历史长卷&#xff0c;每一滴都蕴含着丰富的故事与智慧。豪迈白酒&#xff08;HOMANLISM&#xff09;&#xff0c;作为这长卷中的璀璨篇章&#xff0c;更是以其不同的魅力&#xff0c;吸引着无数品鉴者去探寻其中的奥秘。今…

android13 禁用wifi

总纲 android13 rom 开发总纲说明 目录 1.前言 2.情况分析 3.代码分析 3.1 代码位置1 3.2 代码位置2 3.3 代码位置3 4.代码修改 5. 彩蛋 1.前言 这个文章讲的是,在frameworks里面禁止打开wifi。 2.情况分析 我们打开wifi一般是 public static void turnOnWifi(Co…

Linux修改ssh默认端口22为其他端口2024

一、修改配置文件 修改ssh服务的配置文件&#xff1a; /etc/ssh/sshd_config 将Port 22放开注释&#xff0c;并将22修改为2024&#xff0c;并保存 二、重启sshd服务 systemctl restart sshd 三、重启服务失败 如果重启服务失败&#xff0c;可以执行以下命令&#xff1a; …

web 自动化测试,一定得掌握的 8 个核心知识点

使用 cypress 进行端对端测试&#xff0c;和其他的一些框架有一个显著不同的地方&#xff0c;它使用 javascript 作为编程语言。传统主流的 selenium 框架是支持多语言的&#xff0c;大多数 QA 会的python 和 java 语言都可以编写 selenium 代码&#xff0c;遇到需要编写 js 代…

HoloLens 和 Unity 空间坐标系统 Coordinate systems

坐标系统 Spatial coordinate systems 所有的 3D 图形应用程序都使用笛卡尔坐标系统来推理虚拟物体的位置和朝向。 这些坐标系建立三个垂直轴&#xff1a;X、Y 和 Z。 添加到场景的每个对象在其坐标系中都有一个 XYZ 位置。 Windows 调用在物理世界中具有实际意义的坐标系统…

Win10系统配置JDK和Maven环境变量

目录 一、Win10系统配置JDK和Maven环境变量 二、测试 配置环境变量可以不用cd到应用程序的bin目录&#xff0c;就可以运行。配置环境变量可以方便IDE开发工具识别JDK和Maven 省去了手动选择。 一、Win10系统配置JDK和Maven环境变量 1、右键我的电脑>属性&#xff0c;弹出…