C++处理图存储的方式分享

C++处理图存储的方式分享

在C++中处理图的存储方式有多种,这里主要讲解三种最常见和实用的方式:邻接矩阵邻接表关联数组

邻接矩阵

邻接矩阵是图最简单、使用最广泛的存储方式之一,它使用一个二维矩阵表示节点之间的关系。当图中有 n 个节点时,可以用一个 n x n 的矩阵来存储它们之间的关系,矩阵中的每个元素存储两个节点之间的边的信息,如边的权重。

以下是一个用邻接矩阵存储的无向有权图的代码示例:

const int MAXN = 1000;   // 最多节点数
int Graph[MAXN][MAXN];   // 邻接矩阵,可存储节点间权重信息
int n;                   // 图中节点总数

int main(){
    // 初始化图
    memset(Graph, 0, sizeof(Graph)); // 图的全部初始化为零,即无边
    // 显示节点i和节点j之间的权重
    printf("%d\n", Graph[i][j]);
    return 0;
}

邻接表

邻接表用链表方式存储图,对于一个有 n 个节点和 m 条边的图,可以使用一个大小为 n 的数组,每个数组元素存储与其相连的所有节点。相比邻接矩阵,邻接表能够更有效地存储稀疏图。

以下是一个用邻接表存储的有向无权图的代码示例:

const int MAXN = 1000;       // 最多节点数
vector<int> Graph[MAXN];     // 邻接表,存储节点的后继
bool visited[MAXN];          // 图结点是否已经遍历
int n;                       // 图中节点总数

void dfs(int curr_node){     // dfs搜索当前节点
    visited[curr_node] = true;
    for(int i=0; i<Graph[curr_node].size(); i++){
        if(!visited[Graph[curr_node][i]]){
            dfs(Graph[curr_node][i]);
        }
    }
}

int main(){
    // 初始化图中每个节点的后继为空
    for(int i=0; i<=n; i++){
        Graph[i].clear(); 
    }
    // 访问节点i的所有后继
    for(int i=0; i<Graph[i].size(); i++){
        int next_node = Graph[i][j];
        // do something...
    }
    return 0;
}

关联数组

关联数组是一种特殊的数组,使用键-值对存储数据。对于图来说,关联数组可以用来实现一个稀疏的邻接矩阵。可以使用 C++ STL 提供的 map 来实现关联数组。

以下是用 map 存储的有向有权图的代码示例:

const int maxn = 1000;      // 最多节点数
map<int, map<int, int> > Graph;   // 关联数组,存储课件之间的权重
int n;                      // 图中节点总数

int main(){
    // 初始化图中每对节点之间的权重(无穷大)
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            Graph[i][j] = INF;    // 无穷大表示不可达
        }
    }
    // 显示节点i和节点j之间的权重
    printf("%d\n", Graph[i][j]);
    return 0;
}

示例说明:

接下来,我们通过一些示例来说明如何使用上述三种方法来处理图。

邻接矩阵

假设我们有一个无向有权图,有 n 个节点,现在想要找到任意两点之间的路径长度。假设图的邻接矩阵为 Graph[][],以下为代码实现:

for(int i=1; i<=n; i++){
    for(int j=i+1; j<=n; j++){
        printf("path between node %d and %d is: ", i, j);
        if(!Graph[i][j]){
            printf("no path\n");
        }else{
            printf("%d\n", Graph[i][j]);
        }
    }
}

以上代码中,使用两重循环对每个节点对进行遍历,当发现节点对 (i, j) 之间没有路径时,即输出 "no path",否则输出节点对之间的路径长度。

邻接表

现在我们有一个有向无权图,想找到从某个节点开始到另一个节点的所有路径。假设图的邻接表为 Graph[],以下为代码实现:

void dfs(int curr_node, int dest_node, vector<int>& path){
    path.push_back(curr_node);
    if(curr_node == dest_node){
        // 当前为目标节点,则输出路径
        for(int i=0; i<path.size(); i++){
            printf("%d ", path[i]);
        }
        printf("\n");
    }else{
        // 否则继续遍历
        for(int i=0; i<Graph[curr_node].size(); i++){
            dfs(Graph[curr_node][i], dest_node, path);
        }
    }
    path.pop_back();    // 回溯
}

int main(){
    vector<int> path;
    dfs(1, 5, path); // 找从节点1到节点5的所有路径
    return 0;
}

以上代码中,使用深度优先搜索算法递归遍历节点,同时使用一个记录路径的向量 path 来保存路径。当遍历到终点时,输出所有保存在 path 中的节点,从而找到所有路径。

关联数组

现在我们有一个有向有权图,要找到从某个节点开始到其他所有节点的最短路径。假设图的关联数组为 Graph,以下为代码实现:

const int INF = 1e9;  // 假设无穷大为1e9

