Java高阶数据结构 图补充-拓扑排序

news2024/11/24 12:44:49

拓扑排序

@在这里插入图片描述

文章目录

  • Java高阶数据结构 & 图补充-拓扑排序
    • 1. 什么是拓扑排序
    • 2. 拓扑排序算法思想-卡恩算法
    • 3. 拓扑排序代码实现
      • 3.1 遍历链表计算入度
      • 3.2 挑选一个入度为0的顶点
      • 3.3 输出顶点
      • 3.4 判断循环结束是否为全-1
      • 3.4 *kahn*方法
      • 3.5 测试

Java高阶数据结构 & 图补充-拓扑排序

1. 什么是拓扑排序

图片来源:简单、快速地带你了解图论以及拓扑排序!_哔哩哔哩_bilibili

  • 讲得很好哦!

这里我以羊了个羊小游戏这款砖块消除类小游戏为例:

在这里插入图片描述

有一个规则:

在这里插入图片描述

  • 当上层砖块覆盖下层砖块的时候,下层砖块不可以被选中移动(暗)
  • 上层砖块移走后,下层砖块才能被移动(亮)

则可以用如下图表示这种逻辑结构:

在这里插入图片描述

  • A->B,代表A覆盖B
  • 即一种无环不带权有向图
  1. 带回路的话,那么这个顶点就相当于自己覆盖了自己,不合理
  2. 无向的话,一条边则是双向的,同1不合理
  3. 箭头代表覆盖关系,权值不重要

在这里插入图片描述

那么我们给每个砖块一个layer值:

在这里插入图片描述

要求:

  • layer值大的砖块显示上,覆盖layer值小的砖块
  • 即A->B,layer(A) > layer(B)

在开发过程中需要这个layer,至于用处是什么,不做解释,这里这不是重点。

  • 至于这款游戏的原理,感兴趣的可以去网上找找资料研究一下

我们只需要找到一个序列,保证上方的覆盖者要在被覆盖者前方,再为其安排一个递减的序列

在这里插入图片描述

那么问题是:如何生成这个序列呢?

  • 这个排序,就叫做==“拓扑排序”==

类似的,如果你需要学习一系列的课程,那么一些知识一定需要另一些知识作为基础~

在这里插入图片描述

  • 而显然的,符合实际的是:这种序列不应该唯一
    • 学习路径肯定不一定单一呀~
  • 事实上也如此~
    • 一个图的拓扑排序很有可能有多解

2. 拓扑排序算法思想-卡恩算法

  • 本文章用邻接表的存储结果!

基础知识传送门:Java高阶数据结构 & 图 & 图的表示与遍历_s:103的博客-CSDN博客

例子:

在这里插入图片描述

前面提到,如果成环则没有拓扑序列,那么我们也可以通过能否拓扑排序,来判断一个图是否带环

  • 这也算是拓扑排序的一个额外得到功能吧

这里只讲解一种简单直接的算法,卡恩算法

  • 重点在于每个顶点的入度

步骤:

  1. 遍历一遍邻接表,计算所有顶点的入度
  2. 挑选一个入度为0的顶点,并输出
  3. 刚才挑中的顶以及其指向的顶点的入度都减1
    • -1的入度代表此顶点被删除
  4. 挑选一个入度为0的顶点,并输出
  5. 刚才挑中的顶以及其指向的顶点的入度都减1
  6. 重复这个操作,直到所有顶点都被删除(入度都为-1)
    • 如果最终是因为没有入度为0的顶点而不是全部顶点都被删除而停止的循环,则说明存在环

疑问:

1. 你很快会意识到,如果出现多个入度为0的顶点,应该怎么办?

答:先挑选谁都无所谓,因为这两个入度为0的顶点,是一种并列的关系,不会相互影响。即使他们有可能分支下去会有公共顶点,这也不会导致“乱了规则”的现象,因为“汇聚的第一个公共顶点”入度至少为2,只有其入度为0的时候才能被选中

  • 也就是说,只有如果先选中的入度为0的顶点输出后,诞生新的入度为0的顶点,一定也与原来入度为0的顶点也是并列
  • 这也是序列不唯一的原因~

2. 为什么入度为0的顶点先被选中?

答:这很显然,入度为0,代表没人指向它

  • 也就是说,它没被覆盖,而只覆盖别人!
  • 万物之源

算法复杂度分析:

  • 每个顶点和每条边都刚好被访问一次

V因为顶点数,E为边数

  • 则时间复杂度为O(V + E)

动图演示:

在这里插入图片描述

3. 拓扑排序代码实现

  • 我这边直接延用之前实现邻接表的代码(自制API)
  • 获取:Java高阶数据结构 & 图 & 图的表示与遍历_s:103的博客-CSDN博客

以下代码就不做过多解释了,完全依照刚才的算法思想~

3.1 遍历链表计算入度

