使用C++实现n阶行列式的计算

本文原文发表于本人博客 哔哔哔哔-使用C++实现n阶行列式的计算

在这里感谢我的学长以及Bowen Young大佬提供了帮助

前言

前几天刚开始学线性代数,于是就想用C++复现一下
本来以为是很简单的,但是后期纠错花了好几个晚上才搞定
毕竟我太菜了
C++源码已上传至GitHub

项目地址

https://github.com/gst-be/determinant

源码

#include 
#include 
#define N 900//比n^n大即可
#define max_n 30//最高可算多少阶行列式

using namespace std;

//计算每项前系数
int t(int p[N],int n)
{	
	int c=0;//定义逆序数计数器
	
	for(int i=0;i<n-1;i++)
	{
		for(int j=i+1;j<n;j++)
		{
			if(p[i]>p[j])  
			c++;//出现逆序则自增1
			else if(p[i]==p[j])
			return 0;//出现同列情况将系数变为0
		}
	}
	
	if(c%2==0)
	return 1;//偶逆序数返回1
	else
	return -1;//奇逆序数返回-1
}

//计算系数外每项的乘积
double product(double x[max_n][max_n],int p[N],int n)
{
	double pdt=1;//乘积初始化为1
	for(int i=0;i<n;i++)
	{
		pdt*=x[i][p[i]];
	}
	return pdt;//返回本次序列数所对应的乘积
}


double sum(double x[max_n][max_n],int n)
{
	double sum1=0;//初始化结果为0
	int p[N];//定义序列数,从p[1]开始每一位的值对应取x[][]中每行的第几列
	for(int i=0;i<N;i++)
	{
		p[i]=0;//初始化
	}
	
	
	for(int i=0;i<pow(n,n);i++)
	{
		sum1+=t(p,n)*product(x,p,n);
		
		//开始生成序列数
		p[0]++;
		for(int j=0;j<n;j++)
		{
			if(p[j]==n)
			{
				p[j]=0;
				p[j+1]++;
			}
		}
		
		
	}
	
	
	return sum1;
}

int main()
{
	int n;//阶数
	double x[max_n][max_n];
	cout<<"input n=";
	cin>>n;//定义行列式阶数

	//输入行列式的每一项的值
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			cout<<"input x["<<i<<"]["<<j<<"]=";
			cin>>x[i][j];
		}
	}
	
	
	cout<<"D="<<sum(x,n);
	
	return 0;
}

解析

n阶行列式定义

使用C++实现n阶行列式的计算_第1张图片
这里将行列式中的每项视为一个二维数组x[max_n][max_n]
使用C++实现n阶行列式的计算_第2张图片
其中在开头定义的常量max_n为本程序所能运算的最大阶数

n阶行列式的定义式

使用C++实现n阶行列式的计算_第3张图片
可以看出:
n阶行列式在运算时由两个部分组成

  • 第一部分是系数,在所选的序列的总逆序数为偶数时取1,奇数为-1
  • 第二部分是所选序列的累乘
    那么在编写程序时也可分成这两项来分别编写
    使用C++实现n阶行列式的计算_第4张图片
    其中,系数k由函数t(int p[N],int n)生成
    累乘部分由函数product(double x[max_n][max_n],int p[N],int n)生成

系数的生成

由于定义中规定不能选中同行同列的项相乘,但由于这个实现起来比较麻烦,所以就将同列的情况所对应系数为0
即:

  • 序列为偶逆序,函数返回1
  • 序列为奇逆序,函数返回-1
  • 序列为同列,函数返回0

累乘的生成

这个没什么好说的,将结果的值先初始化为1,然后从序列p[]中读取每轮所要取第几行第几列的值,然后用for循环实现累乘即可

序列的生成

这个想了很久,后来请教了我计科的学长,用n位n进制来实现:

这是一个n*n的矩阵,每行取一个数,需要遍历每一种结果,因此共有n^n种不同的取法
那么可以由这么一个数表示每行所要取第几列,也就是一个n位长的数,每一轮个位都自增1,逢n进1,直到n^n种情况遍历完为止
这个数的每一位都表示该行取第几列,比如个位数表示第一行取第几位,十位数表示第二位取第几位,n位数表示第n行取第几位
每次先自增1,再由一个for循环嵌套if来判断是否需要进位
为方便,就将这段序列数存储在了数组p[]
并且在此之前需要将数组初始化
这段代码被写在了sum(double x[max_n][max_n],int n)


所遇到的问题

1. 数组索引溢出

定义数组时用的x[max_n][max_n],但是在for循环中所遍历的范围是1-max_n,超出了数组所定义的范围
所以后期调整为遍历0-max_n

2. 乘方的表示

之前写乘方时使用的是n^n,但在C++中^表示异或
正确的方式是在头文件中调用,然后使用pow()函数
pow()函数的使用方法:
pow(x,y)表示x的y次方

3. C++环境出错

后来发现所有的错误都排除了,但是还是不能正常输出D的值,但是在学长的电脑上能正常运行的,因此发现是环境问题
将VSCode换为Dev C++后居然就能正常运行了
目前该问题笔者还在研究中


小结

肝这个代码花了我近四天晚上的时间来构思和修改错误
尽管并非作业,但是能用自己所学的C++来实现某项功能还是很有成就感的
也很感谢有大佬在我遇到困难时能出手相助


本文原文发布于哔哔哔哔(bebebe.be)

你可能感兴趣的:(数学,cpp,c++,开发语言)