LeetCode拓扑排序题代码触发空指针调用错误求助
问题分析与解决
你的运行时错误根源在于在同一个循环迭代中处理多个叶子节点时,会出现对空unordered_set调用begin()并解引用的未定义行为。
举个典型场景:假设节点A和B互相连接,在同一轮循环中先处理A,删除B集合里的A,此时B的集合只剩一个元素;接着处理另一个叶子节点C,删除B集合里的C,此时B的集合变为空。当遍历到B时,graph[B].size() == 0满足<=1的判断条件,这时执行*(graph[B].begin()),但空集合的begin()等于end(),解引用这个迭代器会直接触发空指针类的未定义行为,也就是你看到的报错。
同时,你在同一个for循环里动态修改graph和n,会导致同一轮循环中处理刚被修改状态的节点,逻辑混乱,进一步放大了出错概率。
修复方案
正确的做法是每一轮循环先收集当前所有的叶子节点,再统一处理这些叶子节点的删除操作,避免遍历过程中修改数据导致的迭代问题:
class Solution { public: vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) { if (n == 1) return {0}; vector<unordered_set<int>> graph(n); for (auto& edge : edges) { graph[edge[0]].insert(edge[1]); graph[edge[1]].insert(edge[0]); } queue<int> leaves; // 初始化叶子节点队列 for (int i = 0; i < n; ++i) { if (graph[i].size() == 1) { leaves.push(i); } } // 剥洋葱式删除叶子,直到剩余节点数<=2 while (n > 2) { int leafCount = leaves.size(); n -= leafCount; for (int i = 0; i < leafCount; ++i) { int leaf = leaves.front(); leaves.pop(); int neighbor = *(graph[leaf].begin()); graph[neighbor].erase(leaf); // 如果邻居变成新的叶子,加入队列 if (graph[neighbor].size() == 1) { leaves.push(neighbor); } } } // 收集剩余的根节点 vector<int> res; while (!leaves.empty()) { res.push_back(leaves.front()); leaves.pop(); } return res; } };
关键修复点
- 用队列收集每一轮的叶子节点,统一处理,避免遍历过程中修改数据引发的迭代错误
- 仅当节点的邻居集合大小为1时才视为叶子,避免处理空集合的情况
- 每一轮处理固定数量的叶子节点(当前队列的大小),保证
n的递减逻辑准确
内容的提问来源于stack exchange,提问作者Ruiyang Li
相关产品推荐
相关产品推荐

