【数据结构-图】图介绍

news2025/1/3 11:26:31

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
img

  • 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老
  • 导航
    • 檀越剑指大厂系列:全面总结 java 核心技术点,如集合,jvm,并发编程 redis,kafka,Spring,微服务,Netty 等
    • 常用开发工具系列:罗列常用的开发工具,如 IDEA,Mac,Alfred,electerm,Git,typora,apifox 等
    • 数据库系列:详细总结了常用数据库 mysql 技术点,以及工作中遇到的 mysql 问题等
    • 懒人运维系列:总结好用的命令,解放双手不香吗?能用一个命令完成绝不用两个操作
    • 数据结构与算法系列:总结数据结构和算法,不同类型针对性训练,提升编程思维,剑指大厂

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨

博客目录

    • 一.图的概念
      • 1.概念
      • 2.有向 vs 无向
      • 3.度
      • 4.权
      • 5.路径
      • 6.环
      • 7.图的连通性
    • 二.DFS 和 BFS
      • 1.Java 表示
      • 2.DFS
      • 3.BFS
    • 三.拓扑排序
      • 1.什么是拓扑排序?
      • 2.BFS
      • 3.DFS
      • 4.Kahn
    • 四.习题
      • 1.图-相关题目

一.图的概念

1.概念

图是由顶点(vertex)和边(edge)组成的数据结构,例如

A
B
C
D

该图有四个顶点:A、B、C、D 以及四条有向边,有向图中,边是单向的

2.有向 vs 无向

如果是无向图,那么边是双向的,下面是一个无向图的例子

A
B
C
D

3.度

是指与该顶点相邻的边的数量

A
B
C
D
E
F

例如上图中

  • A、B、C、E、F 这几个顶点度数为 2
  • D 顶点度数为 4

有向图中,细分为入度出度,参见下图

A
B
C
D
E
F
  • A (2 out / 0 in)
  • B、C、E (1 out / 1 in)
  • D (2 out / 2 in)
  • F (0 out / 2 in)

4.权

边可以有权重,代表从源顶点到目标顶点的距离、费用、时间或其他度量。

北京
武汉
广州
上海
800km
1900km
1200km
1050km
700km

5.路径

路径被定义为从一个顶点到另一个顶点的一系列连续边,例如上图中【北京】到【上海】有多条路径

  • 北京 - 上海
  • 北京 - 武汉 - 上海

路径长度

  • 不考虑权重,长度就是边的数量
  • 考虑权重,一般就是权重累加

6.环

在有向图中,从一个顶点开始,可以通过若干条有向边返回到该顶点,那么就形成了一个环

A
B
C
D
E

7.图的连通性

如果两个顶点之间存在路径,则这两个顶点是连通的,所有顶点都连通,则该图被称之为连通图,若子图连通,则称为连通分量

A
B
C
D
E
F
G
H
I
J

二.DFS 和 BFS

比如说,下面的图

A
B
C
D

邻接矩阵可以表示为:

  A B C D
A 0 1 1 0
B 1 0 0 1
C 1 0 0 1
D 0 1 1 0

邻接表可以表示为:

A -> B -> C
B -> A -> D
C -> A -> D
D -> B -> C

有向图的例子

A
B
C
D
  A B C D
A 0 1 1 0
B 0 0 0 1
C 0 0 0 1
D 0 0 0 0
A - B - C
B - D
C - D
D - empty

1.Java 表示

顶点

public class Vertex {
    String name;
    List<Edge> edges;

    // 拓扑排序相关
    int inDegree;
    int status; // 状态 0-未访问 1-访问中 2-访问过,用在拓扑排序

    // dfs, bfs 相关
    boolean visited;

    // 求解最短距离相关
    private static final int INF = Integer.MAX_VALUE;
    int dist = INF;
    Vertex prev = null;
}

public class Edge {

    Vertex linked;
    int weight;

    public Edge(Vertex linked) {
        this(linked, 1);
    }

    public Edge(Vertex linked, int weight) {
        this.linked = linked;
        this.weight = weight;
    }
}

