数据结构第13节 无向图

无向图是图论中的一个基本概念,它是数学和计算机科学中用来描述一组对象(顶点)以及它们之间的成对关系(边)的结构。在无向图中,边是没有方向的,这意味着边所连接的两个顶点可以互相访问。

定义

无向图 ( G ) 可以定义为一个有序对 ( G=(V,E) ),其中:

  • ( V ) 是顶点的集合,也称作节点的集合。
  • ( E ) 是边的集合,边是 ( V ) 中顶点的无序对,表示两个顶点之间的连接。

术语

  • 顶点:图中的基本单位,通常用字母 ( v ) 或 ( u ) 表示。
  • :连接顶点的线段,表示两个顶点之间的关系,通常用 ( e ) 表示。
  • 度数:一个顶点的度数是与该顶点相邻的所有边的数量。
  • 路径:一系列顶点和边,使得每个边都连接路径中的连续两个顶点。
  • 简单路径:路径中不重复经过任何顶点。
  • :闭合路径,起点和终点相同。
  • 连通性:如果图中任意两个顶点之间都存在路径,则称该图为连通图。
  • 连通分量:无向图中的最大连通子图,彼此之间没有边相连。

图的表示

无向图可以用以下几种方式表示:

  • 邻接矩阵:一个 ( |V| \times |V| ) 的矩阵,其中第 ( i ) 行第 ( j ) 列的元素为 1 如果顶点 ( i ) 和顶点 ( j ) 之间有一条边,否则为 0。
  • 邻接列表:对于每个顶点,维护一个链表,包含与之直接相连的所有顶点。

应用

无向图在许多领域有应用,如:

  • 社交网络:顶点可以代表人,边可以代表朋友关系。
  • 互联网:网页作为顶点,超链接作为边。
  • 电路设计:顶点可以是电路元件,边可以是连接导线。
  • 地图和道路网络:顶点可以是城市或交叉口,边可以是道路。
  • 化学分子结构:顶点可以是原子,边可以是化学键。

算法

处理无向图的一些常见算法包括:

  • 深度优先搜索 (DFS):从某个顶点开始,尽可能深入地探索每条路径。
  • 广度优先搜索 (BFS):从某个顶点开始,探索所有离起点等距离的顶点。
  • 最小生成树算法:如Prim算法或Kruskal算法,用于在加权图中找到一棵包含所有顶点的最小权重的树。
  • 连通性检测:确定图是否连通,或找出所有连通分量。

无向图是理解和解决许多复杂问题的基础工具。在实际应用中,无向图可以转化为有向图或加权图以适应更复杂的关系和需求。

在Java中,我们可以使用邻接矩阵或邻接列表来表示无向图。下面是一个使用邻接列表的例子:

import java.util.*;

public class Graph {
    private final int V;   // Number of vertices
    private LinkedList<Integer> adj[]; //Adjacency List

    // Constructor
    Graph(int v) {
        V = v;
        adj = new LinkedList[v];
        for (int i=0; i<v; ++i)
            adj[i] = new LinkedList();
    }

    //Function to add an edge into the graph
    void addEdge(int v,int w) {
        adj[v].add(w); // Add w to v’s list.
        adj[w].add(v); // Since graph is undirected, add v to w's list too
    }

    // Function to print the graph
    void printGraph() {
        for (int v = 0; v < V; ++v) {
            System.out.println("Adjacency list of vertex "+ v);
            System.out.print("head ");
            Iterator<Integer> it = adj[v].listIterator();
            while (it.hasNext())
                System.out.print(" -> " + it.next());
            System.out.println("\n");
        }
    }

    public static void main(String args[]) {
        Graph g = new Graph(5);

        g.addEdge(0, 1);
        g.addEdge(0, 4);
        g.addEdge(1, 2);
        g.addEdge(1, 3);
        g.addEdge(1, 4);
        g.addEdge(2, 3);
        g.addEdge(3, 4);

        g.printGraph();
    }
}

在这个例子中,我们首先定义了一个Graph类,它有两个私有变量:V(顶点的数量)和adj(邻接列表)。然后我们在构造函数中初始化这些变量。

我们定义了一个addEdge方法来添加边。由于这是一个无向图,所以我们需要在两个顶点的邻接列表中都添加对方。

最后,我们定义了一个printGraph方法来打印图的邻接列表表示。