void Dijkstra(int S){
    priority_queue< pair<int, int>, vector< pair<int, int> >, greater< pair<int, int> > > Q; // 最小堆
    vector<int> dis(n+1, INF);    // 到每个点的距离
    vector<int> pre(n+1, 0);      // 记录到最短路径上每个节点的前一个节点
    dis[S] = 0;
    Q.push(make_pair(0, S));
    while(!Q.empty()){
        int u = Q.top().second; Q.pop();
        for(map<int, int>::iterator iter = Graph[u].begin(); iter != Graph[u].end(); iter++){
            int v = iter->first;
            int w = iter->second;
            if(dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                pre[v] = u;
                Q.push(make_pair(dis[v], v));
            }
        }
    }
}

int main(){
    Dijkstra(1);   // 找节点1到其他所有节点的最短路径
    return 0;
}

以上代码中,使用 Dijkstra 算法遍历以起点 S 开始到所有节点的最短路径,同时记录每个节点的前驱节点。当遍历完成后,输出所有节点到起点的最短路径长度,并输出最短路径的具体路径。

注意,以上的关联数组实现方式使用 STL 的 map 类型,但是在实际使用中,我们可以使用 C++11 的 unordered_map 容器替代 map,以提高代码效率。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++处理图存储的方式分享 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C++运行时获取类型信息的type_info类与bad_typeid异常

    C++编程语言是一门静态类型语言,因此在编译期就会确定对象的类型。但有时候在运行期需要动态地获取对象的类型信息,这时就可以使用type_info类。Type_info类是C++标准库中的一个类,它能提供关于类型的信息。当程序尝试动态地获取一个对象的类型信息,但该对象的类型没有type_info信息时,就会抛出bad_typeid异常。 下面是使用type_i…

    C 2023年5月23日
    00
  • B/S与C/S架构的区别介绍

    B/S与C/S架构的区别介绍 概念阐述 B/S (Browser/Server) 是指基于浏览器/服务器结构构建的软件系统。C/S (Client/Server) 是指基于客户端/服务器结构构建的软件系统。B/S架构下,用户通过浏览器访问网站,浏览器向服务器发出请求,服务器对请求做出响应,返回 HTML、JavaScript、CSS 等格式的网页,并通过这些…

    C 2023年5月23日
    00
  • 详解QListWidget如何实现自定义Item效果

    下面是详细讲解“详解QListWidget如何实现自定义Item效果”的完整攻略。 1. QListWidget简介 QListWidget是QT中常用的一个列表控件,它能够方便地显示列表数据,并且还支持很多常用的操作,比如单选、多选、拖拽等。在QListWidget中,默认的Item是由QListWidgetItem类提供的,它能够显示一些基本的文本、图标…

    C 2023年5月23日
    00
  • C++如何过滤出字符串的中文(GBK、UTF-8)

    下面是完整的攻略: 1. 判断字符串编码格式 在过滤字符串中的中文之前,我们需要先判断字符串的编码格式。因为GBK和UTF-8编码下的中文字符的字节长度是不同的。 1.1 GBK编码格式 在GBK编码下,每个中文字符由2个字节组成。所以我们可以通过判断每个字符的字节长度是否为2来判断字符串的编码格式是GBK。 bool isGBK(const char* s…

    C 2023年5月23日
    00
  • VSCode配置C语言环境的方法

    请看下面的具体攻略。 VSCode配置C语言环境的方法 VSCode是一款轻量级的代码编辑器,但同时也具有很强的扩展性,在开发C语言代码时,通过VSCode配置C语言环境,可以提升开发效率。下面就介绍一下如何进行配置。 步骤1: 安装C语言扩展插件 在VSCode中安装C语言的扩展插件,这里推荐使用”ms-vscode.cpptools”。 打开VSCode…

    C 2023年5月23日
    00
  • C enum(枚举)

    下面详细讲解一下C语言中枚举(enum)的完整使用攻略。 枚举的定义 C语言中的枚举是一种用户自定义的数据类型,它允许我们定义一组命名的常量。枚举常量被称为枚举值(enum value)。 在C语言中枚举的定义格式为: enum 枚举类型名{ 枚举值1, 枚举值2, …… 枚举值n }; 其中,枚举类型名是一个标识符,它是这个枚举类型的名称;枚举值是一组常量…

    C 2023年5月10日
    00
  • 解析C++ 浮点数的格式化输出

    解析C++浮点数的格式化输出主要有三个方面的内容: 格式化字符串的控制符 浮点数输出的精度控制 浮点数的取值范围 下面我就分别给出详细的讲解。 1. 格式化字符串的控制符 C++中常用的输出控制符有以下几种: 控制符 功能 %d 以十进制整数形式输出 %c 以字符形式输出 %s 以字符串形式输出 %f 以浮点数形式输出 %o 以八进制整数形式输出 %x 以十…

    C 2023年5月23日
    00
  • php7 错误处理机制修改实例分析

    PHP7 错误处理机制修改实例分析 一、背景 在PHP7中,错误处理机制发生了一些变化。具体来说,PHP7增加了Throwable接口和Error类,用于代替旧版的Exception类。此外,PHP7还引入了一种新的错误处理器:Throwable处理器。Throwable处理器是一种标准的PHP异常处理方式,可以通过使用try-catch语句来捕获和处理所有…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部