2.DFS

public class Dfs {
    public static void main(String[] args) {
        Vertex v1 = new Vertex("v1");
        Vertex v2 = new Vertex("v2");
        Vertex v3 = new Vertex("v3");
        Vertex v4 = new Vertex("v4");
        Vertex v5 = new Vertex("v5");
        Vertex v6 = new Vertex("v6");

        v1.edges = List.of(new Edge(v3), new Edge(v2), new Edge(v6));
        v2.edges = List.of(new Edge(v4));
        v3.edges = List.of(new Edge(v4), new Edge(v6));
        v4.edges = List.of(new Edge(v5));
        v5.edges = List.of();
        v6.edges = List.of(new Edge(v5));

        dfs1(v1);
    }

    private static void dfs2(Vertex v) {
        LinkedList<Vertex> stack = new LinkedList<>();
        stack.push(v);
        while (!stack.isEmpty()) {
            Vertex pop = stack.pop();
            pop.visited = true;
            System.out.println(pop.name);
            for (Edge edge : pop.edges) {
                if (!edge.linked.visited) {
                    stack.push(edge.linked);
                }
            }
        }
    }

    private static void dfs1(Vertex v) {
        v.visited = true;
        System.out.println(v.name);
        for (Edge edge : v.edges) {
            if (!edge.linked.visited) {
                dfs(edge.linked);
            }
        }
    }
}

3.BFS

public class Bfs {
    public static void main(String[] args) {
        Vertex v1 = new Vertex("v1");
        Vertex v2 = new Vertex("v2");
        Vertex v3 = new Vertex("v3");
        Vertex v4 = new Vertex("v4");
        Vertex v5 = new Vertex("v5");
        Vertex v6 = new Vertex("v6");

        v1.edges = List.of(new Edge(v3), new Edge(v2), new Edge(v6));
        v2.edges = List.of(new Edge(v4));
        v3.edges = List.of(new Edge(v4), new Edge(v6));
        v4.edges = List.of(new Edge(v5));
        v5.edges = List.of();
        v6.edges = List.of(new Edge(v5));

        bfs(v1);
    }

    private static void bfs(Vertex v) {
        LinkedList<Vertex> queue = new LinkedList<>();
        v.visited = true;
        queue.offer(v);
        while (!queue.isEmpty()) {
            Vertex poll = queue.poll();
            System.out.println(poll.name);
            for (Edge edge : poll.edges) {
                if (!edge.linked.visited) {
                    edge.linked.visited = true;
                    queue.offer(edge.linked);
                }
            }
        }
    }
}

三.拓扑排序

1.什么是拓扑排序?

拓扑排序(Topological Sorting)是一种用于有向图(Directed Acyclic Graph,DAG)的节点排序算法。在拓扑排序中,图中的节点被安排成线性顺序,满足以下条件:

  1. 对于任意的有向边 (u, v),节点 u 在节点 v 之前。
  2. 图中不能包含环路(即,图必须是有向无环图,DAG)。

拓扑排序主要应用于描述一些任务或事件之间的依赖关系,其中每个节点代表一个任务或事件,有向边表示依赖关系。通过拓扑排序,你可以确定任务或事件的执行顺序,以确保没有依赖关系被破坏。

拓扑排序算法通常使用深度优先搜索(DFS)或广度优先搜索(BFS)来实现。算法的基本思想是从入度为 0 的节点开始,逐步移除这些节点及其出边,然后继续处理新的入度为 0 的节点,直到所有节点都被处理。

拓扑排序在许多领域有广泛的应用,包括编译器优化、任务调度、依赖分析、项目管理等。它是一种非常有用的算法,用于解决有向图中的依赖关系问题。

网页基础
Java Web
Java 基础
数据库
Spring框架
微服务框架
实战项目

2.BFS

