数据结构入门-13-图

news2024/11/15 19:51:49

文章目录

  • 一、图的概述
    • 1.1 图论的作用
    • 1.2 图的分类
      • 1.2.1 无向图
      • 1.2.2 有向图
      • 1.2.3 无权图
      • 1.2.4 有劝图
    • 1.3 图的基本概念
  • 二、树的基本表示
    • 2.1 邻接矩阵
      • 2.1.1 邻接矩阵 表示图
      • 2.1.2 邻接矩阵的复杂度
    • 2.2 邻接表
      • 2.2.1 邻接表的复杂度
      • 2.2.2 邻接表By哈希表
  • 三、图的深度优先遍历
    • 3.1 图深度遍历过程
    • 3.2 图遍历改进
    • 3.3 先中后
    • 3.4 复杂度
  • 四、深度遍历的应用
    • 4.1 求联通分量
    • 4.2 单源路径问题
    • 4.3 检测无向图中的环
    • 4.4 二分图检测
  • 五、图的广度优先遍历
  • 六、图论问题的建模
  • 七、图论和AI
  • 十一、最小生成树
    • 11.1 带权图
  • 十二、最短路径
    • 12.1 迪杰斯特拉算法
      • 12.1.1 Dijkstra原理

一、图的概述

1.1 图论的作用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2 图的分类

在这里插入图片描述

1.2.1 无向图

在这里插入图片描述

1.2.2 有向图

在这里插入图片描述在这里插入图片描述

1.2.3 无权图

在这里插入图片描述

1.2.4 有劝图

在这里插入图片描述

1.3 图的基本概念

  1. 两点相邻
  2. 点的邻边
  3. 路径Path,从一个点到另一个点走过的路
  4. 环Loop,多个点围城一个圈
  5. 自环边,自己和自己形成环
  6. 平行边,重复的边

在这里插入图片描述

  1. 联通分量
    在这里插入图片描述

  2. 无环图
    在这里插入图片描述
    树是一种无环图,一个联通的无环图(一个联通分量)就是树

  3. 连通图的 生成树
    在这里插入图片描述
    V:顶点数

在这里插入图片描述
10) 顶点的度degree
顶点相邻的边数
在这里插入图片描述

二、树的基本表示

2.1 邻接矩阵

在这里插入图片描述
在这里插入图片描述

V:顶点数,E:边数

2.1.1 邻接矩阵 表示图

import java.io.*;
import java.util.Scanner;

public class AdjMatrix {

    private int V;
    private int E;
    private int[][] adj;

    public AdjMatrix(String filename){

        File file = new File(filename);

        try(Scanner scanner = new Scanner(file)){

            V = scanner.nextInt();
            adj = new int[V][V];

            E = scanner.nextInt();
            for(int i = 0; i < E; i ++){
                int a = scanner.nextInt();
                int b = scanner.nextInt();
                adj[a][b] = 1;
                adj[b][a] = 1;
            }
        }
        catch(IOException e){
            e.printStackTrace();
        }
    }

    @Override
    public String toString(){
        StringBuilder sb = new StringBuilder();

        sb.append(String.format("V = %d, E = %d\n", V, E));
        for(int i = 0; i < V; i ++){
            for(int j = 0; j < V; j ++)
                sb.append(String.format("%d ", adj[i][j]));
            sb.append('\n');
        }
        return sb.toString();
    }

    public static void main(String[] args){

        AdjMatrix adjMatrix = new AdjMatrix("src/main/java/hGraph/base/file/g.txt");
        System.out.print(adjMatrix);
    }
}

    public int V(){
        return V;
    }

    public int E(){
        return E;
    }

//判断是否有边,两顶点是否相邻
    public boolean hasEdge(int v, int w){
        validateVertex(v);
        validateVertex(w);
        return adj[v][w] == 1;
    }
//查找和顶点v相连的顶点
    public ArrayList<Integer> adj(int v){
        validateVertex(v);
        ArrayList<Integer> res = new ArrayList<>();
        for(int i = 0; i < V; i ++)
            if(adj[v][i] == 1)
                res.add(i);
        return res;
    }
//查找顶点的度
    public int degree(int v){
        return adj(v).size();
    }

2.1.2 邻接矩阵的复杂度

在这里插入图片描述

空间复杂度 可以优化,
求一个点的相邻结点 可以优化

