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

在C++中不创建子矩阵,通过原矩阵引用及元素坐标计算行列式

当然可以!你的这几个问题其实都是围绕行列式计算的无额外存储实现,我给你一步步讲清楚:

1. 仅用初始矩阵变量+引用递归计算行列式

完全没问题!递归过程中你根本不需要创建任何额外的矩阵存储,只需要把原矩阵的const引用传给递归函数就行——因为行列式计算只需要读取元素,不会修改原矩阵,引用既安全又节省内存。

核心思路是:递归函数除了接收原矩阵引用,还需要额外参数标记当前要计算的子矩阵在原矩阵中的“范围”(或者说,要排除哪些行和列),这样每次递归都能直接从原矩阵中筛选出需要的元素,不用复制子矩阵。

2. 不创建子矩阵,用坐标计算子行列式

这其实是拉普拉斯展开的核心思路:n阶矩阵的行列式等于某一行(或列)所有元素与其代数余子式的乘积之和。而代数余子式对应的就是“去掉该元素所在行和列后的n-1阶子矩阵的行列式”——我们根本不需要真的生成这个子矩阵,只需要在递归时告诉函数“跳过指定的行和列”,遍历元素时过滤掉这些位置即可。

举个C++的实现例子,用vector<vector<int>>作为矩阵类型:

#include <vector>
using namespace std;

long long calcDeterminant(const vector<vector<int>>& mat, int subSize, int excludeRow = -1, int excludeCol = -1) {
    // 递归终止条件:1阶子矩阵,返回唯一没被排除的元素
    if (subSize == 1) {
        for (int i = 0; i < mat.size(); ++i) {
            if (i == excludeRow) continue;
            for (int j = 0; j < mat[i].size(); ++j) {
                if (j == excludeCol) continue;
                return mat[i][j];
            }
        }
        return 0; // 理论上不会走到这里
    }

    long long det = 0;
    // 找到当前子矩阵的第一行(原矩阵中第一个没被排除的行)
    int currentRow = -1;
    for (int i = 0; i < mat.size(); ++i) {
        if (i != excludeRow) {
            currentRow = i;
            break;
        }
    }

    // 遍历当前行的所有有效列(没被排除的列)
    for (int j = 0; j < mat.size(); ++j) {
        if (j == excludeCol) continue;
        // 计算代数余子式的符号:(-1)^(子矩阵中的行号+列号)
        // 当前行在子矩阵中是第0行,列号需要计算:如果当前列在排除列之前,就是j;否则是j-1
        int subColIndex = (j < excludeCol) ? j : j - 1;
        int sign = (subColIndex % 2 == 0) ? 1 : -1;

        // 递归计算子行列式:排除当前行和当前列,子矩阵大小减1
        det += sign * mat[currentRow][j] * calcDeterminant(mat, subSize - 1, currentRow, j);
    }

    return det;
}

// 对外调用的入口函数
long long determinant(const vector<vector<int>>& mat) {
    int n = mat.size();
    return calcDeterminant(mat, n);
}

这个实现里,所有递归调用都只操作原矩阵的引用,通过excludeRow和excludeCol参数标记要跳过的行和列,完全没有创建任何子矩阵。

3. 这种实现方式是否可以用递归,或是不应采用递归?

完全可以用递归,而且递归是实现拉普拉斯展开最直观的方式,代码可读性非常高,适合小矩阵的场景。不过你也要知道递归的局限性:

  • 时间效率问题:拉普拉斯展开本身的时间复杂度是O(n!),不管递归还是迭代都一样——n=10的时候已经要算3628800次,n=15更是天文数字。所以这种方法只适合小矩阵(比如n≤10),大矩阵一定要用高斯消元法(O(n³)复杂度)。
  • 栈溢出风险:递归深度等于矩阵的维度n,如果n太大(比如n>20),可能会触发栈溢出。不过还是那句话,n>20的话O(n!)的计算时间根本无法接受,你也不会用拉普拉斯展开来算。

如果要处理大矩阵,高斯消元的迭代实现会更高效,也能避免栈溢出;但如果是小矩阵,递归的实现方式简洁又好懂,完全没问题。

内容的提问来源于stack exchange,提问作者johnydr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:22:17