public class TopologicalSort {
    public static void main(String[] args) {
        Vertex v1 = new Vertex("网页基础");
        Vertex v2 = new Vertex("Java基础");
        Vertex v3 = new Vertex("JavaWeb");
        Vertex v4 = new Vertex("Spring框架");
        Vertex v5 = new Vertex("微服务框架");
        Vertex v6 = new Vertex("数据库");
        Vertex v7 = new Vertex("实战项目");

        v1.edges = List.of(new Edge(v3)); // +1
        v2.edges = List.of(new Edge(v3)); // +1
        v3.edges = List.of(new Edge(v4));
        v6.edges = List.of(new Edge(v4));
        v4.edges = List.of(new Edge(v5));
        v5.edges = List.of(new Edge(v7));
        v7.edges = List.of();

        List<Vertex> graph = List.of(v1, v2, v3, v4, v5, v6, v7);
        // 1. 统计每个顶点的入度
        for (Vertex v : graph) {
            for (Edge edge : v.edges) {
                edge.linked.inDegree++;
            }
        }
        /*for (Vertex vertex : graph) {
            System.out.println(vertex.name + " " + vertex.inDegree);
        }*/
        // 2. 将入度为0的顶点加入队列
        LinkedList<Vertex> queue = new LinkedList<>();
        for (Vertex v : graph) {
            if (v.inDegree == 0) {
                queue.offer(v);
            }
        }
        // 3. 队列中不断移除顶点,每移除一个顶点,把它相邻顶点入度减1,若减到0则入队
        List<String> result = new ArrayList<>();
        while (!queue.isEmpty()) {
            Vertex poll = queue.poll();
//            System.out.println(poll.name);
            result.add(poll.name);
            for (Edge edge : poll.edges) {
                edge.linked.inDegree--;
                if (edge.linked.inDegree == 0) {
                    queue.offer(edge.linked);
                }
            }
        }
        if (result.size() != graph.size()) {
            System.out.println("出现环");
        } else {
            for (String key : result) {
                System.out.println(key);
            }
        }
    }
}

3.DFS

public class TopologicalSortDFS {

    public static void main(String[] args) {
        Vertex v1 = new Vertex("网页基础");
        Vertex v2 = new Vertex("Java基础");
        Vertex v3 = new Vertex("JavaWeb");
        Vertex v4 = new Vertex("Spring框架");
        Vertex v5 = new Vertex("微服务框架");
        Vertex v6 = new Vertex("数据库");
        Vertex v7 = new Vertex("实战项目");

        v1.edges = List.of(new Edge(v3));
        v2.edges = List.of(new Edge(v3));
        v3.edges = List.of(new Edge(v4));
        v6.edges = List.of(new Edge(v4));
        v4.edges = List.of(new Edge(v5));
        v5.edges = List.of(new Edge(v7));
        v7.edges = List.of();

        List<Vertex> graph = List.of(v1, v2, v3, v4, v5, v6, v7);
        LinkedList<String> result = new LinkedList<>();
        for (Vertex v : graph) {
            if(v.status==0) {
                dfs(v, result);
            }
        }
        System.out.println(result);
    }

    private static void dfs(Vertex v, LinkedList<String> result) {
        if (v.status == 2) {
            return;
        }
        if (v.status == 1) {
            throw new RuntimeException("发现环");
        }
        v.status = 1;
        for (Edge edge : v.edges) {
            dfs(edge.linked, result);
        }
        v.status = 2;
        result.push(v.name);
    }
}

4.Kahn

是的,Kahn 算法是一种使用广度优先搜索(BFS)的拓扑排序算法。该算法是由 Arthur Kahn 于 1962 年提出的,用于对有向无环图(DAG)进行拓扑排序。

Kahn 算法的基本思想是不断找到入度为 0 的节点,然后从图中移除这些节点及其出边,直到所有节点都被处理。这个过程与广度优先搜索类似,因此它使用了 BFS 的思想。

Kahn 算法的主要步骤包括:

  1. 初始化一个队列,将所有入度为 0 的节点加入队列。
  2. 从队列中取出一个节点,将其加入拓扑排序的结果中,并移除与该节点关联的出边,相应地更新相关节点的入度。
  3. 重复步骤 2,直到队列为空。

