C++_有向图_使用邻接表(链表-智能指针shared_ptr)实现

// 在C++中,实现有向图的一种常见方式是使用邻接表
// 邻接表的核心思想是,对于图中的每个节点,使用一个"链表"来存储它的邻接节点。每个链表中的节点表示从当前节点出发的边的终点。
// 下面是一个简单的实现示例,其中包含以下组件:
// Graph: 表示整个有向图。
// Node: 表示一个节点及其连接的邻接表。
// AdjNode: 表示邻接表中的一个节点。

// 在这个代码示例中,Graph类表示一个有向图。它使用了邻接表来存储每个节点的邻接边。
// 每个节点的邻接表是一个链表,使用 std::shared_ptr 来确保动态分配的内存得到妥善管理。 
// addEdge 方法用于向图中添加有向边,
// printGraph 方法用于打印整个图的结构。


// 这段代码涉及到有向图中使用邻接表实现添加边的操作。
// 我们来逐句解释代码的功能:
// auto newNode = std::make_shared<AdjNode>(destination);:
// 这行代码使用std::make_shared创建一个新的AdjNode(邻接节点)对象。AdjNode的构造函数被调用,并传入了目标节点(destination)作为参数。
// std::make_shared返回一个智能指针(std::shared_ptr),指向新创建的AdjNode对象。这种智能指针负责自动管理内存,确保对象在不再需要时正确释放。

// newNode->next = nodes[source].head;:
// 这行代码将新创建的邻接节点的next指针指向源节点的当前邻接表头部
// 这样做的目的是将新创建的节点插入到邻接表的头部,即成为链表中的第一个节点。原有的链表头部节点成为新创建节点的下一个节点。

// nodes[source].head = newNode;:
// 这行代码将源节点的邻接表头部更新为新创建的邻接节点。
// 这样做的目的是将新创建的节点设为链表的头节点,从而确保新节点成为邻接表中的第一个节点。这一行与前一行代码共同实现了将新节点插入邻接表头部的操作。

// 综上所述,这段代码实现了向图的源节点的邻接表中添加一个新的邻接节点,并将其插入到邻接表的头部位置。这是向有向图中添加边的基本操作之一。

#include <iostream>
#include <vector>
#include <memory>

// 表示邻接表中的一个节点
struct AdjNode {
    int dest; // 目的节点
    std::shared_ptr<AdjNode> next; // 指向下一个邻接节点的指针

    AdjNode(int d) : dest(d), next(nullptr) {}
};

// 表示图中的一个节点
struct Node {
    std::shared_ptr<AdjNode> head; // 指向邻接表头部的指针

    Node() : head(nullptr) {}
};

// 表示整个有向图
class Graph {
public:
    // 初始化图,给定节点数
    Graph(int n) : numVertices(n), nodes(n) {}

    // 添加有向边,从源节点到目标节点
    void addEdge(int source, int destination) {
        auto newNode = std::make_shared<AdjNode>(destination);
        newNode->next = nodes[source].head;
        nodes[source].head = newNode;
    }

    // 打印整个图
    void printGraph() {
        for (int i = 0; i < numVertices; ++i) {
            std::cout << "Node " << i << ":";
            auto current = nodes[i].head;
            while (current) {
                std::cout << " -> " << current->dest;
                current = current->next;
            }
            std::cout << std::endl;
        }
    }

private:
    int numVertices; // 图中节点数
    std::vector<Node> nodes; // 存储所有节点
};

int main() {
    Graph g(5); // 创建一个有5个节点的图

    // 添加一些有向边
    g.addEdge(0, 1);
    g.addEdge(0, 4);
    g.addEdge(1, 2);
    g.addEdge(1, 3);
    g.addEdge(1, 4);
    g.addEdge(3, 4);

    // 打印整个图
    g.printGraph();

    return 0;
}

// 在C++中,实现有向图的一种常见方式是使用邻接表。
// 邻接表的核心思想是,对于图中的每个节点,使用一个"链表"来存储它的邻接节点。每个链表中的节点表示从当前节点出发的边的终点。
// 下面是一个简单的实现示例,其中包含以下组件:
// Graph: 表示整个有向图。
// Node: 表示一个节点及其连接的邻接表。
// AdjNode: 表示邻接表中的一个节点。

