C++实现行列式的相关操作
目录
一.前言
二.行列式运算操作集
1.概览
2.行列式的定义
3.行列式的输出与输入
4.行列式行与行,列与列的相加
5.行列式的行交换与列交换
6.行列式的行提取公因数与列提取公因数
7.行列式系数清零恢复
8.判断一个行列式是否是三角阵
9.求余子式和代数余子式
10.求行列式的值
11.行列式的转置
12.所有代码
三.总结
一.前言
最近在学习C++,数据结构以及线性代数,我突发奇想,为什么不把这几个东西放在一起学习呢?于是我想把一些可以用C++语言描述的线性代数上的操作写出来,这样一来也可以加深我的记忆,写了一些之后果然行列式的性质我都记住了。接下来我将分享我的小成果。
二.行列式运算操作集
1.概览
我将这个操作集命名为了“linear_algebra.h”,也就是线性代数,我用百度直接翻译的。因为我的目标不只局限于行列式,我希望能写出一个包括大部分线性代数操作的库,因此我给它起名为线性代数,但是目前里边只有行列式的操作。
2.行列式的定义
既然是对行列式进行操作那么必须有一个合适的结构来存储行列式,经过认真的学习行列式的构造,我定义了如下结构的行列式:
typedef struct{double data[MaxSize][MaxSize];//二维数组,存储行列式用的数据主体int dimension;//维度,也就是行列式的阶数double multiple;//用于存储行列式的倍数
}det;//行列式的基本定义
首先是一个方形二维数组存放行列式,我命名为了data,dimension是阶数,multiple是系数,我用英文“乘”来表示,因为我当时忘了系数用英语怎么说。我们知道行列式的一个性质就是可以提出一行或一列的公因数放到外边作为整个行列式的系数,我们也可以将行列式的系数乘到里边的一行或一列中去。因此我需要一个变量来存储这个值。
3.行列式的输出与输入
1.行列式的输入
void input_det(det &inc_det){//以引用的方式传入行列式,因为我们需要对行列式进行改变。int i, j;std::cout << "请输入行列式维度:";std::cin >> inc_det.dimension;std::cout << "请输入行列式构型:" << std::endl;for (i = 0; i < inc_det.dimension; i++){for (j = 0; j < inc_det.dimension; j++){std::cin >> inc_det.data[i][j];}}inc_det.multiple = 1;
}//此函数用于输入一个行列式
2.行列式的输出
void print_det(det inc_det){//打印一个行列式1,因为仅访问即可,所以不用使用引用类型int i, j;std::cout << "这个行列式的维度为:" << inc_det.dimension << std::endl;std::cout << "其具体构型为:" << std::endl;for (i = 0; i < inc_det.dimension; i++){ std::cout << "|";for (j = 0; j < inc_det.dimension-1; j++){std::cout << inc_det.data[i][j] << " ";}if(i == inc_det.dimension/2)std::cout << inc_det.data[i][j] << "|" << "*"<< inc_det.multiple << std::endl;elsestd::cout << inc_det.data[i][j] << "|" << std::endl;}
}//此函数用于输出一个行列式
4.行列式行与行,列与列的相加
void det_add(det &inc_det, int i, int j, int n, int flag){//此函数用于将行列式的第i行/列的n倍加到第j行/列。i是加行;j是被加行;n是加行的倍数;flag是标志符号,若为0,则代表进行行操作,若为1则代表列操作,其他非法。i -= 1;j -= 1;if(flag==0){//标志为0进行行操作for (int t = 0; t < inc_det.dimension;t++){inc_det.data[j][t] = inc_det.data[j][t] + n * inc_det.data[i][t];}}else if(flag==1){for (int t = 0; t < inc_det.dimension;t++){inc_det.data[t][j] = inc_det.data[t][j] + n * inc_det.data[t][i];}}else{std::cout << "非法的标志符号:flag。flag只允许为1/0。" << std::endl;}}//将一个行列式中的第i行的n倍加在其第j行上
就是简单的二维数组的行列操作。
5.行列式的行交换与列交换
void det_change(det &inc_det, int i, int j, int flag){//行/列互换。交换第i行/列与第j行/列的值。flag是标志符号,0代表行操作,1代表列操作,其他非法。int t, h;i -= 1;j -= 1;if(flag==0){for (t = 0; t < inc_det.dimension; t++){h = inc_det.data[j][t];inc_det.data[j][t] = inc_det.data[i][t];inc_det.data[i][t] = h;}inc_det.multiple *= -1;//符号变化}else if(flag==1){for (t = 0; t < inc_det.dimension; t++){h = inc_det.data[t][j];inc_det.data[t][j] = inc_det.data[t][i];inc_det.data[t][i] = h;}inc_det.multiple *= -1;//符号变化}else{std::cout << "非法的标志符号:flag。flag只允许为1/0。" << std::endl;}}//互换行列式的第i行和第j行
同样是简单的二维数组行列操作,但是注意系数要乘一个“-1”。
6.行列式的行提取公因数与列提取公因数
void det_extract(det &inc_det, int i, int n,int flag){//行/列公因数的提取。flag是标志位,0代表行操作,1代表列操作。int t;i -= 1;if(i<0){std::cout << "非法的参数值:i。行/列数最小为1。" << std::endl;return;}if(flag==0){for (t = 0; t < inc_det.dimension;t++){inc_det.data[i][t] = inc_det.data[i][t]/n;}inc_det.multiple *= n;}else if(flag==1){for (t = 0; t < inc_det.dimension;t++){inc_det.data[t][i] = inc_det.data[t][i]/n;}inc_det.multiple *= n;}else{std::cout << "非法的标志符号:flag。flag只允许为1/0。" << std::endl;}}
7.行列式系数清零恢复
void det_recover(det &inc_det, int i,int flag){//将系数乘到第i行/列上int t;i -= 1;if(i<0){std::cout << "非法的参数值:i。行/列数最小为1。" << std::endl;return;}if(flag==0){for (t = 0; t < inc_det.dimension;t++){inc_det.data[i][t] = inc_det.data[i][t]*inc_det.multiple;}inc_det.multiple = 1;}else if(flag==1){for (t = 0; t < inc_det.dimension;t++){inc_det.data[t][i] = inc_det.data[t][i]*inc_det.multiple;}inc_det.multiple = 1;}else{std::cout << "非法的标志符号:flag。flag只允许为1/0。" << std::endl;}}
将系数乘入指定的行/列中,系数变为1。
8.判断一个行列式是否是三角阵
bool trangle_det(det &inc_det){//通过逐行检测的方式判断一个行列式是不是三角阵int i, j,ji = 0;bool down_flag = true;bool up_flag = true;for (i = 1,j = 1; i < inc_det.dimension;i++,j++){for (ji = 0; ji < j;ji++){if(inc_det.data[i][ji]!=0){down_flag = false;}}}for (i = 0, j = 1; i < inc_det.dimension; i++, j++){for (ji = j; ji < inc_det.dimension;ji++){if(inc_det.data[i][ji]!=0){up_flag = false;}}}if(up_flag||down_flag){return true;}else{return false;}
}//判断某一个行列式是否是三角行列式,包括上三角和下三角
通过暴力扫描法判断一个行列式是否是三角阵,三角阵分为上三角和下三角和对角阵,但是我们只需判断出它为上三角或下三角就能确定其为三角阵了。
9.求余子式和代数余子式
det remainder_form(det inc_det, int i, int j){//求余子式,结果会返回一个新的矩阵类型。det m;int inc_r, inc_l;int m_r = 0, m_l = 0;m.dimension = inc_det.dimension - 1;m.multiple = inc_det.multiple;for (inc_r = 0; inc_r < inc_det.dimension; inc_r++){for (inc_l = 0; inc_l < inc_det.dimension; inc_l++){if (inc_r != i && inc_l != j){m.data[m_r][m_l] = inc_det.data[inc_r][inc_l];m_l++;if (m_l > m.dimension-1){m_r++;m_l = 0;}}}}return m;
}
这个函数只能求出余子式的结构。也就是会得到一个新的矩阵。代数余子式经过带入公式就可以得到,具体的行列式求值需要函数的相互配合使用。但是这个函数只负责求出余子式的结构。同时我们注意在求余子式时不能让外边有系数,这是我设计的一个缺陷,如果外边有系数必须先乘进去,否则会导致行列式出现数值错误。
10.求行列式的值
1.递归函数
int solve_normal_det(det inc_det){//求普通和行列式double sum = 0;if(inc_det.dimension>2){for (int i = 0; i < inc_det.dimension; i++){sum = sum + pow(-1,i)*inc_det.data[i][0]*solve_normal_det(remainder_form(inc_det,i,0));}return sum;}else{return inc_det.data[0][0] * inc_det.data[1][1] - inc_det.data[0][1] * inc_det.data[1][0];}}
递归的配合余子式函数算出行列式的值,可以发现这里和书上的定义法是一样的,也就是第一行/列的值乘以他们的代数余子式再相加。这里可以发现代数余子式直接带入公式就可以配合余子式函数计算出来。
2.总函数
double solve_det(det &inc_det){det_recover(inc_det, 1, 0);//在求一个矩阵之前我们最好将他恢复成初始阵if(trangle_det(inc_det)){int result = 1;for (int i = 0; i < inc_det.dimension;i++){result = result * inc_det.data[i][i];}return result * inc_det.multiple;;}else{return solve_normal_det(inc_det);}}//用于求解行列式
这个函数有点特殊,它是用于求所有的行列式的,在这个函数里首先会判断一下是否为三角阵,如果是的话就直接对角相乘;不是的话就使用上面的行列式求解函数。因为这里涉及计算以及余子式的划分,所以我在一开头就把系数乘到了行列式里边。
11.行列式的转置
void det_transposition(det &inc_det){//转置就是行列互换int t[MaxSize][MaxSize];for (int i = 0; i < inc_det.dimension;i++){for (int j = 0; j < inc_det.dimension;j++){t[i][j] = inc_det.data[i][j];}}//先复制一份样品。for (int i = 0; i < inc_det.dimension;i++){for (int j = 0; j < inc_det.dimension;j++){inc_det.data[j][i] = t[i][j];}}
}
暴力的备份转置法。
12.所有代码
#include <iostream>
#include <math.h>
#define MaxSize 100
/*-------------------------------------------维度在100以内的行列式计算----------------------------------------------*/
typedef struct{double data[MaxSize][MaxSize];//二维数组,存储行列式用的数据主体int dimension;//维度,也就是行列式的阶数double multiple;//用于存储行列式的倍数
}det;//行列式的基本定义void input_det(det &inc_det){//以引用的方式传入行列式,因为我们需要对行列式进行改变。int i, j;std::cout << "请输入行列式维度:";std::cin >> inc_det.dimension;std::cout << "请输入行列式构型:" << std::endl;for (i = 0; i < inc_det.dimension; i++){for (j = 0; j < inc_det.dimension; j++){std::cin >> inc_det.data[i][j];}}inc_det.multiple = 1;
}//此函数用于输入一个行列式void print_det(det inc_det){//打印一个行列式1,因为仅访问即可,所以不用使用引用类型int i, j;std::cout << "这个行列式的维度为:" << inc_det.dimension << std::endl;std::cout << "其具体构型为:" << std::endl;for (i = 0; i < inc_det.dimension; i++){ std::cout << "|";for (j = 0; j < inc_det.dimension-1; j++){std::cout << inc_det.data[i][j] << " ";}if(i == inc_det.dimension/2)std::cout << inc_det.data[i][j] << "|" << "*"<< inc_det.multiple << std::endl;elsestd::cout << inc_det.data[i][j] << "|" << std::endl;}
}//此函数用于输出一个行列式void det_add(det &inc_det, int i, int j, int n, int flag){//此函数用于将行列式的第i行/列的n倍加到第j行/列。i是加行;j是被加行;n是加行的倍数;flag是标志符号,若为0,则代表进行行操作,若为1则代表列操作,其他非法。i -= 1;j -= 1;if(flag==0){//标志为0进行行操作for (int t = 0; t < inc_det.dimension;t++){inc_det.data[j][t] = inc_det.data[j][t] + n * inc_det.data[i][t];}}else if(flag==1){for (int t = 0; t < inc_det.dimension;t++){inc_det.data[t][j] = inc_det.data[t][j] + n * inc_det.data[t][i];}}else{std::cout << "非法的标志符号:flag。flag只允许为1/0。" << std::endl;}}//将一个行列式中的第i行的n倍加在其第j行上void det_change(det &inc_det, int i, int j, int flag){//行/列互换。交换第i行/列与第j行/列的值。flag是标志符号,0代表行操作,1代表列操作,其他非法。int t, h;i -= 1;j -= 1;if(flag==0){for (t = 0; t < inc_det.dimension; t++){h = inc_det.data[j][t];inc_det.data[j][t] = inc_det.data[i][t];inc_det.data[i][t] = h;}inc_det.multiple *= -1;//符号变化}else if(flag==1){for (t = 0; t < inc_det.dimension; t++){h = inc_det.data[t][j];inc_det.data[t][j] = inc_det.data[t][i];inc_det.data[t][i] = h;}inc_det.multiple *= -1;//符号变化}else{std::cout << "非法的标志符号:flag。flag只允许为1/0。" << std::endl;}}//互换行列式的第i行和第j行void det_extract(det &inc_det, int i, int n,int flag){//行/列公因数的提取。flag是标志位,0代表行操作,1代表列操作。int t;i -= 1;if(i<0){std::cout << "非法的参数值:i。行/列数最小为1。" << std::endl;return;}if(flag==0){for (t = 0; t < inc_det.dimension;t++){inc_det.data[i][t] = inc_det.data[i][t]/n;}inc_det.multiple *= n;}else if(flag==1){for (t = 0; t < inc_det.dimension;t++){inc_det.data[t][i] = inc_det.data[t][i]/n;}inc_det.multiple *= n;}else{std::cout << "非法的标志符号:flag。flag只允许为1/0。" << std::endl;}} void det_recover(det &inc_det, int i,int flag){//将系数乘到第i行/列上int t;i -= 1;if(i<0){std::cout << "非法的参数值:i。行/列数最小为1。" << std::endl;return;}if(flag==0){for (t = 0; t < inc_det.dimension;t++){inc_det.data[i][t] = inc_det.data[i][t]*inc_det.multiple;}inc_det.multiple = 1;}else if(flag==1){for (t = 0; t < inc_det.dimension;t++){inc_det.data[t][i] = inc_det.data[t][i]*inc_det.multiple;}inc_det.multiple = 1;}else{std::cout << "非法的标志符号:flag。flag只允许为1/0。" << std::endl;}}bool trangle_det(det &inc_det){//通过逐行检测的方式判断一个行列式是不是三角阵int i, j,ji = 0;bool down_flag = true;bool up_flag = true;for (i = 1,j = 1; i < inc_det.dimension;i++,j++){for (ji = 0; ji < j;ji++){if(inc_det.data[i][ji]!=0){down_flag = false;}}}for (i = 0, j = 1; i < inc_det.dimension; i++, j++){for (ji = j; ji < inc_det.dimension;ji++){if(inc_det.data[i][ji]!=0){up_flag = false;}}}if(up_flag||down_flag){return true;}else{return false;}
}//判断某一个行列式是否是三角行列式,包括上三角和下三角det remainder_form(det inc_det, int i, int j){//求余子式,结果会返回一个新的矩阵类型。我认为在求余子式之前我们应该先把矩阵系数清空det m;int inc_r, inc_l;int m_r = 0, m_l = 0;m.dimension = inc_det.dimension - 1;m.multiple = inc_det.multiple;for (inc_r = 0; inc_r < inc_det.dimension; inc_r++){for (inc_l = 0; inc_l < inc_det.dimension; inc_l++){if (inc_r != i && inc_l != j){m.data[m_r][m_l] = inc_det.data[inc_r][inc_l];m_l++;if (m_l > m.dimension-1){m_r++;m_l = 0;}}}}return m;
}int solve_normal_det(det inc_det){//求普通和行列式double sum = 0;if(inc_det.dimension>2){for (int i = 0; i < inc_det.dimension; i++){sum = sum + pow(-1,i)*inc_det.data[i][0]*solve_normal_det(remainder_form(inc_det,i,0));}return sum;}else{return inc_det.data[0][0] * inc_det.data[1][1] - inc_det.data[0][1] * inc_det.data[1][0];}}double solve_det(det &inc_det){det_recover(inc_det, 1, 0);//在求一个矩阵之前我们最好将他恢复成初始阵if(trangle_det(inc_det)){int result = 1;for (int i = 0; i < inc_det.dimension;i++){result = result * inc_det.data[i][i];}return result * inc_det.multiple;;}else{return solve_normal_det(inc_det);}}//用于求解行列式void det_transposition(det &inc_det){//转置就是行列互换int t[MaxSize][MaxSize];for (int i = 0; i < inc_det.dimension;i++){for (int j = 0; j < inc_det.dimension;j++){t[i][j] = inc_det.data[i][j];}}//先复制一份样品。for (int i = 0; i < inc_det.dimension;i++){for (int j = 0; j < inc_det.dimension;j++){inc_det.data[j][i] = t[i][j];}}
}
三.总结
我主要是为了复习线性代数写了这个操作集。通过写这个操作集我比较深入的复习了行列式的性质,对于行列式的计算以及行和列运算的共同点有了深入的了解。同时还对行列式的运算有了更深的认识。接下来复习全本书应该会舒服点吧?
C++实现行列式的相关操作相关推荐
- 2021年大数据HBase(五):HBase的相关操作JavaAPI方式
全网最详细的大数据HBase文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 前言 HBase的相关操作-JavaAPI方式 一.需求说明 ...
- 2021年大数据HBase(四):HBase的相关操作-客户端命令式!【建议收藏】
全网最详细的大数据HBase文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 前言 HBase的相关操作-客户端命令式 1.进入HBase ...
- 2021年大数据Spark(二十五):SparkSQL的RDD、DF、DS相关操作
目录 RDD.DF.DS相关操作 SparkSQL初体验 SparkSession 应用入口 获取DataFrame/DataSet 使用样例类 指定类型+列名 自定义Schema ...
- 【数据结构】二叉树及其相关操作
二叉树的定义 二叉树是一个由结点构成的有限集合,这个集合或者为空,或者由一个根节点及两棵互不相交的分别称作这个根节点的左子树和右子树的二叉树组成. 二叉树并非一般的树形结构的特殊形式,它们是两种不同的 ...
- Linux之用户组相关操作 groupadd groupdel
Linux之用户组相关操作 groupadd groupdel 1. 创建用户组 命令 说明 groupadd 创建(添加)用户组 创建用户组效果图: [grep是搜索功能,详情博文:https: ...
- Linux之用户相关操作
Linux之用户相关操作 1. 创建用户 [创建后会立即让设置密码] 命令 说明 useradd 创建(添加)用户 useradd命令选项: 选项 说明 -m 自动创建用户主目录,主目录的名字就是用 ...
- java导入包大全_eclipse快速导入jar包的相关操作步骤
eclipse怎样快速导入jar包呢?熟悉这款软件是非常简单的,今天小编就分享了关于eclipse快速导入jar包,有需要的朋友一起来看看吧! eclipse快速导入jar包的相关操作步骤 方法1·最 ...
- 顺序队列相关操作(C语言实现)
#顺序队列相关操作(C语言实现) #include<stdio.h> #define Size 100 typedef int DataType; typedef struct {Data ...
- oracle log.xml分析,怎么在alert目录下的log.xml中关闭logminer的相关操作日志? — oracle-tech...
Oracle版本10g-19c中,使用了logminer,但是在$ORACLE_SID/alert的目录下产生了大量的log_x.xml [email protected] alert]$ cd /o ...
最新文章
- Spark LogisticRegression 逻辑回归之建模
- spring中控制器和服务层校验的实现原理
- linux七大功能,值得Linux向其他系统借鉴的七大功能特性
- (10)调用门提权(无参数)
- Some notes for CLFS2017
- Scala 语言转义字符
- python mq_RabbitMQPython
- Mybaits自定义SQL
- 如何做一名出色的屌丝码农?
- mysql自动拉入黑名单_利用MySQL实现域名黑名单过滤10W记录1ms匹配
- java单元测试模拟输入_java – 单元测试:在定义模拟行为后调用...
- shapefile文件格式说明
- Python简单的音频处理
- 最直白的编译原理-词法分析(清华-王书3版)
- 江南春新年围炉夜谈:如何破解增长焦虑?
- UMTS到LTE的系统架构演进(学习整理:LTE完全指南-LTE、LTE-Advanced、SAE、VolTE和4G移动通信)
- 参考文献格式、论文尾注
- 2019年厦门大学计算机系夏令营经历
- python调用百度地图实现路径规划提取坐标点
- 2017春节~人生智慧箴言