非线性数据结构之图

news/2024/11/8 23:52:13 标签: 数据结构

一、无环图(Acyclic Graph)

1. 定义

无环图是一种没有环路的图,图中的路径不会形成封闭回路。如果无环图是有向的,则称为 有向无环图(DAG, Directed Acyclic Graph)

2. 特点
  • 无环性:无环图中不存在任何顶点能通过一系列边回到自身的路径。
  • 拓扑结构:有向无环图可以进行拓扑排序,将图中的所有顶点线性排序,使得对于每条边 u→v,顶点 u 在 v 之前。
  • 有向无环图(DAG):有向图中没有任何循环的子图。
  • 无向无环图:若是无向图,则无环图为树或森林。
3. 优缺点
  • 优点
    • DAG 支持拓扑排序,适合表达依赖关系。
    • 在算法中常用于流程管理,如任务调度、编译器中的依赖图。
  • 缺点
    • 图的构建和验证无环性相对复杂。
    • 无法表达循环依赖或重复路径。
4. 应用场景
  • 任务调度:表示任务及其依赖关系,确保任务按正确顺序执行。
  • 数据流分析:分析和优化数据流,确保无循环依赖。
  • 版本控制:Git 等版本控制系统使用 DAG 表示分支和合并。
5. 示例

DAG 示例:

该图表示任务 A 完成后可以进行任务 B 和 D,而 C 需要在 B 完成后执行。

示例代码(Java 实现检测 DAG)
import java.util.*;

class Graph {
    private Map<String, List<String>> adjacencyList;

    public Graph() {
        adjacencyList = new HashMap<>();
    }

    public void addVertex(String vertex) {
        adjacencyList.putIfAbsent(vertex, new ArrayList<>());
    }

    public void addEdge(String from, String to) {
        adjacencyList.putIfAbsent(from, new ArrayList<>());
        adjacencyList.putIfAbsent(to, new ArrayList<>());
        adjacencyList.get(from).add(to);
    }

    public boolean isDAG() {
        Set<String> visited = new HashSet<>();
        Set<String> recStack = new HashSet<>();
        for (String vertex : adjacencyList.keySet()) {
            if (isCyclic(vertex, visited, recStack)) {
                return false;
            }
        }
        return true;
    }

    private boolean isCyclic(String vertex, Set<String> visited, Set<String> recStack) {
        if (recStack.contains(vertex)) {
            return true;
        }
        if (visited.contains(vertex)) {
            return false;
        }
        visited.add(vertex);
        recStack.add(vertex);
        for (String neighbor : adjacencyList.get(vertex)) {
            if (isCyclic(neighbor, visited, recStack)) {
                return true;
            }
        }
        recStack.remove(vertex);
        return false;
    }
}

二、邻接矩阵(Adjacency Matrix)

1. 定义

邻接矩阵是图的表示方式之一,用一个二维数组来存储图中顶点之间的连接关系。矩阵的行和列代表图的顶点,数组元素表示对应顶点之间是否存在边。

2. 特点
  • 大小:对于有 n 个顶点的图,邻接矩阵的大小为 n×n。
  • 元素表示
    • 在无权图中,元素为 0 或 1,表示有无边。
    • 在加权图中,元素为边的权重或无穷大(表示无边)。
3. 优缺点
  • 优点
    • 查询高效:判断顶点之间是否存在边的时间复杂度为 O(1)。
    • 简单直观:适合存储稠密图(边多的图)。
  • 缺点
    • 空间复杂度高:需要 O(n2) 的空间,即使图较稀疏。
    • 添加和删除顶点不便:需要重新调整矩阵。
4. 应用场景
  • 网络图:存储所有可能的连接关系,如网络拓扑结构。
  • 图论算法:如 Floyd-Warshall 算法求任意两点间的最短路径。
5. 示例

邻接矩阵表示如下图:

邻接矩阵表示:

ABCD
A0110
B1001
C1001
D0110
示例代码(Java 实现邻接矩阵)
class AdjacencyMatrixGraph {
    private int[][] matrix;
    private int numVertices;

    public AdjacencyMatrixGraph(int numVertices) {
        this.numVertices = numVertices;
        matrix = new int[numVertices][numVertices];
    }

    public void addEdge(int i, int j) {
        matrix[i][j] = 1;
        matrix[j][i] = 1; // 无向图
    }

    public boolean hasEdge(int i, int j) {
        return matrix[i][j] != 0;
    }
}

三、邻接表(Adjacency List)

1. 定义

邻接表是另一种图的表示方式,使用链表或数组列表来存储每个顶点的邻居。每个顶点维护一个列表,包含它所连接的所有其他顶点。

2. 特点
  • 存储灵活:根据每个顶点的度数,所需的存储空间不同。
  • 空间高效:对于稀疏图(边少的图)更节省空间,所需空间为 O(V+E)。
  • 动态性强:添加和删除边和顶点相对简单。
