news 2026/4/16 13:33:24

图的基础概念操作与遍历

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
图的基础概念操作与遍历

一、图的基础概念与术语

  1. 概念:图是一种非线性数据结构,由顶点和边组成,相较于线性关系(链表)和分治关系(树),网络关系(图)的自由度更高,因而更为复杂。

  2. 常见类型

    1. 是否有方向:无向图与有向图

      • 在无向图中,边表示两顶点之间的“双向”连接关系
      • 在有向图中,边具有方向性,即A→B和B→A两个方向的边是相互独立的
    2. 所有顶点是否连通:连通图和非连通图

      • 对于连通图,从某个顶点出发,可以到达其余任意顶点。
      • 对于非连通图,从某个顶点出发,至少有一个顶点无法到达。
    3. 我们还可以为边添加“权重”变量,从而得到有权图

  3. 术语:

    1. 邻接:当两顶点之间存在边相连时,称这两顶点“邻接”。
    2. 路径:从顶点 A 到顶点 B 经过的边构成的序列被称为从 A 到 B 的“路径”。
    3. 度:一个顶点拥有的边数。对于有向图,入度表示有多少条边指向该顶点,出度表示有多少条边从该顶点指出。

二、图的表示

  1. 邻接矩阵:设图的顶点数量为 ,邻接矩阵使用一个 大小的矩阵来表示图,每一行(列)代表一个顶点,矩阵元素代表边,用0或1表示两个顶点之间是否存在边。

  1. 邻接表:邻接表(adjacency list)使用n个链表来表示图,链表节点表示顶点。第i个链表对应顶点i,其中存储了该顶点的所有邻接顶点(与该顶点相连的顶点)。

三、图的基础操作

  1. 基于邻接矩阵的实现
