场景设定

想象你是一个社交达人,要记录你和所有朋友的关系(这就是“图”)。每个朋友是一个节点,关系是一条边。你需要快速回答:“我有哪些朋友?”(遍历邻居)。


方式1:链式前向星(固定小本本)

  • 核心思想:你买了一个固定页数的笔记本(预分配的数组)。

  • 怎么记?

    1. 给每个朋友一个专属页(head[你])。
    2. 每认识一个新朋友,就在笔记本最新空白页记录:
      • 朋友名字 (to)
      • 和你的关系 (weight,可选)
      • 关键! 还要写上“上一个记录在笔记本第几页?” (next)
    3. 更新你的专属页:写上最新这条记录的页码
  • 通俗比喻

    • 你的笔记本就是 edges[] 数组(每条边占一页)。
    • head[你] 是你名字标签贴纸指向的最新记录页码。
    • next 就像是“上一条记录在第几页?”的提示。
    • 要查所有朋友?从 head[你] 找到最新记录,然后根据 next 翻到前一页,再前一页…直到没记录了(next = -1)。

优点

  1. 省空间(内存少)
    • 笔记本只记核心信息(朋友名、关系、上条页码),没有多余开销。
    • vector 像活页夹,每页本身还有夹子、标签等额外重量(vector 的容量指针、大小等元数据)。
  2. 加朋友超快(O(1))
    • 直接写在最新空白页,更新你的标签贴纸 (head) 就行。固定操作,永不拖延。
  3. 笔记本整齐(内存连续)
    • 所有记录按页码连续存放。CPU 一次“搬”一摞记录进缓存效率高(缓存友好),但翻页查找过程不连续

缺点

  1. 笔记本页数固定(静态大小)
    • 买的时候要猜最多交多少朋友。朋友太多?本子写满了,得重买更大的本子,全部重抄一遍(重新初始化,扩容麻烦)。
  2. 绝交(删除边)超麻烦
    • 想删掉一个朋友的记录?你得顺着链条一页页找,找到后还要修改它前后记录的 next 指向,像拆掉一节火车车厢。几乎没人用链式前向星删边。
  3. 查朋友名单有点慢(遍历效率)
    • 虽然记录在物理上是连续的,但你查名单时是根据 next 跳着翻页(第 5 页 -> 第 2 页 -> 第 8 页)。翻页动作不连贯,CPU 缓存可能帮不上忙。
  4. 写起来费劲(代码复杂)
    • 你得自己维护 head 和每条记录的 next 指针。写代码时容易搞晕,调试也麻烦。

代码:

#include <bits/stdc++.h> 
using namespace std;
const int N = 1000;  // 最大节点数
const int M = 10000; // 最大边数// 定义边的结构体
struct Edge {int to;     // 这条边指向哪个节点int next;   // 同一个起点的下一条边的索引(相当于"上一条记录的页码")int w;      // 边权(可选)
} edges[M];  // 存储所有边的数组int head[N]; // head[u] 表示节点 u 的第一条边的索引(初始为 -1)
int idx = 0;    // 当前边的索引(相当于"最新空白页的页码")// 添加一条从 u 到 v 的边,权重为 w
void addEdge(int u, int v, int w) {edges[idx].to = v;       // 记录这条边指向 vedges[idx].w = w;        // 记录边权edges[idx].next = head[u]; // 新边的 next 指向 u 原来的第一条边head[u] = idx++;         // 更新 u 的第一条边为当前这条边
}// 遍历节点 u 的所有邻居
void printNeighbors(int u) {cout << "节点 " << u << " 的朋友: ";for (int i = head[u]; i != -1; i = edges[i].next) {int v = edges[i].to;int w = edges[i].w;cout << v << "(亲密度:" << w << ") ";}cout << endl;
}int main() {memset(head, -1, sizeof(head)); // 初始化 head 数组为 -1(表示空链表)// 添加边:0 -> 1 (权重 5), 0 -> 2 (权重 3), 1 -> 2 (权重 2)addEdge(0, 1, 5);addEdge(0, 2, 3);addEdge(1, 2, 2);// 打印邻居printNeighbors(0); // 输出: 节点 0 的朋友: 2(亲密度:3) 1(亲密度:5)printNeighbors(1); // 输出: 节点 1 的朋友: 2(亲密度:2)return 0;
}