Kahn 算法的时间复杂度为 O(V + E),其中 V 是图中的节点数,E 是图中的边数。它是一种有效的拓扑排序算法,用于处理有向无环图中的依赖关系。

四.习题

1.图-相关题目

题目编号题目标题算法思想
547省份数量DFS、BFS、并查集
797所有可能路径DFS、BFS
1584连接所有点的最小费用最小生成树
743网络延迟时间单源最短路径
787K 站中转内最便宜的航班单源最短路径
207课程表拓扑排序
210课程表 II拓扑排序

觉得有用的话点个赞 👍🏻 呗。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

img

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

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

相关文章

【笔试强训选择题】Day48.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&#xff…

WebGL绘制圆形的点

目录 前言 如何实现圆形的点&#xff1f; 片元着色器内置变量&#xff08;gl_FragCoord、gl_PointCoord&#xff09; gl_PointCoord的含义 示例程序&#xff08;RoundedPoint.js&#xff09; 代码详解 前言 本文将讨论示例程序RoundedPoint&#xff0c;该程序绘制了圆…

一款强大的ntfs磁盘读写工具Paragon NTFS 15破解版百度网盘下载

今天再给大家分享一款NTFS工具Paragon NTFS 15&#xff0c;Paragon NTFS 15破解版是目前的最新版&#xff0c;需要的赶快收藏&#xff0c;地址失效可以留言。 Paragon Ntfs For Mac 15下载&#xff1a;https://souurl.cn/s84CCB Crcak链接: https://pan.baidu.com/s/1c2Hx7QBE…

MySQL数据库基础知识要点总结

目录 前言 一.数据库构成 1.1 表 1.2 关系 1.3 索引 1.4 查询语言 1.5 数据库管理系统 二.数据类型 2.1 整数 2.2 浮点 2.3 日期与时间 2.4 字符串 三.约束条件 3.1 主键约束 3.2 唯一约束 3.3 外键约束 3.4 非空约束 3.5 默认值约束 总结 前言 数据库是…

Linux环境下安装jdk1.8并配置环境变量

JDK版本&#xff1a;1.8 Linux准备工作 1.在usr目录下创建一个java文件夹准备放置我们下载好的jdk安装包 // An highlighted block var foo bar;2 , 将下载好的安装包放到我们刚刚创建好的 /usr/java 目录下, 执行 命令解压安装包。 tar -zxvf jdk-8u221-linux-x64.tar.g…

open62541开发:添加sqlite3 历史数据库

历史数据库在OPCUA 应用中十分重要&#xff0c;例如OPCUA 网关和OPCUA 汇聚服务器中都需要历史数据库功能。但是open62541 协议栈中仅包含了基于内存的历史数据库&#xff0c;在实际应用中是不够的。本博文讨论open62541 中添加sqlite3 为基础的历史数据库若干问题。 借鉴 Gi…

【Python小练习】简单浮点矩阵乘法

前言 最近上《计算机控制系统》课&#xff0c;涉及许多矩阵运算&#xff08;乘法居多&#xff09;&#xff0c;觉得手算不过来&#xff0c;按计算器太慢&#xff0c;于是写一个Python小程序做做。 二、代码 import numpy as np from numpy import shapem int(input("…

3D点云数据集制作实录【LiDAR】

在过去的两年里&#xff0c;我一直在和机器人打交道。 今年早些时候&#xff0c;我不再只关注相机&#xff0c;而是决定开始使用激光雷达。 因此&#xff0c;经过大量研究后&#xff0c;我选择了 32 束 RoboSense 设备。 推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 …

ElasticSearch深度分页解决方案

文章目录 概要ElasticSearch介绍es分页方法es分页性能对比表方案对比 From/Size参数深度分页问题Scroll#性能对比向前翻页 总结个人思考 概要 好久没更新文章了&#xff0c;最近研究了一下es的深分页解决方案。和大家分享一下&#xff0c;祝大家国庆节快乐。 ElasticSearch介…

