使用迭代方法计算矩阵的行列式

时间:2018-06-09 21:15:37

标签: c++ recursion matrix iteration determinants

我编写了C ++代码,使用递归方法计算矩阵的行列式。

现在,我想使用迭代方法重写该递归方法。但我无法弄清楚如何实现这一目标。

问题是:如何将特定的递归方法( int Determinant(int *&,const int))重写为迭代方法?

以下是我的C ++代码:

// Determinant C++
#include <iostream>
#include <ctime>
using namespace std;

void RandInitArray(int *, const int, int = 0, int = 20);
void Display(int *, const int);

int CalculateDeterminant(int *&, const int);
int Determinant(int *&, const int);

int main()
{
    start = clock();
    srand((unsigned int)time(NULL));

    int N = 12;     // Size of matrix
    int * S = new int[N * N];
    int a(-10), b(10), det;

    RandInitArray(S, N, a, b);
    cout.precision(4);
    Display(S, N);

    det = CalculateDeterminant(S, N);

    cout << "\nDeterminant = " << det << "\n\n";

    cin.get();
    return 0;
}

void RandInitArray(int * arr, const int N, int a, int b)
{
    for (int i = 0; i < N * N; i++)
        arr[i] = rand() % (b - a + 1) + a;
}

void Display(int *arr, const int N)
{
    for (int i = 0; i < N * N; i++)
        cout << arr[i] << ((i + 1) % N ? "\t" : "\n");
}

int CalculateDeterminant(int *& S, const int N)
{
    int rez;

    if (N < 1)
        cout << "Size of matrix must be positive\n";
    else if (N == 1)
        rez = *S;
    else if (N == 2)
        rez = S[0] * S[3] - S[1] * S[2];
    else if (N == 3)
        rez = S[0] * S[4] * S[8] + S[1] * S[5] * S[6] + S[2] * S[3] * S[7] -
        S[2] * S[4] * S[6] - S[1] * S[3] * S[8] - S[0] * S[5] * S[7];
    else
        rez = Determinant(S, N);

    return rez;
}

int Determinant(int *& S, const int N)
{
    int sign(1), det(0), res, M(N - 1);
    int  * _S;

    for (int k = 0; k < N; k++)
    {
        _S = new int[M * M];

        int ind = 0;
        for (int i = N; i < N * N; i++)
        {
            if (i % N != k)
                _S[ind++] = S[i];
        }

        if (M == 3)
        {
            res = S[k] == 0 ? 0 : _S[0] * _S[4] * _S[8] + _S[1] * _S[5] * _S[6] + _S[2] * _S[3] * _S[7] -
            _S[2] * _S[4] * _S[6] - _S[1] * _S[3] * _S[8] - _S[0] * _S[5] * _S[7];

            delete[] _S;
        }
        else
            res = S[k] == 0 ? 0 : Determinant(_S, N - 1);

        det += S[k] * sign * res;
        sign *= -1;
    }

    delete[] S;

    return det;
}

我知道这不是计算大矩阵行列式的最智能方法。我可以使用矩阵变换简化矩阵,并大大加快计算速度。

尽管如此,我们将非常感谢任何帮助或提示。

2 个答案:

答案 0 :(得分:1)

通过使用关于下面给出的决定因素的两个事实,您可以计算行列式而不进行任何递归,并且对于大矩阵,这也会快得多。    1)将一行的标量倍数添加到另一行不会改变行列式。    2)交换两行否定了决定因素

这是使用您的代码实现的:

// Determinant C++
#include <iostream>
#include <stdio.h>
#include <ctime>
using namespace std;

void RandInitArray(int *, const int, int = 0, int = 20);
void Display(int *, const int);

int CalculateDeterminant(int *&, const int);
int Determinant(int *&, const int);

long long DeterminantIterative(int *&, const int);
int ResolveRows(int **, const int, int, int);
void Display(int **, const int);

bool RECURSIVE = true;
bool ShowCalculation = true;

int main()
{
    srand((unsigned int)time(NULL));

    int N = 6;     // Size of matrix
    int * S = new int[N * N];
    int a(-10), b(10), det;

    RandInitArray(S, N, a, b);

    if (N < 12)
    {
        cout << " ======== Recursive ========\n\n";
        Display(S, N);
        det = CalculateDeterminant(S, N);
        cout << "\nDeterminant = " << det << "\n\n";
    }

    cout << " ======== Iterative ========\n";
    RECURSIVE = false;
    det = CalculateDeterminant(S, N);
    cout << "\nDeterminant = " << det << "\n\n";

    cin.get();
    return 0;
}

void RandInitArray(int * arr, const int N, int a, int b)
{
    for (int i = 0; i < N * N; i++)
        arr[i] = rand() % (b - a + 1) + a;
}