关键点

  • head[u] 存储节点 u最新一条边的索引(类似链表头指针)。
  • edges[idx] 存储所有边,idx 是当前可用的边索引(类似动态分配的页数)。
  • next 指向同起点的上一条边(类似链表的前驱指针)。
  • 遍历时,从 head[u] 开始,沿着 next 走,直到 -1(类似链表遍历)。

适合谁? 朋友数量上限确定(比如竞赛题已知最大点数/边数),追求极致速度和省内存的“极客”。


方式2:Vector 邻接表(活页文件夹)

  • 核心思想:你买了一个带标签的活页文件夹。给每个朋友(包括你自己)分配一个专属分区

  • 怎么记?

    1. 想加一个新朋友“老王”?
    2. 直接找到你自己的分区
    3. 在分区里新加一页活页纸,写上“老王”和你们的关系(vector[你].push_back(Edge{老王, 关系}))。
  • 通俗比喻

    • 文件夹是 vector > graph
    • 每个分区是 graph[你]graph[朋友A]graph[朋友B]
    • 每个分区里的活页纸就是该节点的所有邻居边记录。

优点

  1. 分区独立,无限加页(动态扩容)
    • 你的分区写满了?系统自动给你换更大的分区页夹(vector 自动扩容)。虽然换的时候要复印所有旧页(复制数据),但均摊下来每次加页还是很快(均摊 O(1))。
  2. 查朋友名单超快(遍历高效)
    • 打开你自己的分区,里面的活页纸按添加顺序叠放(内存连续)。你可以一口气从头翻到尾,翻页动作流畅,CPU 缓存疯狂点赞!
  3. 用起来超简单(代码简洁)
    • 加朋友?一句 graph[你].push_back(老王)。查朋友?一个 for 循环遍历 graph[你]。逻辑清晰,不易出错。
  4. 额外功能强大(STL支持)
    • 想按关系亲密度排序朋友?直接用 sort(graph[你].begin(), graph[你].end())。想找特定朋友?可以用 find。活页夹兼容各种“办公用具”(STL算法)。

缺点

  1. 文件夹本身有点重(内存开销大)
    • 每个分区(vector)都要维护自己的“目录”(容量、大小等元数据)。朋友非常多时,比链式前向星多占 20%-50% 内存。
  2. 换分区页夹时手忙脚乱(扩容开销)
    • 虽然系统自动帮你换,但换的那一刻(扩容)要把所有旧页复印到新分区,这时添加操作会短暂变慢(虽然均摊后很快,但有波动)。
  3. 撕掉某页很麻烦(删除边低效)
    • 想删掉分区中间一页?你得把后面所有页往前挪一格(vector 删除中间元素 O(度数))。除非你总是删最后一页(pop_back)。
  4. 分区分散(内存不连续)
    • 你的分区、朋友A的分区、朋友B的分区在文件夹里可能不挨着。虽然每个分区内部连续,但访问不同节点时,CPU 可能要在文件夹里跳来跳去。

适合谁? 朋友数量不确定或经常变,追求代码好写、好读、易维护的“务实派”。绝大多数工程项目的首选。

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1000; // 最大节点数// 定义边的结构体(比链式前向星更简单,不需要 next)
struct Edge {int to; // 这条边指向哪个节点int w;  // 边权(可选)
};vector<Edge> graph[N]; // graph[u] 存储节点 u 的所有邻居// 添加一条从 u 到 v 的边,权重为 w
void addEdge(int u, int v, int w) {graph[u].push_back({v, w}); // 直接 push_back 即可
}// 遍历节点 u 的所有邻居
void printNeighbors(int u) {cout << "节点 " << u << " 的朋友: ";for (Edge e : graph[u]) {cout << e.to << "(亲密度:" << e.w << ") ";}cout << endl;
}int main() {// 添加边:0 -> 1 (权重 5), 0 -> 2 (权重 3), 1 -> 2 (权重 2)addEdge(0, 1, 5);addEdge(0, 2, 3);addEdge(1, 2, 2);// 打印邻居printNeighbors(0); // 输出: 节点 0 的朋友: 1(亲密度:5) 2(亲密度:3)printNeighbors(1); // 输出: 节点 1 的朋友: 2(亲密度:2)return 0;
}