// 在这个代码示例中,Graph类表示一个有向图。它使用了邻接表来存储每个节点的邻接边。
// 每个节点的邻接表是一个链表,使用 std::shared_ptr 来确保动态分配的内存得到妥善管理。 
// addEdge 方法用于向图中添加有向边,
// printGraph 方法用于打印整个图的结构。


// 这段代码涉及到有向图中使用邻接表实现添加边的操作。
// 我们来逐句解释代码的功能:
// auto newNode = std::make_shared<AdjNode>(destination);:
// 这行代码使用std::make_shared创建一个新的AdjNode(邻接节点)对象。AdjNode的构造函数被调用,并传入了目标节点(destination)作为参数。
// std::make_shared返回一个智能指针(std::shared_ptr),指向新创建的AdjNode对象。这种智能指针负责自动管理内存,确保对象在不再需要时正确释放。

// newNode->next = nodes[source].head;:
// 这行代码将新创建的邻接节点的next指针指向源节点的当前邻接表头部。
// 这样做的目的是将新创建的节点插入到邻接表的头部,即成为链表中的第一个节点。原有的链表头部节点成为新创建节点的下一个节点。

// nodes[source].head = newNode;:
// 这行代码将源节点的邻接表头部更新为新创建的邻接节点。
// 这样做的目的是将新创建的节点设为链表的头节点,从而确保新节点成为邻接表中的第一个节点。这一行与前一行代码共同实现了将新节点插入邻接表头部的操作。

// 综上所述,这段代码实现了向图的源节点的邻接表中添加一个新的邻接节点,并将其插入到邻接表的头部位置。这是向有向图中添加边的基本操作之一。

 --

智能指针 shared_ptr 是 C++ 标准库提供的一种智能指针类型,用于管理动态分配的资源,特别是在动态内存分配和释放方面非常有用。它可以确保在没有引用时释放资源,避免内存泄漏,并能够安全地共享资源的所有权。

std::shared_ptr 是 C++11 引入的智能指针类型之一,旨在提供一种自动化的内存管理方式。与原生指针相比,它具有自动管理内存的优势,可以避免内存泄漏和重复释放等问题。


下面是 shared_ptr 的一些关键特点:
1. 自动内存管理: shared_ptr 可以自动管理动态分配的内存资源的生命周期。当没有指向资源的 shared_ptr 时,资源会被自动释放,无需手动调用 delete
2. 引用计数: shared_ptr 通过引用计数来跟踪资源的使用情况。每当创建一个指向资源的 shared_ptr,计数器就会增加;当 shared_ptr 被销毁时,计数器减少。当计数器为零时,资源会被释放。
3. 多个指针共享资源: 多个 shared_ptr 可以指向同一块内存资源,它们共享对资源的访问和所有权。这使得在程序中传递和共享资源变得更加简单和安全。
4. 线程安全: shared_ptr 的引用计数是线程安全的,因此可以在多线程环境中安全地使用。
5. 循环引用解决方案: shared_ptr 能够检测并解决循环引用的问题,当存在循环引用时,通过使用 weak_ptr 来打破循环引用,防止内存泄漏。
总之,智能指针 shared_ptr 提供了一种方便而安全的方式来管理动态分配的资源,它是现代 C++ 编程中的重要工具之一。

#include <iostream>
#include <memory> // 引入 shared_ptr 头文件

int main() {
    // 创建一个 shared_ptr 指向一个新的 int 对象,并初始化值为 42
    std::shared_ptr<int> ptr1 = std::make_shared<int>(42);

    // 打印共享指针指向的值
    std::cout << "Value: " << *ptr1 << std::endl;

    // 打印当前引用计数(应该是 1,因为只有 ptr1 引用该对象)
    std::cout << "Reference count: " << ptr1.use_count() << std::endl;

    {
        // 在一个新的作用域中创建另一个 shared_ptr
        std::shared_ptr<int> ptr2 = ptr1; // ptr2 和 ptr1 共享同一个 int 对象

        // 打印新的引用计数(应该是 2,因为 ptr1 和 ptr2 都引用同一个对象)
        std::cout << "Reference count: " << ptr1.use_count() << std::endl;

        // ptr2 离开作用域时,会自动释放对对象的引用,但对象不会被销毁,因为 ptr1 仍然持有该对象
    }

    // 在作用域结束后,打印引用计数(应该是 1,因为 ptr2 已被销毁)
    std::cout << "Reference count after scope: " << ptr1.use_count() << std::endl;

    // 当 ptr1 离开作用域时,内存将自动释放
    return 0;
}