稀疏图&稠密图
根据边的多少

完全图 每个顶点都连接

在这里插入图片描述

2.2 邻接表

在这里插入图片描述

2.2.1 邻接表的复杂度

在这里插入图片描述
在这里插入图片描述

2.2.2 邻接表By哈希表

在这里插入图片描述
用红黑树实现图

import java.io.File;
import java.io.IOException;
import java.util.TreeSet;
import java.util.Scanner;

public class AdjSet {

    private int V;
    private int E;
    private TreeSet<Integer>[] adj;

    public AdjSet(String pathStr){

        File file = new File(pathStr);

        try(Scanner scanner = new Scanner(file)){

            V = scanner.nextInt();
            if(V < 0) throw new IllegalArgumentException("V must be non-negative");
            adj = new TreeSet[V];
            for(int i = 0; i < V; i ++)
                adj[i] = new TreeSet<Integer>();

            E = scanner.nextInt();
            if(E < 0) throw new IllegalArgumentException("E must be non-negative");

            for(int i = 0; i < E; i ++){
                int a = scanner.nextInt();
                validateVertex(a);
                int b = scanner.nextInt();
                validateVertex(b);

                if(a == b) throw new IllegalArgumentException("Self Loop is Detected!");
                if(adj[a].contains(b)) throw new IllegalArgumentException("Parallel Edges are Detected!");

                adj[a].add(b);
                adj[b].add(a);
            }
        }
        catch(IOException e){
            e.printStackTrace();
        }
    }

    private void validateVertex(int v){
        if(v < 0 || v >= V)
            throw new IllegalArgumentException("vertex " + v + "is invalid");
    }

    public int V(){
        return V;
    }

    public int E(){
        return E;
    }

    public boolean hasEdge(int v, int w){
        validateVertex(v);
        validateVertex(w);
        return adj[v].contains(w);
    }

    public Iterable<Integer> adj(int v){
    // public TreeSet<Integer> adj(int v){
        validateVertex(v);
        return adj[v];
    }

    public int degree(int v){
        validateVertex(v);
        return adj[v].size();
    }

    @Override
    public String toString(){
        StringBuilder sb = new StringBuilder();

        sb.append(String.format("V = %d, E = %d\n", V, E));
        for(int v = 0; v < V; v ++){
            sb.append(String.format("%d : ", v));
            for(int w : adj[v])
                sb.append(String.format("%d ", w));
            sb.append('\n');
        }
        return sb.toString();
    }

    public static void main(String[] args){

        AdjSet adjSet = new AdjSet("g.txt");
        System.out.print(adjSet);
    }
}

三、图的深度优先遍历

3.1 图深度遍历过程

之前描述过树的遍历
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

    public GraphDFS(Graph G){

        this.G = G;
        visited = new boolean[G.V()];
        dfs(0);
    }

    private void dfs(int v){

        visited[v] = true;
        order.add(v);
        for(int w: G.adj(v))
            if(!visited[w])
                dfs(w);
    }

3.2 图遍历改进

在这里插入图片描述

不和0 相连 的顶点,就不会遍历
原因是只针对0 调用
改进:对每一个节点进行调用
在这里插入图片描述

    public GraphDFS(Graph G){

        this.G = G;
        visited = new boolean[G.V()];
        for(int v = 0; v < G.V(); v ++)
            if(!visited[v])
                dfs(v);
    }

    private void dfs(int v){

        visited[v] = true;
        pre.add(v);
        for(int w: G.adj(v))
            if(!visited[w])
                dfs(w);
        post.add(v);
    }

    public Iterable<Integer> pre(){
        return pre;
    }

    public Iterable<Integer> post(){
        return post;
    }

3.3 先中后

在树中有先中后遍历
在这里插入图片描述

图也可以分为 先 后序遍历

在这里插入图片描述

3.4 复杂度

遍历的复杂度:O(V+E)

四、深度遍历的应用

4.1 求联通分量

在这里插入图片描述

4.2 单源路径问题

在这里插入图片描述
依然做了深度优先遍历,记录这个顶点的pre:从哪里来的
单源路径:从一个顶点出发的路径,不能反向查找

import java.util.ArrayList;
import java.util.Collections;

public class SingleSourcePath {

    private Graph G;
    private int s;

    private boolean[] visited;
    private int[] pre;