/* 基于邻接矩阵实现的无向图类 */ class GraphAdjMat { vector<int> vertices; vector<vector<int>> adjMat; public: /* 构造方法 */ GraphAdjMat(const vector<int> &vertices, const vector<vector<int>> &edges) { // 添加顶点 for (int val : vertices) { addVertex(val); } // 添加边 for (const vector<int> &edge : edges) { addEdge(edge[0], edge[1]); } } /* 获取顶点数量 */ int size() const { return vertices.size(); } /* 添加顶点 */ void addVertex(int val) { int n = size(); vertices.push_back(val); adjMat.emplace_back(vector<int>(n, 0)); for (vector<int> &row : adjMat) { row.push_back(0); } } /* 删除顶点 */ void removeVertex(int index) { if (index >= size()) { throw out_of_range("顶点不存在"); } vertices.erase(vertices.begin() + index); adjMat.erase(adjMat.begin() + index); for (vector<int> &row : adjMat) { row.erase(row.begin() + index); } } /* 添加边 */ // 参数 i, j 对应 vertices 元素索引 void addEdge(int i, int j) { if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) { throw out_of_range("顶点不存在"); } adjMat[i][j] = 1; adjMat[j][i] = 1; } /* 删除边 */ void removeEdge(int i, int j) { if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) { throw out_of_range("顶点不存在"); } adjMat[i][j] = 0; adjMat[j][i] = 0; } /* 打印邻接矩阵 */ void print() { cout << "顶点列表 = "; printVector(vertices); cout << "邻接矩阵 =" << endl; printVectorMatrix(adjMat); } };
  1. 基于邻接表的实现
/* 基于邻接表实现的无向图类 */ class GraphAdjList { public: unordered_map<Vertex *, vector<Vertex *>> adjList; /* 在 vector 中删除指定节点 */ void remove(vector<Vertex *> &vec, Vertex *vet) { for (int i = 0; i < vec.size(); i++) { if (vec[i] == vet) { vec.erase(vec.begin() + i); break; } } } /* 构造方法 */ GraphAdjList(const vector<vector<Vertex *>> &edges) { for (const vector<Vertex *> &edge : edges) { addVertex(edge[0]); addVertex(edge[1]); addEdge(edge[0], edge[1]); } } /* 获取顶点数量 */ int size() { return adjList.size(); } /* 添加边 */ void addEdge(Vertex *vet1, Vertex *vet2) { if (!adjList.count(vet1) || !adjList.count(vet2) || vet1 == vet2) throw invalid_argument("不存在顶点"); adjList[vet1].push_back(vet2); adjList[vet2].push_back(vet1); } /* 删除边 */ void removeEdge(Vertex *vet1, Vertex *vet2) { if (!adjList.count(vet1) || !adjList.count(vet2) || vet1 == vet2) throw invalid_argument("不存在顶点"); remove(adjList[vet1], vet2); remove(adjList[vet2], vet1); } /* 添加顶点 */ void addVertex(Vertex *vet) { if (adjList.count(vet)) return; adjList[vet] = vector<Vertex *>(); } /* 删除顶点 */ void removeVertex(Vertex *vet) { if (!adjList.count(vet)) throw invalid_argument("不存在顶点"); adjList.erase(vet); for (auto &adj : adjList) { remove(adj.second, vet); } } /* 打印邻接表 */ void print() { cout << "邻接表 =" << endl; for (auto &adj : adjList) { const auto &key = adj.first; const auto &vec = adj.second; cout << key->val << ": "; printVector(vetsToVals(vec)); } } };

四、图的遍历

  1. 广度优先搜索:广度优先遍历是一种由近及远的遍历方式,从某个节点出发,始终优先访问距离最近的顶点,并一层层向外扩张
  2. 代码实现:
vector<Vertex *> graphBFS(GraphAdjList &graph, Vertex *startVet) { vector<Vertex *> res; unordered_set<Vertex *> visited = {startVet}; queue<Vertex *> que; que.push(startVet); while (!que.empty()) { Vertex *vet = que.front(); que.pop(); res.push_back(vet); for (auto adjVet : graph.adjList[vet]) { if (visited.count(adjVet)) continue; que.push(adjVet); visited.emplace(adjVet); } } return res; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 20:56:47

wangEditor实现word公式粘贴转MathType格式

企业网站后台管理系统Word集成方案设计与实施 作为河北IT行业集团上市公司项目负责人&#xff0c;针对企业网站后台管理系统文章发布模块的Word集成需求&#xff0c;我进行了全面的技术评估与方案规划。以下是基于集团技术栈和业务需求的完整解决方案。 一、技术选型与产品评…

作者头像 李华
网站建设 2026/4/16 13:33:22

Spring-AI系列——Tool Calling获取当前时间

文章目录一、调用流程二、代码tool包下的TimeTools.java类controller.ZhipuChatClientController.java三、效果四、底层调用情况一、调用流程 二、代码 tool包下的TimeTools.java类 package org.example.tool;import org.springframework.ai.tool.annotation.Tool; import or…

作者头像 李华
网站建设 2026/4/16 13:32:33

探索基于STM32F407VET6的三相PFC技术之旅

基于stm32f407Vet6的三相PFC参考利用dq变换&#xff0c;PID控制&#xff0c;spwm等&#xff0c;知识点非常多&#xff0c;是您学习技术的好帮手&#xff0c;成语完整&#xff0c;并有详细技术文档说明&#xff0c;程序工程可编译&#xff0c;并带有中文注释。在电力电子领域&am…

作者头像 李华
网站建设 2026/4/16 10:53:13

一文搞懂CNN - LSTM - Attention回归预测:新手友好实战

CNN-LSTM-Attention回归&#xff0c;基于卷积神经网络(CNN)-长短期记忆神经网络(LSTM)结合注意力机制(Attention)的数据回归预测&#xff0c;多变量输入单输入&#xff0c;可以更换为时序预测&#xff0c;多变量/单变量都有 LSTM可根据需要更换为BILSTM,GRU 程序已经调试好&…

作者头像 李华
网站建设 2026/4/16 12:33:48

SPSS——判别分析——“一般判别分析”

更多免费教程和软件 :​ 判别分析 【判别分析的概念和目的】 判别分析是一种对观察对象进行分类的统计学方法,它与聚类分析不同,它在分析之前就非常明确观察对象分为几个类别,该分析方法的目的就是从现有已知类别的观察对象中建立一个判别函数来,然后再用该判别函数去判…

作者头像 李华
网站建设 2026/4/16 11:05:28

Agent 结构(LLM + Tool + Executor)

day29&#xff1a;理解Agent 结构&#xff08;LLM Tool Executor&#xff09; 一、Agent定义 简单介绍 Agent 能“思考 → 决策 → 调用工具 → 再思考”的 LLM 程序 公式化一点就是&#xff1a; Agent LLM Tools Executor它和「问 → 答」最大的区别是&#xff1a; LLM …

作者头像 李华