关键点

  • graph[u] 是一个 vector,直接存储 u 的所有邻居边。
  • 添加边直接用 push_back,无需维护 next 指针。
  • 遍历时直接 for (Edge e : graph[u]),比链式前向星更直观。

总结

总的来说,两款存图方式各有优劣,具体取决于需求和喜好

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YAML 中定义 List 的几种方式

在 YAML 配置文件中定义 List 并在 Spring 应用中注入是非常常见的操作&#xff0c;下面详细介绍具体写法和注入方式。一、YAML 中定义 List 的几种方式1. 缩进式写法&#xff08;推荐&#xff09;最常用的方式&#xff0c;通过短横线 - 加空格表示列表项&#xff1a;yaml# app…

C# 反射和特性(自定义特性)

自定义特性 你或许已经注意到了&#xff0c;应用特性的语法和之前见过的其他语法有很大不同。你可能会觉得特 性是一种完全不同的结构类型&#xff0c;其实不是&#xff0c;特性只是一种特殊的类。 有关特性类的一些要点如下。 用户自定义的特性类叫作自定义特性。所有特性类都…

科目二的四个电路

一.K21电动机单连续运转接线(带点动控制)1.电路图2.主线路这可很明了,是一条直线,从上接到下就OK了,然后从热继电器出来,接到SB3按钮的常闭触点上接着往下走一端接到SB2的常闭触点上,接着往下走&#xff0c;走到接触器的线圈上,从L2借一条火线出来,从熔断器的上端接入,另一端接…

【位运算】查询子数组最大异或值|2693

本文涉及知识点 位运算、状态压缩、枚举子集汇总 3277. 查询子数组最大异或值 给你一个由 n 个整数组成的数组 nums&#xff0c;以及一个大小为 q 的二维整数数组 queries&#xff0c;其中 queries[i] [li, ri]。 对于每一个查询&#xff0c;你需要找出 nums[li…ri] 中任…

HTML DOM 方法

HTML DOM 方法 引言 HTML DOM&#xff08;文档对象模型&#xff09;是HTML文档的编程接口&#xff0c;它允许开发者通过JavaScript来操作HTML文档中的元素。DOM 方法是DOM编程的核心&#xff0c;它提供了丰富的操作手段来改变网页的结构、样式和行为。本文将详细介绍HTML DOM中…

w嵌入式分享合集68

自己的原文哦~ https://blog.51cto.com/whaosoft/14133002 一、一键开关机电路的设计方案 方案一&#xff1a;电路图 一键开关机电路分析如下&#xff1a; 电路工作流程如下&#xff1a; Key按下瞬间&#xff0c;Q2、Q1导通&#xff0c;7805输入电压在8.9V左右&…

FFmpeg QoS 处理