在这个例子中:

  • 我们首先创建了一个 shared_ptr,并使用 std::make_shared 创建了一个新的整数对象并初始化值为 42。

  • 然后我们打印了当前 shared_ptr 的引用计数和指向的值。

  • 接着,我们在一个新的作用域中创建了另一个 shared_ptr 指向相同的整数对象。此时,引用计数变为 2,因为有两个指针引用同一个对象。

  • 当作用域结束后,ptr2 离开作用域,被销毁,引用计数又变回 1。

  • 最后,当 ptr1 也离开作用域时,整数对象将被销毁,因为没有其他指针引用它。

这个例子展示了 std::shared_ptr 的基本用法以及它如何自动管理内存。

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

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

相关文章

flutter开发实战-GetX响应式状态管理使用

flutter开发实战-GetX响应式状态管理使用 GetX是一个简单的响应式状态管理解决方案。GetX是Flutter的一款超轻、功能强大的解决方案。它将高性能状态管理、智能依赖注入和路由管理快速而实用地结合在一起。这里简单使用一下GetX 一、引入GetX 在工程的pubspec.yaml中引入插件…

Python中的分布式爬虫系统Scrapy与分布式任务队列的结合

随着互联网的不断发展&#xff0c;网络爬虫在数据采集和信息挖掘中发挥着重要作用。然而&#xff0c;单机爬虫往往难以应对大规模数据抓取的需求&#xff0c;因此&#xff0c;构建分布式爬虫系统成为了一种必然选择。本文将介绍如何利用 Python 中的 Scrapy 框架和分布式任务队…

TikTok自动评论、回复的脚本怎么制作?

在当今数字化的时代&#xff0c;社交媒体平台如TikTok已经成为人们日常生活的一部分&#xff0c;为了更有效地在TikTok上进行营销或互动&#xff0c;许多用户和企业开始寻找自动化工具&#xff0c;如自动评论和回复的脚本&#xff0c;以节省时间并提高效率。 本文将科普如何制…

H5 处理点击元素高亮、自定义按钮、去除焦点边框

1、设置移动设备上点击元素时出现的高亮颜色 *{-webkit-tap-highlight-color: transparent; }2、如果你想要自定义按钮的样式&#xff0c;你可以使用 -webkit-appearance: none; 来移除按钮的默认样式 .button {-webkit-appearance: none;appearance: none; /* 兼容性更好的通…

C语言 | Leetcode C语言题解之第72题编辑距离

题目&#xff1a; 题解&#xff1a; static inline int Min(const int a, const int b, const int c) {int min (a < b) ? a : b;return (min < c) ? min : c; }int minDistance(char * word1, char * word2){int m strlen(word1), n strlen(word2);int dp[m 1][n…

知识蒸馏,需要合适的教师模型,学生模型,蒸馏数据,损失函数,训练策略,让小模型有大模型的知识

知识蒸馏使用的是Teacher—Student模型&#xff0c;其中teacher是“知识”的输出者&#xff0c;student是“知识”的接受者。知识蒸馏的过程分为2个阶段: 原始模型训练: 训练"Teacher模型", 它的特点是模型相对复杂&#xff0c;也可以由多个分别训练的模型集成而成。…

C++_红黑树的学习

1. 红黑树的概念 红黑树 &#xff0c;是一种 二叉搜索树 &#xff0c;但 在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是 Red 或 Black 。 通过对 任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路 径会比其他路径长出俩倍 &…

【活动】如何通过AI技术提升内容生产的效率与质量

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 如何通过AI技术提升内容生产的效率与质量引言一、自然语言处理&#xff08;NLP&…

JAVA排序相关习题7

1.插入排序 1.1 基本思想 直接插入排序是一种简单的插入排序法&#xff0c;其基本思想是&#xff1a; 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到一个新的有序序列 。 /*** 时间复杂度&…

自然资源-地质勘查工作的流程梳理

