C++处理3×3矩阵排列时出现Segmentation Fault问题排查
问题分析与解决方案
你遇到的Segmentation Fault主要有两个核心原因:递归DFS导致的栈溢出,以及全局状态缓存未清空引发的内存耗尽,再加上算法本身不适合寻找最短路径,导致效率极低且资源占用过大。
具体错误原因
- 递归深度超限:DFS递归会沿着一条路径不断深入,对于3×3矩阵的状态空间,最坏情况下递归深度可能达到数万级别,而程序的栈空间通常只有几MB,最终触发栈溢出(SIGSEGV)。
- 全局map未清空:你的
mp是全局变量,即使单个测试用例,递归过程中也会不断向其中添加状态,随着状态数累积(最多可达9! = 362880个),内存占用持续增长,最终malloc分配内存失败。 - 算法选型不当:DFS并不适合寻找最短路径(最小步数),它会优先探索深层路径,不仅效率低,还无法保证第一次找到的是最优解,需要额外维护
min_count,进一步增加了资源消耗。
修正方案:改用BFS算法
BFS(广度优先搜索)是寻找最短路径的标准算法,它按层级遍历状态,第一次到达目标状态时的步数就是最小步数,而且用迭代方式实现,不会有栈溢出问题。同时我们可以优化状态表示,用整数代替字符串,减少内存占用和状态转换时间。
以下是修正后的代码:
#include <bits/stdc++.h> using namespace std; // 判断是否为质数(题目中两数之和最大为9+8=17,所以只需判断到17) bool isPrime(int n) { return n == 2 || n == 3 || n == 5 || n == 7 || n == 11 || n == 13 || n == 17; } // 将3x3矩阵转换为整数(比如123456789) int matrixToInt(const vector<vector<int>>& mat) { int num = 0; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { num = num * 10 + mat[i][j]; } } return num; } // 将整数转换回3x3矩阵 void intToMatrix(int num, vector<vector<int>>& mat) { for (int i = 2; i >= 0; --i) { for (int j = 2; j >= 0; --j) { mat[i][j] = num % 10; num /= 10; } } } void solve() { vector<vector<int>> vec(3, vector<int>(3)); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { cin >> vec[i][j]; } } const int target = 123456789; int start = matrixToInt(vec); if (start == target) { cout << 0 << endl; return; } // BFS队列:存储当前状态和对应的步数 queue<pair<int, int>> q; // 记录已访问的状态,避免重复处理 unordered_set<int> visited; q.push({start, 0}); visited.insert(start); // 四个方向:右、下(对应原代码中的交换相邻元素) vector<pair<int, int>> dirs = {{0, 1}, {1, 0}}; int min_count = -1; while (!q.empty()) { auto [current_num, steps] = q.front(); q.pop(); vector<vector<int>> mat(3, vector<int>(3)); intToMatrix(current_num, mat); // 遍历所有位置,尝试交换相邻元素 for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { for (auto [di, dj] : dirs) { int ni = i + di; int nj = j + dj; if (ni >= 0 && ni < 3 && nj >=0 && nj <3) { // 检查两数之和是否为质数 if (isPrime(mat[i][j] + mat[ni][nj])) { swap(mat[i][j], mat[ni][nj]); int next_num = matrixToInt(mat); if (next_num == target) { min_count = steps + 1; // 找到答案后直接退出所有循环 goto end_search; } if (!visited.count(next_num)) { visited.insert(next_num); q.push({next_num, steps + 1}); } // 交换回来,恢复原矩阵 swap(mat[i][j], mat[ni][nj]); } } } } } } end_search: cout << min_count << endl; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int test; cin >> test; while (test--) { solve(); } return 0; }
关键优化点
- 状态表示优化:用整数代替字符串,将3x3矩阵转换为一个9位数,比字符串更节省内存,且哈希和比较操作更快。
- BFS迭代实现:使用队列代替递归,避免栈溢出问题,且第一次到达目标状态时的步数就是最小步数,无需维护
min_count变量。 - 局部化状态缓存:将
visited设为solve()的局部变量,每次测试用例后自动销毁,不会积累状态导致内存泄漏。 - 输入输出优化:添加
ios::sync_with_stdio(false); cin.tie(nullptr);加速输入输出,避免因大量IO导致的性能问题。
测试你提供的输入用例:
1 7 3 2 4 1 5 6 8 9
程序会正确输出6,且不会触发Segmentation Fault。
内容的提问来源于stack exchange,提问作者Sourabh Khandelwal
相关产品推荐
相关产品推荐

