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日

相关文章

  • Turbo C 2.0集成环境的使用教程

    Turbo C 2.0集成环境的使用教程 Turbo C 2.0是一个古老的C语言编程环境,由Borland公司开发。虽然它已经停止支持并淘汰多年,但是它仍然是一些编程者心中的经典。本教程将带您了解Turbo C 2.0的基本用法和一些代码示例。 安装Turbo C 2.0 首先我们需要安装Turbo C 2.0,您可以从网上下载Turbo C 2.0的安装…

    C 2023年5月23日
    00
  • C++中的类成员函数当线程函数

    C++中的线程库(std::thread)可以处理各种类型的函数作为线程函数,包括类的成员函数。对于类成员函数,我们需要考虑如何处理this指针,并注意线程的生命周期。 以下是将类成员函数作为线程函数的完整攻略: 步骤1:定义类 首先,需要定义一个含有成员函数的类。本例中,我们定义了一个简单的Counter类,它具有公共函数increment(),用于增加计…

    C 2023年5月22日
    00
  • c/c++获取系统时间函数的方法示例

    获取系统时间是编程中常用的功能之一,c/c++提供了多种方法来获取系统时间。下面将介绍获取系统时间的常用方法。 获取系统时间的常用函数 1. time() time()函数返回从1970年1月1日0时0分0秒到当前时间的秒数。time函数的详细定义如下: #include <time.h> time_t time(time_t *timer); …

    C 2023年5月30日
    00
  • Linux系统下C语言gets函数出现警告问题的解决方法

    以下是详细讲解 “Linux系统下C语言gets函数出现警告问题的解决方法”的完整攻略。 1. gets函数警告问题 在 Linux 系统下使用 C 语言进行编程时,我们有时会使用 gets 函数,但是这种函数在读取字符串时很容易造成缓冲区溢出,导致程序崩溃。因此,编译器会提示警告信息,防止程序出错。 下面是使用 gets 函数的示例代码: #include…

    C 2023年5月30日
    00
  • 浅谈c++ hook 钩子的使用介绍

    浅谈C++ Hook 钩子的使用介绍 1. 什么是Hook钩子? Hook钩子是一种可以监控和修改系统、进程或应用程序行为的技术。在Windows操作系统下,可以通过Hook技术对API函数进行钩取,实现拦截API调用并进行自定义的处理。 2. Hook钩子的类型 在Windows操作系统中,可以使用以下两种类型的Hook钩子: 2.1 系统级钩子 系统级钩…

    C 2023年5月30日
    00
  • C++11中的变长模板的示例详解

    让我来详细讲解“C++11中的变长模板的示例详解”的完整攻略: 什么是变长模板 在C++标准库中,存在一个叫做std::tuple的工具类,可以用于表示可以持有任意个元素的集合。其中元素的类型可以不相同。这里的“任意个元素”就是指可以持有任意个类型参数。这种由C++模板机制提供的自由组合类型的能力,就是变长模板。 变长模板的语法 变长模板的语法非常简单,就是…

    C 2023年5月23日
    00
  • 如何在C++中建立一个顺序表

    建立顺序表的过程可以分为以下几个步骤: 1. 准备工作 在C++中建立顺序表,我们需要先定义一个结构体来表示顺序表的元素,包含数据和序号信息。比如我们可以这样定义: struct ListElement { int data; // 数据 int index; // 序号 } 2. 建立顺序表 接下来我们可以使用一个数组来保存顺序表中的元素,需要先定义数组的…

    C 2023年5月23日
    00
  • 在spring中手写全局异常拦截器

    为了实现全局异常拦截器,我们需要以下步骤: 1.创建全局异常处理类 我们需要创建一个全局异常处理类来捕获控制器中抛出的异常。假设我们的类名为 GlobalExceptionHandler。 @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.c…

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