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

这个程序是一个图的实现,使用邻接表来表示图的结构:

1. 结构定义部分:
   - `AdjListNode` 结构定义了
邻接表中的节点,每个节点包含一个名称和一个指向下一个邻接节点的指针
   - `Node` 结构定义了
图中的节点,每个节点包含一个名称和一个指向邻接表头部的指针

邻接表通常是用链表来实现的。在这个程序中,每个节点(Node)都有一个指向邻接表头部的指针(AdjListNode* head),而邻接表中的每个节点(AdjListNode)也是链表中的一个节点,通过指针连接起来。

2. 图类的方法:
   - `addNode` 方法用于向图中添加新的节点。它创建一个新的 `Node` 对象并将其添加到节点数组中。vector<Node> nodes;  // 存储图中所有节点的数组
   - `addEdge` 方法用于向图中添加边。它首先查找源节点和目标节点在数组中的索引,然后创建一个新的邻接表节点表示目标节点,并将其插入到源节点的邻接表头部。
   - `printGraph` 方法用于打印图的邻接表。它遍历节点数组,对于每个节点,遍历其邻接表并打印节点名称。

3. main函数:
   - 在 `main` 函数中,首先创建了一个 `Graph` 对象。
   - 然后通过调用 `addNode` 方法向图中添加了几个节点。
   - 接着通过调用 `addEdge` 方法向图中添加了几条边。
   - 最后调用 `printGraph` 方法打印了图的邻接表。

总体来说,这个程序展示了如何使用 C++ 实现图的基本操作,包括添加节点、添加边和打印邻接表。

vector<Node> nodes;  // 存储图中所有节点的数组
这行代码声明了一个名为 nodes 的 vector,用于存储图中所有节点的数组
在 C++ 中,vector 是一种动态数组,可以自动调整大小以容纳更多的元素。
在这个程序中,nodes 向量存储的是 Node 结构的对象,即图中的节点。
通过 vector 的特性,我们可以方便地添加、删除和访问图中的节点,而不需要手动管理数组的大小和内存。 

#include <iostream>
#include <string>
#include <vector>

using namespace std;

// 邻接表节点结构
struct AdjListNode {
    string name;         // 节点名称
    AdjListNode* next;   // 指向下一个邻接节点的指针

    // 构造函数
    AdjListNode(string name) {
        this->name = name;   // 初始化节点名称
        this->next = nullptr; // 初始化指针为空
    }
};

// 图的节点结构
struct Node {
    string name;        // 节点名称
    AdjListNode* head;  // 指向邻接表头部的指针

    // 构造函数
    Node(string name) {
        this->name = name;   // 初始化节点名称
        this->head = nullptr; // 初始化指针为空
    }
};

// 图类
class Graph {
private:
    vector<Node> nodes;  // 存储图中所有节点的数组

public:
    // 添加节点到图中
    void addNode(string nodeName) {
        nodes.push_back(Node(nodeName)); // 将新节点添加到节点数组中
    }

    // 添加边到图中
    void addEdge(string source, string dest) {
        int sourceIndex = findNodeIndex(source); // 查找源节点在数组中的索引
        int destIndex = findNodeIndex(dest);     // 查找目标节点在数组中的索引

        if (sourceIndex != -1 && destIndex != -1) { // 如果找到了源节点和目标节点
            AdjListNode* newNode = new AdjListNode(dest); // 创建一个新的邻接表节点,表示目标节点
            newNode->next = nodes[sourceIndex].head;      // 将新节点插入到源节点的邻接表头部
            nodes[sourceIndex].head = newNode;

            // 这段代码并没有处理无向图的情况,所以会有缺陷
            // 如果需要处理无向图,需要额外添加一条边,指向源节点
        }
    }