//获取所有顶点的入度
public int[] getDevs() {
    int n = arrayV.length;
    int[] arr = new int[n];
    for (int i = 0; i < n; i++) {
        Node cur = edgeList.get(i);
        while(cur != null) {
            arr[cur.dest]++;
            cur = cur.next;
        }
    }
    return arr;
}

3.2 挑选一个入度为0的顶点

  • 你也可以结合isvVsted数组(标记数组)和堆去存储,节约时间
  • 这里用最简单的遍历法
public int getFirstZero(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        if(arr[i] == 0) {
            return i;
        }
    }
    return -1;
}

3.3 输出顶点

  • 这里我将顶点输出到队列里了
public void outputV(int index, int[] arr, Queue<Character> queue) {
    queue.offer(arrayV[index]);
    arr[index]--;
    Node cur = edgeList.get(index);
    while(cur != null) {
        arr[cur.dest]--;
        cur = cur.next;
    }
}

3.4 判断循环结束是否为全-1

public boolean isContainCir(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        if(arr[i] != -1) {
            return true;
        }
    }
    return false;
}

3.4 kahn方法

public static void main(String[] args) {


    //定义与构建图
    char[] chars = "012345678".toCharArray();
    GraphByList graph = new GraphByList(chars.length, true);
    graph.initArrayV(chars);
    graph.addEdge('0', '1', 1);
    graph.addEdge('0', '2', 1);
    graph.addEdge('1', '3', 1);
    graph.addEdge('2', '3', 1);
    graph.addEdge('2', '4', 1);
    graph.addEdge('4', '3', 1);
    graph.addEdge('6', '0', 1);
    graph.addEdge('7', '0', 1);
    graph.addEdge('7', '6', 1);
    graph.addEdge('8', '5', 1);

    //定义队列
    Queue<Character> queue = new LinkedList<>();
    boolean flag = graph.kahn(queue);

    System.out.println(flag ? "带环" : "不带环");
    System.out.println(queue);
}

3.5 测试

在这里插入图片描述


文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆

我对图的内容就完结撒花咯✿✿ヽ(°▽°)ノ✿

图论不止于此,如果感兴趣,可以有更深入的研究!


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

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

相关文章

python内置函数,推导式

abs&#xff1a;取绝对值 data abs&#xff08;-10&#xff09; pow&#xff1a;次方 data pow&#xff08;2&#xff0c;5&#xff09; sum&#xff1a;求和 num_list p[1,2,10,20] res sum(num_list) divmod取商和余数&#xff1a; v1&#xff0c;v2 divmod&…

第七届福州大学信息安全竞赛——shellcode1 绕过strlen检查,绕过沙箱检查,执行orw shellcode拿到flag

题目自取&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1HrMqh-lX-mkfueVeLzoEJg 提取码&#xff1a;oyel 介绍下这可恶的沙箱机制 这是一道非常让人蛋疼的题目&#xff0c;之前我只听说过沙箱&#xff0c;但是并没有自己实际接触过沙箱这个保护机制&#xff0c;大…

基于PKI的物联网安全服务体系建设

文章目录 1. PKI 概况1.1 PKI 简介1.2 CA 介绍1.2.1 CA证书包含主要内容1.2.1 CA 的工作原理1.2.2 主流的CA机构 1.4 PKI 应用场景 2. PKI 在物联网领域中的应用2.1 物联网PKI架构包含组件2.2 物联网PKI证书链 3. 创建自签CA证书3.1 自签名根证书创建3.2 创建云平台证书3.3 创建…

甘肃非煤矿山电子封条 智慧矿山 opencv

甘肃非煤矿山电子封条 智慧煤矿接入国家矿山安全平台是通过pythonopencv网络模型&#xff0c;甘肃非煤矿山电子封条pythonopencv网络模型对关键位置&#xff08;回风井口、运人井口、车辆出入口&#xff09;对现场人员行为、数量、穿戴着装及设备状态各数据进行实时监控分析。p…

【连续介质力学】特征值和特征向量问题

特征值和特征向量问题 二阶张量和一个向量&#xff08;单位向量 n ^ ′ \hat n n^′&#xff09;的点积会得到一个向量&#xff0c;也就是说&#xff0c;将一个二阶张量投影到某个方向所得到的向量的方向实际上与 n ^ ′ \hat n n^′ 的方向不一样&#xff1a; 特征值和特征向…

IDEA添加.gitignore忽略不需要提交的文件

问题 git上传的时候&#xff0c;我们已经将 xxx 文件添加到了.gitignore 中&#xff0c;但是在push 后&#xff0c;远程仓库还是会显示此文件&#xff0c;比如我们在.gitignore文件当中添加了不需要提交的target目录&#xff0c;但是提交的时候&#xff0c;还是会被提交。 原因…

2023.5.14总结

