Yan`s Notepad

--- My Notepad......Articles, tools and etc.
C++程序计算行列式的值
这次的内容,是在开始学线性代数的时候想到的。我的教材上,第一章就是行列式的值。介绍了二阶到n阶的行列式的求法。不过想笑的是,才刚开始学,我老是算错它,大部分时候是因为负号忘记了。于是便想着写一个程序来计算一下。在此之前,先提及行列式的有关内容,也算是复习一遍。
我们知道,针对于二、三阶行列式,可以采用对角线法则展开,也就是主对角线上的元素相乘相加,副对角线上的元素相乘相减:
small
但是,对角线法则只是适用于二、三阶行列式,并且这个只是一个规律。说到这里还想起高中的时候,用叉乘求法向量,一群好奇的同学去学行列式,然后拿四阶行列式用对角线法则计算的做法,现今不免觉得搞笑有趣。
针对于任意阶的行列式,可以采用代数余子式展开的方式来计算。当我们从某个n阶行列式中删去第i行,第j列之后,余下的数的位置不变,组成的n-1阶行列式叫做余子式。把余子式乘以-1的i+j次方,得到的就是代数余子式。我们用红色的笔标出了被划掉的行和列,并且写出了对应的余子式、代数余子式:
small
这个时候, 我们就可以将一个行列式展开,也就是行列式的值等于某一行或者某一列的所有元素和它们对应的代数余子式的积的和。比如我们展开一个三阶行列式可以是:
small
那么我们就可以来展开一下下面这个行列式的值,当作练习。为了引出下面的内容,我展开了两个行列式,第二个是第二行的所有元素加上了第一列的对应的值。
small
可以看到,它们两个的值都是一样的。这是行列式的性质:将行列式中的第i行的k倍加到第j行上、或者是第i列的k倍加到第j列上,行列式的值不变。并且分别记作r(i)+kr(j),c(i)+kc(j)。至此,考虑展开一个下图的行列式:该行列式主对角线下方的元素都是0,主对角线上方的元素都不为0,按照每一个行列式的第一列进行展开,得到了下面的结果:
small
因而,对于上三角矩阵的行列式,它的值就是主对角线上的元素相乘。因此,我们可以将一个输入的矩阵通过某行减去某另一行的方式,来计算行列式的值。比如下面的行列式,我们通过变换将之化为上三角矩阵行列式然后计算。按照之前的性质,它的值不变。
small
总结出一般性的方法:一步步的往右边走,从第一列开始,把第一行第一列元素下方的值全部划为0,然后把第二列第二行元素下方的值全部划为0......直到最后一列为止。因此,我们可以得到以下的程序:
#include <iostream>
#define  BUFF2D(buff, i, j, n)     ((buff) + ((i) * (n)) + (j))
#define  REAL_EPSILON              1e-6
typedef float  _real;
int main()
{
    int      n, i, j, k;
    _real    bas, q, d, *matrix;
    printf("输入阶数: ");
    std::cin >> n;
    matrix = (_real*)malloc(n * n *sizeof(_real));
    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            std::cin >> *BUFF2D(matrix, i, j, n);
    d = *matrix;                                        // d = 该矩阵的第一行, 第一列的元素
    for (i = 1; i < n; i++)                             // 把输入矩阵化成上三角矩阵, 开始划每一列
    {
        bas = *BUFF2D(matrix, i - 1, i - 1, n);         // 减去的行的列首的元素
        if (fabs(bas) > REAL_EPSILON)                   // 只划掉当前列不为0的行
            for (j = i; j < n; j++)
            {
                q = *BUFF2D(matrix, j, i - 1, n) / bas; // 下一行, 正在进行运算的列首的元素, 然后让matrix[j][i - 1]-q*bas=0
                for (k = i - 1; k < n; k++)             // 遍历运算该行: r(j) - qr(i - 1)
                    *BUFF2D(matrix, j, k, n) -= q * *BUFF2D(matrix, i - 1, k, n);
            }
        d *= *BUFF2D(matrix, i, i, n);                  // 对角线相乘
    }
    free(matrix);
    printf("det(A) = %f\n", d);
    system("pause");
    return 0;
}
当然,你也可以按照代数余子式展开一个行列式,做类似的运算,不过这样的方法怕是麻烦些许,故不考虑。注意,首个循环从1开始是因为第一行的值是一直不改变的,所以可以从1开始。在上面的程序中,使用了BUFF2D这个宏来访问二维数组下标。你也可以使用一般的二维数组,一般的二维数组的下标方式是[列][行]的样子。