    // 打印图的邻接表
    void printGraph() {
        for (const auto& node : nodes) {                   // 遍历每个节点
            cout << node.name << " -> ";                   // 打印节点名称
            AdjListNode* current = node.head;              // 获取当前节点的邻接表头部
            while (current) {                              // 遍历邻接表
                cout << current->name;                     // 打印邻接节点的名称
                if (current->next) cout << " -> ";         // 如果存在下一个节点,打印箭头
                else cout << " -> nullptr";                // 否则打印链表末尾
                current = current->next;                   // 移动到下一个邻接节点
            }
            if (node.head == nullptr) cout << "nullptr";   // 如果当前节点没有邻接节点,则输出 nullptr
            cout << endl;                                  // 换行
        }
    }



private:
    // 查找节点在数组中的索引
    int findNodeIndex(string nodeName) {
        for (size_t i = 0; i < nodes.size(); ++i) {   // 遍历节点数组
            if (nodes[i].name == nodeName) {          // 如果找到节点名称匹配的节点
                return i;                              // 返回节点在数组中的索引
            }
        }
        return -1;                                     // 如果没找到,返回-1
    }
};

int main() {
    Graph graph;           // 创建图对象

    graph.addNode("A");    // 添加节点
    graph.addNode("B");
    graph.addNode("C");
    graph.addNode("D");
    graph.addNode("E");

    graph.addEdge("A", "B"); // 添加边
    graph.addEdge("B", "C");
    graph.addEdge("C", "A");
    graph.addEdge("C", "D");
    graph.addEdge("D", "A");

    graph.printGraph();    // 打印图的邻接表

    return 0;
}

// 该程序用于实现一个简单的图(Graph)的数据结构,图中包含多个节点,每个节点具有一个名称,并且每个节点可以与其他节点相连,以表示图中边的关系。
// 节点(Node)和邻接表(AdjListNode)
// Node:每个 Node 对象具有两个成员变量:一个字符串变量 name,用于保存节点的名称,以及一个指针变量 head,用于指向该节点的邻接表。
// AdjListNode:每个 AdjListNode 对象具有两个成员变量:一个字符串变量 name,用于保存邻接节点的名称,以及一个指针变量 next,用于指向下一个邻接节点。


// 这两行代码一起完成了将新创建的邻接表节点插入到源节点的邻接表的头部的操作。让我解释一下:
// newNode->next = nodes[sourceIndex].head;:
// 这行代码将新节点 newNode 的 next 指针指向了源节点的邻接表的头部。这样,新节点就被插入到了邻接表的头部位置。
// nodes[sourceIndex].head = newNode;:
// 接着,这行代码将源节点的邻接表的头指针指向了新节点 newNode。这样,新节点就成为了邻接表的新的头部,而原来的邻接表头部节点成为了新节点的下一个节点,从而完成了插入操作。

// 当你有一个指向对象的指针时,你可以使用 -> 运算符来访问该对象的成员,
// 而不必先解引用指针再使用 . 运算符。这在处理动态分配的对象时特别有用,因为你通常会使用指针来引用它们。

// -> 是 C++ 中用于访问对象成员的运算符,通常用于访问类的成员或者指向对象的指针的成员。
// 在这个语境中,newNode->next 是指针 newNode 所指向的对象的成员 next。
// 也就是说,newNode->next 表示访问 newNode 指向的邻接表节点的下一个节点的指针。


// -> 符号用于访问指针的成员。在这里,newNode 是指向 AdjListNode 对象的指针,我们想访问它的 next 成员。
// -> 符号与 .(->) 等价,但它是一种简写方式来访问指针的成员。
// 因此,newNode->next 等价于 (newNode)->next。它说的是“从 newNode 指向的对象中找出 next 成员”

A -> B -> nullptr
B -> C -> nullptr
C -> D -> A -> nullptr
D -> A -> nullptr
E -> nullptr
请按任意键继续. . .

// 该程序用于实现一个简单的图(Graph)的数据结构,图中包含多个节点,每个节点具有一个名称,并且每个节点可以与其他节点相连,以表示图中边的关系
// 节点(Node)和邻接表(AdjListNode)
// Node:每个 Node 对象具有两个成员变量:一个字符串变量 name,用于保存节点的名称,以及一个指针变量 head,用于指向该节点的邻接表。
// AdjListNode:每个 AdjListNode 对象具有两个成员变量:一个字符串变量 name,用于保存邻接节点的名称,以及一个指针变量 next,用于指向下一个邻接节点。