这周平时在刷蓝桥杯的题目&#xff0c;周天打了一场2021年陕西省的省赛的重现赛。 重现赛我们没打满&#xff0c;打了三个小时&#xff0c;A了四个&#xff0c;不过应该也差不多了。 登录—专业IT笔试面试备考平台_牛客网 以前没学过数论分块&#xff0c;今天学了学。对于一些向…

Hadoop上传及下载数据流程

网络拓扑及机架感知 网络拓扑 节点距离&#xff1a;两个节点到达共同父节点的距离和 机架感知 &#xff08; 副本节点的选择 &#xff09; 例如&#xff1a;500个节点&#xff0c;上传数据my.tar.gz,副本数为3&#xff0c; 根据机架感知&#xff0c;副本数据…

防止攻击者对您使用合法工具

恶意行为者越来越多地利用合法工具来实现其目标&#xff0c;其中包括禁用安全措施、横向移动和传输文件。使用常用工具可以让攻击者逃避检测。 虽然端点产品可以将定制工具或恶意软件标记为恶意软件&#xff0c;但商业上可用的工具通常被组织标记为干净或列入允许列表。 这让…

MacBook Pro合上盖子不休眠的问题简单分析

15年款的MacBook Pro每次不用的时候都是直接合上盖子&#xff08;开着一堆程序&#xff09;系统会自动休眠&#xff0c;但是升级了新系统Sierra之后就发现合上盖子竟然没有休眠&#xff08;第二次打开盖子后发现掉了50%多的电&#xff0c;而且温度比较高&#xff09;&#xff0…

软考A计划-真题-分类精讲汇总-第十一章(多媒体基础)

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

MySQL只有information_schema一个数据库

背景&#xff1a;centos新安装的mysql数据库。使用DbEaver连接mysql库时&#xff0c;发现左边不显示表。使用命令框mysql -uroot回车登录时&#xff0c;发现只能看到information_schema一个数据库了。 原因&#xff1a;   因为mysql数据库的user表里&#xff0c;存在用户名为…

Julia入门-1、使用C++调用Julia脚本语言

文章目录 0、开发环境1、测试Julia环境2、调用Julia脚本语言准备3、使用C++调用Julia脚本语言(1)使用C++调用简单的Julia脚本语言(2)使用C++调用复杂的Julia脚本语言0、开发环境 操作系统: ①Windows 10 开发编译器: ①VS 2015 Professional ②VS Code + julia-vscode插件(…

《计算机网络—自顶向下方法》 第六章Wireshark实验:IP 协议分析

IP 协议&#xff08;Internet Protocol&#xff09;&#xff0c;又译为网际协议或互联网协议&#xff0c;是用在 TCP/IP 协议簇中的网络层协议。主要功能是无连接数据报传送、数据报路由选择和差错控制。IP 协议是 TCP/IP 协议族的核心协议&#xff0c;其主要包含两个方面&…

Spring Boot 配置文件总结

前言 Spring Boot 中提供一个全局的配置文件&#xff1a;application.properties&#xff0c;这个配置文件的作用就是&#xff0c;允许我们通过这个配置文件去修改 Spring Boot 自动配置的默认值。 Spring Boot 支持两种格式的配置文件&#xff1a;application.properties 和…

C/C++每日一练(20230515) 区间和的个数、BST最近公共祖先、最接近元素

目录 1. 区间和的个数 &#x1f31f;&#x1f31f;&#x1f31f; 2. 二叉搜索树的最近公共祖先 &#x1f31f; 3. 找最接近元素 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏…

前端路由、vue-router常见用法、路由重定向、动态路由匹配、声明式导航 编程式导航 、导航守卫

前端路由、vue-router常见用法、路由重定向、动态路由匹配、声明式导航 & 编程式导航 、导航守卫 前端路由的概念与原理前端路由 vue-router 的基本使用vue-router 的常见用法路由重定向动态路由匹配声明式导航 & 编程式导航导航守卫 后台管理案例 前端路由的概念与原理…

mysqld之mha高可用

1.MHA的相关知识 1.1 什么是 MHA MHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。 MHA 的出现就是解决MySQL 单点故障的问题。 MySQL故障切换过程中&#xff0c;MHA能做到0-30秒内自动完成故障切换操作。 MHA能在…

C语言设计三子棋

引入 谈到三子棋&#xff0c;大家应该都不陌生&#xff0c;学生时代我们大多人都爱拿作文本有事没事就跟同桌下两把&#xff0c;只要任意一方三点连成一线&#xff0c;就可以胜利。今天我作为一个计算机方面的博主&#xff0c;将会用C语言实现这个简单的小游戏&#xff08;人机…

sort命令 uniq命令 tr命令 cut命令

sort命令 ——以行为单位对文件内容进行排序&#xff0c;也可以根据不同的数据类型来排序 比较原则是从首字符向后&#xff0c;依次按ASCII码值进行比较&#xff0c;最后将他们按升序输出 语法格式&#xff1a; sort [选项] 参数 cat file | sort 选项 -n按照数字进行排序…