在main方法中,我们创建了一个Graph对象,并添加了一些边,然后打印出了这个图。

当然,让我们再看一个使用邻接矩阵表示无向图的例子。邻接矩阵是一种二维数组,用于表示图中顶点之间的连接关系。如果图中的两个顶点u和v之间存在一条边,那么邻接矩阵中的元素A[u][v]和A[v][u]的值为1,否则为0。

下面是一个使用邻接矩阵表示无向图的Java代码示例:

public class Graph {
    private final int V;   // No. of vertices
    private int E;         // No. of edges
    private int[][] adj;   // Adjacency Matrix

    // Constructor
    Graph(int v) {
        V = v;
        E = 0;
        adj = new int[V][V];
    }

    // Method to add an edge in a graph
    public void addEdge(int v, int w) {
        if (v >= 0 && v < V && w >= 0 && w < V) {
            adj[v][w] = 1;
            adj[w][v] = 1;
            E++;
        } else {
            throw new IllegalArgumentException("Invalid vertices");
        }
    }

    // Method to print adjacency matrix
    public void printGraph() {
        for (int v = 0; v < V; v++) {
            for (int w = 0; w < V; w++) {
                System.out.print(adj[v][w] + " ");
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        Graph g = new Graph(5);
        g.addEdge(0, 1);
        g.addEdge(0, 4);
        g.addEdge(1, 2);
        g.addEdge(1, 3);
        g.addEdge(1, 4);
        g.addEdge(2, 3);
        g.addEdge(3, 4);
        g.printGraph();
    }
}

在这个例子中,我们首先定义了一个Graph类,它有三个私有变量:V(顶点的数量),E(边的数量)和adj(邻接矩阵)。然后我们在构造函数中初始化这些变量。

我们定义了一个addEdge方法来添加边。由于这是一个无向图,所以我们需要在邻接矩阵的两个位置上都设置1。

最后,我们定义了一个printGraph方法来打印图的邻接矩阵表示。

在main方法中,我们创建了一个Graph对象,并添加了一些边,然后打印出了这个图的邻接矩阵表示。

让我们通过一个迷宫游戏的例子来理解无向图的应用。在这个游戏中,迷宫可以被看作是一个无向图,其中每个房间都是一个顶点,每个门(连接两个房间的通道)都是一条边。

假设我们有一个迷宫,它由多个房间组成,每个房间都有可能与其他房间相连。我们的目标是找到从起点到终点的路径。这个问题可以通过深度优先搜索(DFS)或广度优先搜索(BFS)在无向图中寻找路径来解决。

以下是一个使用DFS在迷宫(无向图)中寻找路径的Java代码示例:

import java.util.*;

class Maze {
    private final int V;   // Number of rooms
    private LinkedList<Integer> adj[]; //Adjacency List

    // Constructor
    Maze(int v) {
        V = v;
        adj = new LinkedList[v];
        for (int i=0; i<v; ++i)
            adj[i] = new LinkedList();
    }

    //Function to add a door between two rooms
    void addDoor(int v, int w) {
        adj[v].add(w); // Add w to v’s list.
        adj[w].add(v); // Since maze is undirected, add v to w's list too
    }

    // A recursive function to find path from source 's' to destination 'd'
    boolean DFSUtil(int s, int d, boolean visited[]) {
        visited[s] = true;
        System.out.print(s + " ");

        if (s == d)
            return true;

        Iterator<Integer> i = adj[s].listIterator();
        while (i.hasNext()) {
            int n = i.next();
            if (!visited[n]) {
                if (DFSUtil(n, d, visited))
                    return true;
            }
        }
        return false;
    }

    // Prints shortest path from source 's' to destination 'd'
    void findPath(int s, int d) {
        boolean visited[] = new boolean[V];

        if (DFSUtil(s, d, visited) == false)
            System.out.println("No path exists");

        System.out.println();
    }

    public static void main(String args[]) {
        Maze maze = new Maze(9); // Assume we have 9 rooms

        maze.addDoor(0, 1);
        maze.addDoor(0, 3);
        maze.addDoor(1, 2);
        maze.addDoor(1, 3);
        maze.addDoor(2, 4);
        maze.addDoor(3, 4);
        maze.addDoor(4, 5);
        maze.addDoor(5, 6);
        maze.addDoor(6, 7);
        maze.addDoor(7, 8);

        System.out.println("Path from room 0 to room 8:");
        maze.findPath(0, 8);
    }
}

在这个例子中,我们首先定义了一个Maze类,它有两个私有变量:V(房间的数量)和adj(邻接列表)。然后我们在构造函数中初始化这些变量。

我们定义了一个addDoor方法来添加门。由于这是一个无向图,所以我们需要在两个房间的邻接列表中都添加对方。

我们还定义了一个findPath方法来找到从源房间到目标房间的路径。这个方法使用了深度优先搜索(DFS)算法,并且使用了一个辅助方法DFSUtil来进行递归搜索。

在main方法中,我们创建了一个Maze对象,并添加了一些门,然后找到了从房间0到房间8的路径。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

P1392 取数

传送门&#xff1a;取数 如若你看完题解后&#xff0c;仍有问题&#xff0c;欢迎评论 首先说一下 我首先想到的思路 &#xff08; 20%通过率 &#xff09;&#xff1a;通过dfs , 将所有的情况放入priority_queue中&#xff08;greater<int>&#xff09;&#xff0c;维持…

计算两种人像之间的相似度

通过调研&#xff0c;目前存在几种能够计算两个人脸相似度的方法&#xff1a; 1.使用结构相似性计算人脸之间的相似度 结构准确性&#xff1a;生成的图片是否保留了原图足够多细节。 &#xff08;1&#xff09;结构准确性衡量指标&#xff1a;SSIM/MMSSIM SSIM&#xff08;结构…

纯前端低代码开发脚手架 - daelui/molecule

daelui/molecule低代码开发脚手架&#xff1a;分子组件开发、预览、打包 页面代码示例、大屏代码示例预览 可开发页面组件 可开发大屏组件 项目git地址&#xff1a;https://gitee.com/daelui/molecule 在线预览&#xff1a;http://www.daelui.com/daelui/molecule/app/index.…

STM32第十六课:WiFi模块的配置及应用

文章目录 需求一、WiFi模块概要二、配置流程1.配置通信串口&#xff0c;引脚和中断2.AT指令3.发送逻辑编写 三、需求实现代码总结 需求 完成WiFi模块的配置,使其最终能和服务器相互发送消息。 一、WiFi模块概要 本次使用的WiFi模块为ESP-12F模块&#xff08;安信可&#xf…

聚类分析方法(一)

目录 一、聚类分析原理&#xff08;一&#xff09;聚类分析概述&#xff08;二&#xff09;聚类的数学定义&#xff08;三&#xff09;簇的常见类型&#xff08;四&#xff09;聚类框架及性能要求&#xff08;五&#xff09;簇的距离 二、划分聚类算法&#xff08;一&#xff0…

车载测试之-CANoe创建仿真工程

在现代汽车工业中&#xff0c;车载测试是确保车辆电子系统可靠性和功能性的关键环节。而使用CANoe创建仿真工程&#xff0c;不仅能够模拟真实的车辆环境&#xff0c;还能大大提升测试效率和准确性。那么&#xff0c;CANoe是如何实现这些的呢&#xff1f; 车载测试中&#xff0…

PXIe-7976【K410T】

起售价 RMB 152,880.00 块RAM(BRAM): 28620 kbit 动态RAM(DRAM): 2 GB FPGA: Kintex-7 410T PXI背板链路: PCI-Express Gen2 x 8 FPGA片: 63550 DSP片: 1540

敏感词匹配DFA算法

算法简介与场景介绍 DFA算法&#xff0c;中文全称为确定性有穷自动机。它的基本思想是构建一个有穷自动机&#xff0c;当用户输入文本时&#xff0c;通过自动机的状态转换来快速匹配敏感词。具体特征是&#xff0c;有一个有效状态的集合和一些从一个状态通向另一个状态的边&am…

并发处理 优先图和多重图

优先图(Precedence Graph)视图可串性多重图(Polygraph) 优先图(Precedence Graph) 优先图用于冲突可串性的判断。 优先图结构&#xff1a; 结点 (Node)&#xff1a;事务&#xff1b;有向边 (Arc): Ti → Tj &#xff0c;满足 Ti <s Tj&#xff1b; 存在Ti中的操作A1和Tj…

利用redis Zset实现 排行榜功能 配合xxl-job持久化每一个赛季的排行榜

zset 可以排序 使用xxl-job实现定时任务 对历史排行榜持久化到数据库 排行榜有当前赛季排行版和历史排行榜 当前赛季排行榜利用redis 中的SortSet 数据结构 获取 每个月的 月初 利用xxl-job的定时任务持久化化上一个月的排行榜信息 并删除redis中的数据 当排行榜数据量巨大时…

【5G VoNR】VoNR流程简述

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G技术研究。 博客内容主要围绕…

移动校园(5):课程表数据获取及展示

首先写下静态页面&#xff0c;起初打算做成一周的课表&#xff0c;由于是以小程序的形式展现&#xff0c;所以显示一周的话会很拥挤&#xff0c;所以放弃下面的方案&#xff0c;改作一次显示一天 改后结果如下&#xff0c;后期还会进行外观优化 真正困难的部分是数据获取 大家大…

拆分Transformer注意力,韩国团队让大模型解码提速20倍|大模型AI应用开始小规模稳步爆发|周伯文:大模型也有幻觉,全球AI创新指数公布

拆分Transformer注意力&#xff0c;韩国团队让大模型解码提速20倍AI正在颠覆AI上市不到两年&#xff0c;蜗牛游戏可能要退市了&#xff1f;世界人工智能大会结束了&#xff0c;百花齐放&#xff0c;但也群魔乱舞“串联OLED”被苹果带火了&#xff0c;比OLED强在哪里&#xff1f…

文化财经macd顶底背离幅图指标公式源码

DIFF:EMA(CLOSE,12) - EMA(CLOSE,26); DEA:EMA(DIFF,9); MACD:2*(DIFF-DEA),COLORSTICK; JC:CROSS(DIFF,DEA); SC:CROSSDOWN(DIFF,DEA); N1:BARSLAST(JC)1; N2:BARSLAST(SC)1; HH:VALUEWHEN(CROSSDOWN(DIFF,DEA),HHV(H,N1));//上次MACD红柱期间合约最大值 HH2:VALUEWHE…

MySQL:视图、用户管理、C/C++/图形化界面链接访问数据库、网页逻辑

文章目录 1.视图1.1 视图的基本使用1.2 视图的基本规则 2.用户管理2.1 创建、删除、修改用户2.2 数据库权限 3.C/C/图形化界面链接访问数据库3.1 准备工作及常用接口介绍3.2 图形化界面访问MySQL 4.用户逻辑(注册&&登录) 1.视图 视图是一个虚拟表&#xff0c;其内容由…

springboot苏桦旅游管理系统-计算机毕业设计源码02123

摘要 旅游业在全球范围内不断发展&#xff0c;为了提供高效的旅游管理和服务&#xff0c;开发一个旅游管理系统具有重要意义。本文旨在设计和实现该旅游管理系统&#xff0c;以满足用户和管理员的需求。该系统采用Spring Boot作为后端框架&#xff0c;利用其简化的开发流程和强…

ComfyUI如何高效率使用多Lora

Efficient 工作流 {"last_node_id": 29,"last_link_id": 56,"nodes": [{"id": 26,"type": "LoRA Stacker","pos": [540,270],"size": {"0": 320,"1": 322},"flag…

如何让代码兼容 Python 2 和 Python 3?Future 库助你一臂之力

目录 01Future 是什么? 为什么选择 Future? 安装与配置 02Future 的基本用法 1、兼容 print 函数 2、兼容整数除法 3、兼容 Unicode 字符串 03Future 的高级功能 1. 处理字符串与字节 2. 统一异常处理…

STM32-TIM定时器

本内容基于江协科技STM32视频内容&#xff0c;整理而得。 文章目录 1. TIM1.1 TIM定时器1.2 定时器类型1.3 基本定时器1.4 通用定时器1.4 高级定时器1.5 定时中断基本结构1.6 预分频器时序1.7 计数器时序1.8 计数器无预装时序1.9 计数器有预装时序1.10 RCC时钟树 2. TIM库函数…

路径跟踪算法之PID、PP、Stanley详细理解

一、前言 今天又来补作业了&#xff01; 在跟踪控制领域&#xff0c;PID&#xff08;Proportional-Integral-Derivative, 分别为比例、积分、微分&#xff09;、PP&#xff08; Pure-Puresuit, 纯跟踪&#xff09;、Stanley&#xff08;前轮反馈控制&#xff09;是三种最为常见…