自然资源-地质勘查工作的流程梳理 地质勘查从广义上可理解为地质工作&#xff0c;地质队员就好像是国家宝藏的“寻宝人”&#xff0c;通过地质勘查&#xff0c;为国家找矿&#xff0c;以保障国家能源资源安全和服务国计民生&#xff0c;发挥着地质工作在国民经济建设中的基础性…

跟TED演讲学英文:Teachers need real feedback by Bill Gates

Teachers need real feedback Link: https://www.ted.com/talks/bill_gates_teachers_need_real_feedback Speaker: Bill Gates Date: May 2013 文章目录 Teachers need real feedbackIntroductionVocabularyTranscriptSummary后记 Introduction Until recently, many teach…

电子版图书制作,一键转换可仿真翻页的画册

在数字化浪潮的冲击下&#xff0c;传统纸质图书逐渐被电子版图书取而代之。电子版图书以其便携、环保、更新快速等特点&#xff0c;吸引了越来越多的读者。制作一款既具备电子图书的便捷性&#xff0c;又能仿真翻页的画册&#xff0c;成为当下图书出版行业的新趋势 1.要制作电子…

企业数据保护,从严防内部信息泄露开始

在当今的数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。然而&#xff0c;随之而来的是数据安全威胁&#xff0c;尤其是内部信息泄露&#xff0c;这不仅会导致企业面临巨大的经济损失&#xff0c;还可能损害企业的品牌形象和客户信任。因此&#xff0c;从严防内部信息…

56 关于 linux 的 oom killer 机制

前言 这里主要讲的是 linux 的 oom killer 机制 在系统可用内存较少的情况下&#xff0c;内核为保证系统还能够继续运行下去&#xff0c;会选择杀掉一些进程释放掉一些内存。 通常oom_killer的触发流程是&#xff1a;进程A想要分配物理内存&#xff08;通常是读写内存&#…

新能源汽车中HEV与PHEV分别代表什么车型,它们与传统燃油车都有什么区别?

前言 新能源汽车正逐渐成为全球汽车工业的主流方向&#xff0c;而HEV&#xff08;Hybrid Electric Vehicle&#xff09;和PHEV&#xff08;Plug-in Hybrid Electric Vehicle&#xff09;这两种混合动力车型在这一转型过程中扮演着重要角色。下面我们详细探讨HEV与PHEV的定义&a…

基于FPGA的视频矩阵 视频拼接 无缝切换解决方案

视频矩阵 视频矩阵 视频拼接 无缝切换 1. 最大支持144路HDMI视频输入&#xff0c;最大支持144路路HDMI输出&#xff0c;完全交叉切换。 2. 与包括1080p/60的所有HDTV分辨率和高达1920*1200的PC的分辨率兼容&#xff1b; 3. 支持HDMI 1.3a、HDCP 1.3、HDCP 1.4、以及DVI 1.0协…

如何使用visual vm和jstat进行远程监控

如何使用visual vm和jstat进行监控 安装visual vm 好像从jdk某个版本开始&#xff0c;jdk的bin目录下就不自带jvisualvm了&#xff0c;需要从官网下载一个visual vm。 打开visual vm Local是你本地的&#xff0c;无需多言。 先准备下必备的插件 如何通过visual vm观测远程…

Prometheus监控Kubernetes Pod状态

本文将介绍如何配置Prometheus的告警规则&#xff0c;实现对于Kubernetes Pod状态的监控。 1.Pod的状态类型 在Prometheus 监控Kubernetes Pod 状态时&#xff0c;通常可以观察到以下几种状态情况&#xff1a; 1. Running&#xff08;运行中&#xff09; Pod 处于运行状态意…

Spring Framework-IoC详解

IoC的概念和作用 在介绍Ioc之前&#xff0c;我们首先先了解一下以下内容 什么是程序的耦合 耦合性(Coupling)&#xff0c;也叫耦合度&#xff0c;是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度…

Java毕业设计 基于SpringBoot vue新能源充电系统

Java毕业设计 基于SpringBoot vue新能源充电系统 SpringBoot 新能源充电系统 功能介绍 首页 图片轮播 充电桩 充电桩类型 充电桩详情 充电桩预约 新能源公告 公告详情 登录注册 个人中心 余额充值 修改密码 充电桩报修 充电桩预约订单 客服 后台管理 登录 个人中心 修改密码…
最新文章