记一次 .NET 某拍摄监控软件 卡死分析

一&#xff1a;背景 1. 讲故事 今天本来想写一篇 非托管泄露 的生产事故分析&#xff0c;但想着昨天就上了一篇非托管文章&#xff0c;连着写也没什么意思&#xff0c;换个口味吧&#xff0c;刚好前些天有位朋友也找到我&#xff0c;说他们的拍摄监控软件卡死了&#xff0c;让…

Android Shape设置背景

设置背景时&#xff0c;经常这样 android:background“drawable/xxx” 。如果是纯色图片&#xff0c;可以考虑用 shape 替代。 shape 相比图片&#xff0c;减少资源占用&#xff0c;缩减APK体积。 开始使用。 <?xml version"1.0" encoding"utf-8"?…

【STM32单片机】u8g2智能风扇设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器&#xff0c;使用按键、IIC OLED模块、DS18B20温度传感器、直流电机、红外遥控等。 主要功能&#xff1a; 初始化后进入温度显示界面&#xff0c;系统初始状态为手动…

探索视听新纪元: ChatGPT的最新语音和图像功能全解析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f916; 人工智能 AI: &#x1f9e0; Machine …

【我的创作纪念日】使用pix2pixgan实现barts2020数据集的处理(完整版本)

使用pix2pixgan &#xff08;pytorch)实现T1 -> T2的基本代码 使用 https://github.com/eriklindernoren/PyTorch-GAN/ 这里面的pix2pixgan代码进行实现。 进去之后我们需要重新处理数据集&#xff0c;并且源代码里面先训练的生成器&#xff0c;后训练鉴别器。 一般情况下…

亚马逊要求的UL报告的产品标准是什么?如何区分

亚马逊为什么要求电子产品有UL检测报告&#xff1f; 首先&#xff0c;美国是一个对安全要求非常严格的国家&#xff0c;美国本土的所有电子产品生产企业早在很多年前就要求有相关安规检测。 其次&#xff0c;随着亚马逊在全球商业的战略地位不断提高&#xff0c;境外的电子设…

百度资源搜索平台出现:You do not have the proper credential to access this page.怎么办?

Forbidden site not allowed You do not have the proper credential to access this page. If you think this is a server error, please contact the webmaster. 如果你的百度资源平台&#xff0c;点进去出现这个提示&#xff0c;说明您的网站已经被百度清退了。 如果你的网…

队列的分类及用途

队列&#xff08;Queue&#xff09;是一种常见的数据结构&#xff0c;用于存储和管理数据元素。队列通常遵循先进先出&#xff08;FIFO&#xff0c;First-In-First-Out&#xff09;的原则&#xff0c;这意味着最早添加到队列的元素将首先被移除。队列有不同的类型和用途&#x…

VS code本地安装PlantUML

VS code本地安装PlantUML 需要条件vs code安装插件使用常见错误 需要条件 在VS Code上安装PlantUML扩展之前&#xff0c;请确保您具有以下先决条件: : Java与GraphViz(点击可直接跳转下载界面); 安装省略 vs code安装插件 vs code安装以下两个插件&#xff08;PlantUML,Grap…

易云维®智慧工厂数字化管理平台助推工业制造企业数字化转型新动能

近年来&#xff0c;我国正在积极推进工业制造企业数字化转型&#xff0c;工业制造企业数字化转型迎来了密集的利好政策&#xff0c;近期&#xff0c;国家工信部又出台系列政策&#xff0c;实施工业制造企业数字化促进工程&#xff0c;推动工业制造企业更快更好地拥抱数字经济。…

数字安全设备制造有哪几种方式?

数字安全设备制造是指制造用于保护数字信息系统和网络安全的专用设备。以下是几种常见的数字安全设备制造方式&#xff1a; 集成式安全设备制造&#xff1a;集成式安全设备制造是将多种安全功能集成到单一的硬件设备或软件平台中。这种制造方式可以大大降低设备的成本和复杂性&…