void Display(int *arr, const int N)
{
    for (int i = 0; i < N * N; i++)
        cout << arr[i] << ((i + 1) % N ? "\t" : "\n");
}

int CalculateDeterminant(int *& S, const int N)
{
    int rez;

    if (N < 1)
        cout << "Size of matrix must be positive\n";
    else if (N == 1)
        rez = *S;
    else if (N == 2)
        rez = S[0] * S[3] - S[1] * S[2];
    else if (N == 3)
        rez = S[0] * S[4] * S[8] + S[1] * S[5] * S[6] + S[2] * S[3] * S[7] -
        S[2] * S[4] * S[6] - S[1] * S[3] * S[8] - S[0] * S[5] * S[7];
    else
        rez = RECURSIVE ? Determinant(S, N) : (int)DeterminantIterative(S, N);

    return rez;
}

int Determinant(int *& S, const int N)
{
    int sign(1), det(0), res, M(N - 1);
    int  * _S;

    for (int k = 0; k < N; k++)
    {
        _S = new int[M * M];

        int ind = 0;
        for (int i = N; i < N * N; i++)
        {
            if (i % N != k)
                _S[ind++] = S[i];
        }

        if (M == 3)
        {
            res = S[k] == 0 ? 0 : _S[0] * _S[4] * _S[8] + _S[1] * _S[5] * _S[6] + _S[2] * _S[3] * _S[7] -
                _S[2] * _S[4] * _S[6] - _S[1] * _S[3] * _S[8] - _S[0] * _S[5] * _S[7];

            delete[] _S;
        }
        else
            res = S[k] == 0 ? 0 : Determinant(_S, N - 1);


        det += S[k] * sign * res;
        sign *= -1;
    }

    //delete[] S;

    return det;
}

long long DeterminantIterative(int *& S, const int N)
{
    int ** M = new int*[N];
    for (int i = 0; i < N; i++)
        M[i] = new int[N];

    for (int i = 0; i < N * N; i++)
        M[i / N][i % N] = S[i];

    cout << "\n\n  Initial Matrix\n\n";
    Display(M, N);

    long determinant = 1;
    for (int i = 0; i < N - 1; i++)
        for (int j = i + 1; j < N; j++)
            while (M[j][i] != 0)
            {
                determinant *= ResolveRows(M, N, i, j);

                if (determinant == 0)
                    return 0;
            }

    for (int i = 0; i < N; i++)
        determinant *= M[i][i];

    for (int i = 0; i < N; i++)
        delete[] M[i];
    delete[] M;
    delete[] S;

    return determinant;
}

int ResolveRows(int ** M, const int N, int f, int s)
{
    if (ShowCalculation)
        printf("\n\n  f[%d][%d] = %d,\ts[%d][%d] = %d \n", 
            f, f, M[f][f], s, f, M[s][f] );

    int sign = 1;

    int NonZeroRowIndex = s;
    while (M[f][f] == 0)
    {
        sign *= -1;

        if (ShowCalculation)
            printf("  Swap Row[%d] and Row[%d] and change the sign\n", f, s);

        int * tmp = M[NonZeroRowIndex];
        M[NonZeroRowIndex] = M[f];
        M[f] = tmp;
        NonZeroRowIndex++;

        if (M[f][f] != 0)
            return sign;
        if (NonZeroRowIndex == N && M[f][f] == 0)
            return 0;       
    }

    if (fabs(M[f][f]) > fabs(M[s][f]))
    {
        sign *= -1;
        int * tmp = M[s];
        M[s] = M[f];
        M[f] = tmp;

        if (ShowCalculation)
            printf("  Swap Row[%d] and Row[%d] and change the sign\n", f, s);
    }

    int k = M[f][f] == 0 ? 1 : -M[s][f] / M[f][f];

    if (ShowCalculation)
        printf("  Multiply Row[%d] by %d and add to the Row[%d]\n\n", f, k, s);

    for (int i = 0; i < N; i++)
        M[s][i] += k * M[f][i];

    if (ShowCalculation)
    {
        Display(M, N);
        cin.get();
    }

    return sign;
}

void Display(int ** M, const int N)
{
    cout << "  ";
    for (int i = 0; i < N; i++) 
        for (int j = 0; j < N; j++)
            cout << M[i][j] << (j < N - 1 ? "\t" : "\n  ");
}

答案 1 :(得分:1)

你应该总计N!产品术语,每一个都是唯一的产品N个元素,它们都不在同一行或colomn中:按行顺序排序,colomn索引是范围[1··N]的排列,奇数排列被否定。您可以使用std::next_permutation来计算排列并反转每次迭代的符号。