    public SingleSourcePath(Graph G, int s){

        G.validateVertex(s);

        this.G = G;
        this.s = s;
        visited = new boolean[G.V()];
        pre = new int[G.V()];

        dfs(s, s);
    }

    private void dfs(int v, int parent){

        visited[v] = true;
        pre[v] = parent;
        for(int w: G.adj(v))
            if(!visited[w])
                dfs(w, v);
    }

    public boolean isConnectedTo(int t){
        G.validateVertex(t);
        return visited[t];
    }

    public Iterable<Integer> path(int t){

        ArrayList<Integer> res = new ArrayList<Integer>();
        if(!isConnectedTo(t)) return res;

        int cur = t;
        while(cur != s){
            res.add(cur);
            cur = pre[cur];
        }
        res.add(s);

        Collections.reverse(res);
        return res;
    }

    public static void main(String[] args){

        Graph g = new Graph("g.txt");
        SingleSourcePath sspath = new SingleSourcePath(g, 0);
        System.out.println("0 -> 6 : " + sspath.path(6));
        System.out.println("0 -> 5 : " + sspath.path(5));
    }
}

在这里插入图片描述

4.3 检测无向图中的环

在这里插入图片描述

4.4 二分图检测

二分图:
在这里插入图片描述

五、图的广度优先遍历

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

    public GraphBFS(Graph G){

        this.G = G;
        visited = new boolean[G.V()];
        for(int v = 0; v < G.V(); v ++)
            if(!visited[v])
                bfs(v);
    }

    private void bfs(int s){

        Queue<Integer> queue = new LinkedList<>();
        queue.add(s);
        visited[s] = true;
        while(!queue.isEmpty()){
            int v = queue.remove();
            order.add(v);

            for(int w: G.adj(v))
                if(!visited[w]){
                    queue.add(w);
                    visited[w] = true;
                }
        }
    }

    public Iterable<Integer> order(){
        return order;
    }

复杂度:O(V+E)

六、图论问题的建模

七、图论和AI

十一、最小生成树

11.1 带权图

在这里插入图片描述

/// 暂时只支持无向带权图
public class WeightedGraph implements Cloneable{

    private int V;
    private int E;
    private TreeMap<Integer, Integer>[] adj;

    public WeightedGraph(String filename){

        File file = new File(filename);

        try(Scanner scanner = new Scanner(file)){

            V = scanner.nextInt();
            if(V < 0) throw new IllegalArgumentException("V must be non-negative");
            adj = new TreeMap[V];
            for(int i = 0; i < V; i ++)
                adj[i] = new TreeMap<Integer, Integer>();

            E = scanner.nextInt();
            if(E < 0) throw new IllegalArgumentException("E must be non-negative");

            for(int i = 0; i < E; i ++){
                int a = scanner.nextInt();
                validateVertex(a);
                int b = scanner.nextInt();
                validateVertex(b);
                int weight = scanner.nextInt();

                if(a == b) throw new IllegalArgumentException("Self Loop is Detected!");
                if(adj[a].containsKey(b)) throw new IllegalArgumentException("Parallel Edges are Detected!");

                adj[a].put(b, weight);
                adj[b].put(a, weight);
            }
        }
        catch(IOException e){
            e.printStackTrace();
        }
    }

十二、最短路径

带权图的最短路径不一定 走的边最少
在这里插入图片描述

12.1 迪杰斯特拉算法

12.1.1 Dijkstra原理

  1. 指定dis:源到各个顶点的路径,先初始为MAX
    在这里插入图片描述

  2. 找顶点,更新dis
    在这里插入图片描述

  3. 找当前最短的路径,确定这个就是到顶点的最短路径:确定2位0到2的最短路径
    在这里插入图片描述

  4. 根据2顶点,来做更新
    在这里插入图片描述
    这里更新了2 到各个顶点的路径,1 从 4 更新到了3

  5. 再从当前的路径中找最小的,为3 顶点1,
    所以确定顶点1 的最短路径为3

在这里插入图片描述

  1. 再根据顶点1 ,更新dis
    在这里插入图片描述
  2. 确定当前最短的距离为5 ,顶点3
    在这里插入图片描述
  3. 更新dis,到顶点4都为6

在这里插入图片描述

每轮循环:

  1. 初始化源到其他顶点的dis,默认都为MAX
  2. 找到当前没有访问的最短路节点
  3. 确定这个节点的最短路径就是当前大小
  4. 根据这个节点的最短路径大小,更新到其他节点的路径长度,如果比dis中的要小,那么就更新dis

在这里插入图片描述

#from ChatGPT
1.初始化距离数组dist和标记数组visited。将起始地点设置为起点,其他地点的距离初始化为无穷大,visited数组初始化为false。
2.从起点开始遍历所有地点,选择当前距离最小且未被访问过的地点u。
3.对于地点u,更新与其相邻的地点v的距离,如果新的距离小于原来的距离,则更新距离数组dist和路径数组path。
4.标记地点u为已访问,重复上述过程,直到所有地点都被访问。
5.最终得到起点到每个地点的最短距离和路径。

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

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

相关文章

LLM文章阅读:Baichuan 2 干货

如有转载&#xff0c;请注明出处。欢迎关注微信公众号&#xff1a;低调奋进。打算开始写LLM系列文章&#xff0c;主要从数据、训练框架、对齐等方面进行LLM整理。 Baichuan 2: Open Large-scale Language Models 原始文章链接 https://cdn.baichuan-ai.com/paper/Baichuan2-…

Element Plus table formatter函数返回html内容

查看 Element Plus table formatter 支持返回 类型为string 和 VNode对象&#xff1b; 若依全局直接用h函数&#xff0c;无需引用 下面普通基本用法&#xff1a;在Element Plus中&#xff0c;你可以使用自定义的formatter函数来返回VNode对象&#xff0c;从而实现更灵活的自定…

FasterNet(PConv)paper笔记(CVPR2023)

论文&#xff1a;Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks 先熟悉两个概念&#xff1a;FLOPS和FLOPs&#xff08;s一个大写一个小写&#xff09; FLOPS: FLoating point Operations Per Second的缩写&#xff0c;即每秒浮点运算次数&#xff0c;或…

Pytorch实现鸟类品种分类识别(含训练代码和鸟类数据集)

Pytorch实现鸟类品种分类识别(含训练代码和鸟类数据集) 目录 Pytorch实现鸟类品种分类识别(含训练代码和鸟类数据集) 1. 前言 2. 鸟类数据集 &#xff08;1&#xff09;Bird-Dataset26 &#xff08;2&#xff09;自定义数据集 3. 鸟类分类识别模型训练 &#xff08;1&a…

核心实验13合集_vlan mapping 和QinQ_ENSP

项目场景一&#xff1a; 核心实验13合集-1_vlan高级配置_ENSP vlan mapping vlan转换 将用户端发来的vlan30-31的标签全部转换成vlan100向上发送 相关知识点&#xff1a; 定义: VLAN Mapping通过修改报文携带的VLAN Tag来实现不同VLAN的相互映 射。 目的: 在某些场景中&#xf…

c语言数组的用法

c语言数组的用法如下&#xff1a; 一维数组的定义方式 在C语言中使用数组必须先进行定义。一维数组的定义方式为&#xff1a; 类型说明符 数组名 [常量表达式]; 其中&#xff0c;类型说明符是任一种基本数据类型或构造数据类型。数组名是用户定义的数组标识符。方括号中的常量表…

原生js之dom表单改变和鼠标常用事件

那么好,本次我们聊聊表单改变时如何利用onchange方法来触发input改变事件以及鼠标常用的滑入滑出,点击down和点击up事件. 关于onchange方法 onchange方法在鼠标输入完后点击任何非输入框位置时触发.触发时即可改变原有输入框的值. out 、leave、over、down、up鼠标方法 当用…

YOLOV7改进-空洞卷积+共享权重的Scale-Aware RFE

代码 1、先把文件复制到common.py中 2、yolo.py添加类名 3、下半部分进行添加修改 4、cfg-training&#xff1a;新建配置文件 加了一行&#xff0c;后面对于序号1 5、这里选择12层替代

软件第三方测评机构简析:良好的测试环境对软件产品起到的作用

近年来&#xff0c;软件行业发展迅速&#xff0c;软件产品的质量成为用户关注的焦点。而软件的质量评估往往需要依赖专业的第三方测评机构&#xff0c;为了更好地了解软件测试环境对产品质量的重要性&#xff0c;小编整理了以下简析&#xff1a; 一、良好的测试环境对软件产品…

Redis是单线程Or多线程?单线程为什么反而快?

0. 从什么角度看是单线程or多线程 从总体角度来&#xff0c;redis是单线程的&#xff1a; Redis 单线程指的是&#xff1a; 「接收客户端请求->解析请求 ->进行数据读写等操作->发送数据给客户端」 这个过程是由一个线程&#xff08;主线程&#xff09;来完成的…

【Leetcode刷题】哈希

本篇文章为 LeetCode 哈希模块的刷题笔记&#xff0c;仅供参考。 哈希表是一种使用哈希函数组织数据&#xff0c;以支持快速插入和搜索的数据结构。哈希表通过哈希函数通过将任意类型的数据映射到固定大小的数据&#xff0c;以实现快速查找和存储数据。C 中的无序容器 unorder…

音视频编码格式-AAC ADT

1408(16进制) : 0001 0100 0000 1000 audioObjectType为 00010 , 即 2&#xff0c; profie (audioObjectType -1 ) AAC LC samplingFrequencyIndex为 1000 , 即 8 , 对应的采样频率为 16000 channelConfiguration为 0001 , 表示channel数量为1

10、哈希函数与哈希表

哈希函数 出现次数最多的 32G 小文件方法&#xff1a;利用哈希函数在种类上均分 设计RandomPool结构 设计一种结构&#xff0c;在该结构中有如下三个功能: insert(key):将某个key加入到该结构&#xff0c;做到不重复加入 delete(key):将原本在结构中的某个key移除 getRando…

电商3D资产优化管线的自动化

如果你曾经尝试将从 CAD 程序导出的 3D 模型上传到 WebGL 或 AR 服务&#xff0c;那么可能会遇到最大文件大小、永无休止的进度条和糟糕的帧速率等问题。 为了创作良好的在线交互体验&#xff0c;优化 3D 数据的大小和性能至关重要。 这也有利于你的盈利&#xff0c;因为较小的…

识别评估项目风险常用6大方法

提前识别和评估项目风险&#xff0c;有助于风险预防和规避&#xff0c;从而提前采取预防措施&#xff0c;有效避免和减少风险的发生&#xff0c;防止风险进一步扩大和恶化。如果没有提前识别风险&#xff0c;没有及时处理风险问题&#xff0c;往往造成项目交付延迟、成本超支等…

实时监测与优化:3D车辆状态可视化的崭新前景

当谈到车辆状态可视化时&#xff0c;我们进入了数字化时代的新境界。这不仅是一种技术革命&#xff0c;更是一种全新的智能化管理方式&#xff0c;为车辆运营提供了前所未有的便利和效率。以下是3D车辆状态可视化的一些关键方面&#xff0c;以及它如何改变了我们的交通和物流管…

RT-DETR个人整理向理解

一、前言 在开始介绍RT-DETR这个网络之前&#xff0c;我们首先需要先了解DETR这个系列的网络与我们常提及的anchor-base以及anchor-free存在着何种差异。 首先我们先简单讨论一下anchor-base以及anchor-free两者的差异与共性&#xff1a; 1、两者差异&#xff1a;顾名思义&…

《TCP/IP网络编程》阅读笔记--域名及网络地址

目录 1--域名系统 2--域名与 IP 地址的转换 2-1--利用域名来获取 IP 地址 2-2--利用 IP 地址获取域名 3--代码实例 3-1--gethostbyname() 3-2--gethostbyaddr() 1--域名系统 域名系统&#xff08;Domain Name System&#xff0c;DNS&#xff09;是对 IP 地址和域名进行相…

三分钟,教你做出领导满意的可视化报表

数字化已然成为社会发展的共识&#xff0c;企业想要在未来的竞争中占据优势&#xff0c;获取不断发展的数字经济&#xff0c;就必须将数据看作企业的战略资源&#xff0c;利用数据可视化将数据转化为信息&#xff0c;促进企业发展。 数据可视化是什么 在早期数据分析领域&…

业务安全情报第22期 | 不法分子为何盗刷企业短信?

目录 手机短信的重要性 手机短信接口被攻击的危害 社交App短信遭遇疯狂盗刷 社交App该如何防控威胁 规则上的防护措施 技术上的防护措施 近期监测发现&#xff0c;某知名社交平台遭遇黑灰产大规模注册账号&#xff0c;账号短信接口被疯狂盗用。不仅影响正常用户操作&…