3. 优缺点
  • 优点
    • 空间节省:适合稀疏图。
    • 动态操作方便:容易添加和删除边。
  • 缺点
    • 查询效率低:判断是否存在边的时间复杂度为 O(k),其中 k 是顶点的度数。
    • 实现稍复杂:相比邻接矩阵,结构更复杂。
4. 应用场景
  • 社交网络:表示用户和用户之间的朋友关系。
  • 图遍历:如广度优先搜索(BFS)和深度优先搜索(DFS)中经常使用。
5. 示例

邻接表表示如下图:

邻接表表示:

import java.util.*;

class AdjacencyListGraph {
    private Map<Integer, List<Integer>> adjacencyList;

    public AdjacencyListGraph() {
        adjacencyList = new HashMap<>();
    }

    public void addVertex(int vertex) {
        adjacencyList.putIfAbsent(vertex, new ArrayList<>());
    }

    public void addEdge(int vertex1, int vertex2) {
        adjacencyList.get(vertex1).add(vertex2);
        adjacencyList.get(vertex2).add(vertex1); // 无向图
    }

    public List<Integer> getNeighbors(int vertex) {
        return adjacencyList.get(vertex);
    }
}

总结比较

表示方式优点缺点应用场景
邻接矩阵查询边存在性快(O(1)),结构简单空间复杂度高(O(n^2)),稀疏图不高效稠密图、网络结构
邻接表空间效率高(O(V + E)),适合动态操作查询边存在性慢(O(k))稀疏图、社交网络
无环图 (DAG)适合表达依赖关系,可拓扑排序验证无环性复杂任务调度、数据流分析


http://www.niftyadmin.cn/n/5744579.html

相关文章

手撕代码要做(更新)

https://mp.weixin.qq.com/s?__bizMzkyNTY0Mjg0OQ&mid2247483790&idx1&sn308fb18b66cc66b78f7e15822cdd6eff&scene21#wechat_redirect 算法工程师面试常考手撕题&#xff08;更新&#xff09; Transformer篇 单头注意力多头注意力位置编码 神经网络篇 BP…

c++ 多态性

类的多态 多态概念入门 #include <iostream> using namespace std;/* 多态的前提: 拥有继承关系的类中有相同的函数(返回类型、函数名、形参列表) 多态解决的问题&#xff1a;1、派生类的对象被赋值给基类对象时2、派生类的对象初始化基类的引用时3、基类的指针指向派生…

前端 Canvas 绘画 总结

目录 一、使用案例 1、基础使用案例 2、基本案例改为直接JS实现 二、相关资料 1、API教程文档 2、炫酷案例 一、使用案例 1、基础使用案例 使用Canvas的基本步骤&#xff1a; 1、需要一个canvas标签 2、需要获取 画笔 对象 3、使用canvas提供的api进行绘图 <!--…

HTB:Perfection[WriteUP]

目录 连接至HTB服务器并启动靶机 1.What version of OpenSSH is running? 使用nmap对靶机TCP端口进行开放扫描 2.What programming language is the web application written in? 使用浏览器访问靶机80端口页面&#xff0c;并通过Wappalyzer查看页面脚本语言 3.Which e…

基础算法练习--滑动窗口(已完结)

算法介绍 滑动窗口算法来自tcp协议的一种特性,它的高效使得其也变成了算法题的一种重要考点.滑动窗口的实现实际上也是通过两个指针前后遍历集合实现,但是因为它有固定的解题格式,我将其单独做成一个篇章. 滑动窗口的解题格式: 首先,定义两个指针left和right,与双指针不同的…

html的week控件 获取周(星期)的第一天(周一)和最后一天(周日)

html的week控件 获取周(星期)的第一天(周一)和最后一天(周日) <input type"week" id"week" class"my-css" value"ViewBag.DefaultWeek" /><script> function PageList() { var dateStrin…

理解Web登录机制:会话管理与跟踪技术解析(一)

在这篇博客中&#xff0c;我们将深入探讨登录校验、会话技术和会话跟踪技术的基本概念、实现原理及其在Web应用中的应用。我们将介绍常见的会话跟踪技术&#xff0c;如Cookies、Session&#xff0c;并讨论它们的优缺点。同时&#xff0c;我们也会涉及如何使用现有的技术栈来实现…

MySQL 到 ClickHouse 数据同步优化(三)

简述 本文主要介绍 CloudCanal 如何将关系型数据库中数据同步到 ClickHouse&#xff0c;默认使用 ReplacingMergeTree 作为 ClickHouse 表引擎&#xff0c;链路特点包括&#xff1a; 新增 _version、_sign 字段&#xff0c;以便 ClickHouse 准确合并。DML 操作均以 INSERT 写…