// 这两行代码一起完成了将新创建的邻接表节点插入到源节点的邻接表的头部的操作:
// newNode->next = nodes[sourceIndex].head;:
// 这行代码将新节点 newNode 的 next 指针指向了源节点的邻接表的头部。这样,新节点就被插入到了邻接表的头部位置。
// nodes[sourceIndex].head = newNode;:
// 接着,这行代码将源节点的邻接表的头指针指向了新节点 newNode。这样,新节点就成为了邻接表的新的头部,而原来的邻接表头部节点成为了新节点的下一个节点,从而完成了插入操作。

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

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

相关文章

C++类定义时成员变量初始化

在C11中允许在类定义时对成员变量初始化。 class A { public:A() { }void show(){cout << "m_a " << m_a << endl;cout << "m_b " << m_b << endl;} private:int m_a 10;//类定义时初始化int m_b; //没有初始化…

CP,FT,WAT有什么区别?

‍ 知 识星球&#xff08;星球名&#xff1a; 芯片制造与封测社区&#xff0c;星球号&#xff1a; 63559049&#xff09;里的学员问&#xff1a; CP,FT,WAT都是与 芯片的测试有关&#xff0c;他们有什么区别呢&#xff1f; 如何区‍分&#xff1f; ‍ ‍ CP,FT,WAT分别…

MySQL LRU算法(冷热数据分离)

背景 MySQL中使用的InnoDB存储引擎采用了一种特别的最近最少使用&#xff08;LRU, Least Recently Used&#xff09;算法来管理其Buffer Pool中的页&#xff08;包括数据页和索引页&#xff09;。Buffer Pool是InnoDB用来缓存数据&#xff0c;以减少磁盘I/O操作的内存区域。正…

python数据分析中数据可视化简单入门

1.折线图表 首先引入相关包pyecharts&#xff0c;如果没下载可以先下载 pip install pyecharts from pyecharts.charts import Lineline Line() # 添加x轴 line.add_xaxis([呱了个呱,羊村,牟多,蜂地,喵帕斯]) # 添加y轴 line.add_yaxis("GDP",[50,30,40,34,63,22])…

Jrebel 最新的 2023.4 、 2024.1 激活方法

Idea Jrebel 插件安装 在线激活 &#xff08;推荐&#xff09; 访问&#xff1a; https://www.jpy.wang/page/jrebel.html 在jrebel激活的时候填写相应的地址

逻辑漏洞:修改Response状态值导致的逻辑漏洞

目录 1、什么是respone状态值&#xff1f; 2、利用原理 3、PHPYUN人才招聘系统靶场演示 今天还是继续学习逻辑漏洞相关的知识&#xff0c;今天的主题是“修改Response状态值导致的逻辑漏洞”&#xff0c;今天的内容还是参考别的大佬总结好的&#xff0c;我只是在这里进行学习…

Linux系统配置JAVA环境

一、jar包下载 官网:https://www.oracle.com/java/technologies/downloads 二、文件上传 上传到linux服务器 解压 下面是解压的路径 三、修改profile文件 修改etc下的profile文件&#xff0c;添加以下内容 vim /etc/profileexport JAVA_HOME/root/java/jdk-17.0.11 expo…

ttkbootstrap界面美化系列之Meter(六)

Meter是计量表控件&#xff0c;在大数据统计类的界面设计中使用较多&#xff0c;本文将介绍ttk中的Meter控件 一&#xff1a;Meter接口 print(help(ttk.Meter)) Help on class Meter in module ttkbootstrap.widgets:class Meter(tkinter.ttk.Frame)| Meter(masterNone, bo…

半监督节点分类:标签传播和消息传递

基础概念回顾 传统图机器学习的特征工程——节点层面&#xff0c;连接层面&#xff0c;全图层面 节点层面&#xff1a;信用卡欺诈 连接层面&#xff1a;推荐可能认识的人 全图层面&#xff1a;预测分子结构 半监督节点分类 半监督节点分类&#xff1a;用已知标签节点预测未…

推荐书单|提升境界、思维能力

1、《别做正常的傻瓜》 豆瓣评分&#xff1a;8.1 通过揭示人们在日常生活中常见的非理性行为&#xff0c;引导读者认识并克服这些行为&#xff0c;从而做出更明智的决策。 2、《活法》 豆瓣评分&#xff1a;8.1 稻盛和夫分享其人生哲学和经营哲学的著作&#xff0c;强调了正确…

【MATLAB】解决不同版本MATLAB出现中文乱码的问题

解决不同版本MATLAB出现中文乱码的问题 方法1&#xff1a;更改保存类型为GBK方法2&#xff1a;记事本打开方法3&#xff1a;Notepad参考 低版本matlab打开高版本Matlab的.m文件时&#xff0c;出现中文乱码问题。比如下图&#xff1a; 出现原因为&#xff1a; 编码格式不统一问…

深度学习之基于Unet肺部CT图像分割项目

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 肺部CT图像分割在医学诊断中占据重要地位&#xff0c;它有助于医生快速、准确地识别和分析肺部病变。…

关于 Vue.js 双向数据绑定基本实现认知

写在前面 很早的一篇博客&#xff0c;整理了部分&#xff0c;蹭假期整理完博文内容涉及:双向数据绑定 实现方式简单介绍基于发布订阅、数据劫持的双向数据绑定两种不同实现(ES5/ES6) Demo&#xff0c;以及代码简单分析Object.defineProperty && Proxy API 介绍以及特性…

如何配置X86应用程序启用大地址模式(将用户态虚拟内存从2GB扩充到3GB),以解决用户态虚拟内存不够用问题?(项目实战案例解析)

目录 1、概述 2、为什么不直接将程序做成64位的&#xff1f; 3、进程内存不足导致程序发生闪退的案例分析 3.1、问题说明 3.2、将Windbg附加到程序进程上进行动态调试 3.3、动态调试的Windbg感知到了中断&#xff0c;中断在DebugBreak函数调用上 3.4、malloc或new失败的…

企业微信主体能不能修改?

企业微信变更主体有什么作用&#xff1f;当我们的企业因为各种原因需要注销或已经注销&#xff0c;或者运营变更等情况&#xff0c;企业微信无法继续使用原主体继续使用时&#xff0c;可以申请企业主体变更&#xff0c;变更为新的主体。企业微信变更主体的条件有哪些&#xff1…

Java 三大特性之继承

目录 一、为什么需要继承&#xff1f; 二、继承概念 三、继承的语法 四、子类访问父类成员 五、super关键字 六、继承关系下的构造方法 七、继承关系下的初始化 八、protected关键字 九、继承的三种方式 十、final关键字 十一、继承和组合 一、为什么需要继承&#…

五一玩狗“丧志”记

我天生喜欢狗狗。五一来到媳妇老家这几天&#xff0c;只要有机会我都要给一个只叫“瘦瘦”的狗狗多攒一些吃的。 它是一条看家狗&#xff0c;有大人膝盖那么高八十厘米那么长。通体毛色以黄黑为主&#xff0c;少许白色主要集中在爪子和下巴。两耳直挺挺尖尖的竖立着&#xff0c…

mac通过termius连接Linux服务器

mac上安装 linux系统 如果有 linux服务器账号密码&#xff0c;那么上一步可忽略&#xff1b; 比如&#xff1a;直接连接阿里云或腾讯云账号 1. 安装termius 链接: https://pan.baidu.com/s/1iYsZPZThPizxqtkLPT89-Q?pwdbw6j 提取码: bw6j 官网 Termius - SSH platform for …

CNN实现fashion_mnist数据集分类(tensorflow)

1、查看tensorflow版本 import tensorflow as tfprint(Tensorflow Version:{}.format(tf.__version__)) print(tf.config.list_physical_devices())2、加载fashion_mnist数据与预处理 import numpy as np (train_images,train_labels),(test_images,test_labels) tf.keras.d…

[数据结构]————排序总结——插入排序(直接排序和希尔排序)—选择排序(选择排序和堆排序)-交换排序(冒泡排序和快速排序)—归并排序(归并排序)

文章涉及具体代码gitee&#xff1a; 登录 - Gitee.com 目录 1.插入排序 1.直接插入排序 总结 2.希尔排序 总结 2.选择排序 1.选择排序 ​编辑 总结 2.堆排序 总结 3.交换排序 1.冒泡排序 总结 2.快速排序 总结 4.归并排序 总结 5.总的分析总结 1.插入排…