You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用vector<vector<int>>存图越界,改用vector[N]正常的原因

拓扑排序中两种图存储方式的越界问题分析

问题背景

实现简单拓扑排序程序时,尝试用vector<vector<int>>存储图结构,读取图时出现数组越界错误;改用vector<int> edge[N]后程序运行正常。即便尝试初始化edge或把它声明为局部变量,前者仍存在越界问题,需要明确两种存储方式的差异及错误原因。

正确代码

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;

int n, m;
const int N = 1e6 + 10;
vector<int> edge[N];
int adj[N];
int q[N];

inline void toposort() {
    int front = 1, rear = 0;
    for (int i = 1; i <= n; ++i) {
        if (adj[i] == 0){
            q[++rear] = i;
        }
    }
    while (front <= rear) {
        int s = q[front];
        ++front;
        for (auto c : edge[s]) {
            if (--adj[c] == 0) {
                q[++rear] = c;
            }
        }
    }
    if (rear == n) {
        cout << "Yes\n";
    } else {
        cout << "No\n";
    }
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    cin >> n >> m;
    for (int i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        edge[x].push_back(y);
        ++adj[y];
    }

    toposort();

    return 0;
}

错误代码

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;

int n, m;
const int N = 1e6 + 10;
vector< vector<int> > edge;
int adj[N];
int q[N];

inline void toposort() {
    int front = 1, rear = 0;
    for (int i = 1; i <= n; ++i) {
        if (adj[i] == 0){
            q[++rear] = i;
        }
    }
    while (front <= rear) {
        int s = q[front];
        ++front;
        for (auto c : edge[s]) {
            if (--adj[c] == 0) {
                q[++rear] = c;
            }
        }
    }
    if (rear == n) {
        cout << "Yes\n";
    } else {
        cout << "No\n";
    }
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    cin >> n >> m;
    for (int i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        edge[x].push_back(y);
        ++adj[y];
    }

    toposort();

    return 0;
}

测试输入

4 4
1 2
2 3
3 4
1 4

差异分析与错误原因

1. 两种存储结构的本质区别

  • vector<int> edge[N]:这是一个固定长度的全局数组,数组元素是vector<int>。因为N是预定义的常量(1e6+10),程序启动时就会分配好N个空vector的存储空间,下标范围覆盖0到N-1。测试输入中节点编号最大为4,远小于N,所以访问edge[x]不会触发越界。
  • vector<vector<int>> edge:这是一个动态二维vector,默认初始化后size为0,没有任何可用的下标。当代码中直接访问edge[x](比如x=1)时,当前edge的有效下标范围是空的,直接触发数组越界错误。

2. 错误代码的修复方式

在错误代码的main函数中,读取n和m之后,需要先初始化edge的大小,确保能覆盖所有节点的编号:

cin >> n >> m;
edge.resize(n + 1); // 节点编号从1到n,resize到n+1避免下标越界

这样edge会被初始化为包含n+1个空vector<int>的容器,访问edge[1]到edge[n]就属于合法操作。

3. 为什么初始化/局部变量无法解决问题

如果只是声明局部的vector<vector<int>> edge,或者执行无意义的初始化(比如edge = vector<vector<int>>()),都不会改变它size=0的状态,访问edge[x]依然会越界。必须通过resize明确设置容器的大小,才能让下标访问合法。

内容的提问来源于stack exchange,提问作者等不到的时间

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 08:07:51