当前位置:首页 > 技术 > 正文内容

邻接矩阵:图的存储与实现

访客 技术 2026年7月2日 1

图的存储需求

图结构具有复杂的关联特性,任意两个顶点间都可能存在连接关系,因此需要专门的存储机制。常见的图存储方案包括:邻接矩阵、边集数组、邻接表以及链式前向星。本文重点探讨邻接矩阵的实现原理与应用。

邻接矩阵核心原理

邻接矩阵采用二维数组描述顶点间的连接状态,是最直观的图存储方式。其实现分为两个层面:使用一维数组记录顶点信息,借助二维方阵维护邻接关系。

无向图的矩阵表示

对于无向图,邻接矩阵具有严格的数学特性:

  • 若顶点 vᵢvⱼ 相连,则 M[i][j] = M[j][i] = 1
  • 主对角线元素 M[i][i] 通常置零,表示无自环
  • 矩阵关于主对角线完全对称

顶点度数可直接从矩阵计算:第 i 行(或列)中值为1的元素个数即为顶点 vᵢ 的度。无向图中出度与入度相等。

#include <iostream>
#include <vector>
#include <unordered_map>

using namespace std;

vector<vector<int>> buildUndirected(int n, const string& labels, const vector<pair<char, char>>& connections)
{
    unordered_map<char, int> idx;
    for (int i = 0; i < n; ++i) idx[labels[i]] = i;
    
    vector<vector<int>> mat(n, vector<int>(n, 0));
    for (auto& e : connections) {
        int u = idx[e.first], v = idx[e.second];
        mat[u][v] = mat[v][u] = 1;
    }
    return mat;
}

void display(const string& labels, const vector<vector<int>>& mat)
{
    cout << "  ";
    for (char c : labels) cout << c << " ";
    cout << "\n";
    for (int i = 0; i < (int)labels.size(); ++i) {
        cout << labels[i] << "|";
        for (int j = 0; j < (int)labels.size(); ++j)
            cout << mat[i][j] << " ";
        cout << "\n";
    }
}

int main()
{
    string nodes = "abcd";
    vector<pair<char, char>> edges = {{'a','b'}, {'b','c'}, {'c','d'}, {'d','a'}};
    auto m = buildUndirected(4, nodes, edges);
    display(nodes, m);
    return 0;
}

有向图的矩阵表示

有向图的邻接矩阵不再保证对称性:

  • M[i][j] = 1 表示存在从 vᵢ 指向 vⱼ 的有向边
  • i 行元素之和为顶点 vᵢ 的出度
  • j 列元素之和为顶点 vⱼ 的入度
vector<vector<int>> buildDirected(int n, const string& labels, const vector<pair<char, char>>& arcs)
{
    unordered_map<char, int> idx;
    for (int i = 0; i < n; ++i) idx[labels[i]] = i;
    
    vector<vector<int>> mat(n, vector<int>(n, 0));
    for (auto& e : arcs) {
        mat[idx[e.first]][idx[e.second]] = 1;
    }
    return mat;
}

带权图的扩展

带权图(网)的邻接矩阵将布尔值替换为权重数值:

  • 存在边时存储权值 w
  • 无边时存储特殊标记(如 INT_MAX0x3f3f3f3f
  • 对角线元素为0,表示自身距离
#include <climits>

struct WeightedArc {
    char src, dst;
    int w;
};

vector<vector<int>> buildWeighted(int n, const string& labels, const vector<WeightedArc>& arcs)
{
    unordered_map<char, int> idx;
    for (int i = 0; i < n; ++i) idx[labels[i]] = i;
    
    vector<vector<int>> mat(n, vector<int>(n, INT_MAX));
    for (int i = 0; i < n; ++i) mat[i][i] = 0;
    
    for (auto& e : arcs) {
        mat[idx[e.src]][idx[e.dst]] = e.w;
    }
    return mat;
}

最短路径应用:Dijkstra算法

邻接矩阵为经典图算法提供了高效的数据基础。以下展示基于邻接矩阵的Dijkstra实现:

#include <iostream>
#include <algorithm>

const int MAXV = 1005;
const int INF = 0x3f3f3f3f;

int graph[MAXV][MAXV];
int dist[MAXV], pre[MAXV];
bool visited[MAXV];

void dijkstra(int start, int n)
{
    fill(dist, dist + n + 1, INF);
    fill(visited, visited + n + 1, false);
    
    dist[start] = 0;
    for (int i = 1; i <= n; ++i) {
        int u = -1, minD = INF;
        for (int j = 1; j <= n; ++j)
            if (!visited[j] && dist[j] < minD)
                minD = dist[j], u = j;
        
        if (u == -1) break;
        visited[u] = true;
        
        for (int v = 1; v <= n; ++v)
            if (!visited[v] && graph[u][v] != INF && 
                dist[u] + graph[u][v] < dist[v]) {
                dist[v] = dist[u] + graph[u][v];
                pre[v] = u;
            }
    }
}

特性权衡

优势局限
O(1)时间判定任意两顶点连通性O(V²)空间复杂度,稀疏图浪费严重
便于计算顶点度数增删顶点需重建整个矩阵
适合稠密图与频繁查询场景遍历邻接点需扫描整行,效率低

邻接矩阵适用于顶点规模可控、边密度较高的场景,如社交网络分析、路由表维护等。对于大规模稀疏图,建议采用邻接表等压缩存储方案。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。