FFmpeg 中的 QoS (服务质量) 处理主要关注于实时流媒体传输中的时序控制、丢帧策略和网络适应等方面。以下是 FFmpeg 中 QoS 相关的关键机制和配置方法。1. 基本 QoS 机制丢帧策略 (Frame Dropping)cAVDictionary *options NULL; av_dict_set(&options, "framedrop&q…

TexStudio中的Latex,PDFLatex,XeLatex和LuaLatex的区别

多种LaTeX编译器一、多种LaTeX编译器 1.1 PDFLaTeX&#xff08;1994年&#xff09; 默认、最常用的引擎。 输入文件通常是 ASCII 或 UTF-8 编码&#xff08;但中文需要 CJK 宏包或 ctex 宏包支持&#xff09;。 字体选择受限&#xff1a;只能使用 TeX 自带的字体或者 Type 1…

容器化部署:用Docker封装机器翻译模型与服务详解

文章目录一、机器翻译容器化的技术栈选型1.1 为什么需要容器化MT模型&#xff1f;1.2 基础镜像选择对比1.3 典型依赖分层方案1.4 性能对比&#xff08;容器化 vs 原生部署&#xff09;二、关键部署模式2.1 轻量级API服务封装2.2 模型热更新策略三、Docker镜像构建3.1 编写Docke…

leetcode_42 接雨水

1. 题意 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 2. 题解 这个题不会做&#xff0c;全部是看得题解捏。 不过能看懂题解感觉自己也很棒了&#xff01; 看完题解后感觉最难的是如何求出有多少…

Spring Boot 整合 Thymeleaf 模板引擎:从零开始的完整指南

引言&#xff1a;为什么选择 Thymeleaf&#xff1f; Thymeleaf 是一个现代化的服务器端 Java 模板引擎&#xff0c;专为 Web 开发而设计。与 JSP 不同&#xff0c;Thymeleaf 模板是纯 HTML 文件&#xff0c;可以直接在浏览器中预览&#xff0c;无需后端服务器支持。这种"…

pytest介绍(python测试框架)(@pytest.mark.parametrize、@pytest.fixtures)

文章目录**1. 核心特点**- **简洁易用**&#xff1a;无需复杂的配置&#xff0c;只需编写简单的函数或类即可进行测试。- **丰富的断言**&#xff1a;直接使用 Python 内置的 assert 语句&#xff0c;失败时提供详细的错误信息。- **自动发现测试**&#xff1a;通过约定的命名规…

[Python 基础课程]继承

在 Python 的面向对象编程&#xff08;OOP&#xff09;中&#xff0c;继承&#xff08;Inheritance&#xff09; 是一种重要的机制&#xff0c;它允许一个类&#xff08;称为子类或派生类&#xff09;从另一个类&#xff08;称为父类、基类或超类&#xff09;中继承属性和方法。…

QT之设计器组件功能(8大类55个组件)

组件名称 功能描述关键属性1. Layouts&#xff08;布局组件&#xff09;(1) Vertical Layout&#xff08;垂直布局&#xff09;将子控件按垂直方向依次排列layoutSpacing&#xff1a;控件之间的间距layoutMargin&#xff1a;布局边缘的边距layoutStretch&#xff1a;设置各控件…

java中list的api详细使用

在Java中&#xff0c;List是集合框架中最常用的接口之一&#xff0c;继承自Collection&#xff0c;代表有序、可重复的元素集合&#xff08;允许null元素&#xff09;。其核心实现类有ArrayList&#xff08;数组实现&#xff0c;随机访问高效&#xff09;、LinkedList&#xff…

Azure AI Search 探索总结

Azure AI Search 原名 Azure Cognitive Service&#xff0c;是Azure中用来给AI项目构建知识库的组件。知识库本质和数据库很像&#xff0c;但是内部的存储结构和检索算法不一样。比如并不是知识库的每一列都可以用来过滤、检索或group by&#xff0c;而是要根据实际情况配置。A…

高效解决 pip install 报错 SSLError: EOF occurred in violation of protocol

高效解决 pip install 报错 SSLError: EOF occurred in violation of protocol 标签&#xff1a; Python, pip, SSLError, Clash, 网络代理, 问题解决 一、问题描述 在Python开发中&#xff0c;pip 是我们最亲密的伙伴。然而&#xff0c;当你身处需要科学上网的环境&#xff0c…

CSS 核心知识点全解析:从基础到实战应用

大家好&#xff01;今天这篇文章将系统总结 CSS 的核心知识点&#xff0c;从最基础的样式引入到复杂的选择器应用&#xff0c;再到盒子模型、文本处理等实战技巧&#xff0c;全程结合代码示例&#xff0c;让你轻松掌握 CSS 的精髓。一、CSS 是什么&#xff1f;为什么需要它&…

ClickHouse的学习与了解

什么是ClickHouse&#xff1f; ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。 在传统的行式数据库系统中&#xff0c;数据按如下顺序存储&#xff1a;RowWatchIDJavaEnableTitleGoodEventEventTime#0893543506621Investor Relations12016/5/18 5:19#1903295…

安卓11 12系统修改定制化_____修改系统 解锁system分区 去除data加密 自由删减系统应用

在定制化系统中。修改系统分区 解锁system。让用户可以自由删减应用。这个在定制化服务中比较常见。对于此项修改服务。需要我们了解基础的分区常识以及常用的几种基础修改步骤。 通过博文了解💝💝💝 1💝💝💝-----修改rom 解锁 system 分区有什么意义 2💝💝…