在这里感谢我的学长以及Bowen Young大佬提供了帮助
前言
前几天刚开始学线性代数,于是就想用C++复现一下
本来以为是很简单的,但是后期纠错花了好几个晚上才搞定毕竟我太菜了
C++源码已上传至GitHub
项目地址
源码
#include <iostream>
#include <cmath>
#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阶行列式定义
这里将行列式中的每项视为一个二维数组x[max_n][max_n]
其中在开头定义的常量max_n
为本程序所能运算的最大阶数
n阶行列式的定义式
可以看出:
n阶行列式在运算时由两个部分组成
- 第一部分是系数,在所选的序列的总逆序数为偶数时取1,奇数为-1
- 第二部分是所选序列的累乘
那么在编写程序时也可分成这两项来分别编写
其中,系数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++中^
表示异或
正确的方式是在头文件中调用<cmath>
,然后使用pow()
函数
附pow()
函数的使用方法:pow(x,y)
表示x的y次方
3. C++环境出错
后来发现所有的错误都排除了,但是还是不能正常输出D的值,但是在学长的电脑上能正常运行的,因此发现是环境问题
将VSCode换为Dev C++后居然就能正常运行了
目前该问题笔者还在研究中
小结
肝这个代码花了我近四天晚上的时间来构思和修改错误
尽管并非作业,但是能用自己所学的C++来实现某项功能还是很有成就感的
也很感谢有大佬在我遇到困难时能出手相助
2 comments
可不是什么大佬