在本文章内,将会实现行列式的建立、销毁、打印、计算四个操作。
鉴于笔者技术有限,此行列式只针对整数int型,请读者自行扩充~_~。
1.行列式的建立与销毁
我们首先建立行列式的数据类型,由于行列式规模的不确定,采用动态分配方法。
typedef struct
{
int n;
int* p;
}determinant;
建立函数
void build_deter(determinant *d)//创建行列式
{
printf("请输入行列数:>");//输入行列式
scanf("%d", &d->n);
d->p = (int*)malloc(sizeof (int)* d->n*d->n);//为行列式分配空间
if (d->p == NULL)
{
printf("%s", strerror(errno));
}
printf("请按行输入值:>");
for (int i = 0; i < d->n; i++)
{
for (int j = 0; j < d->n; j++)
{
scanf("%d",(d->p)+(i*d->n+j));
}
}
printf("building over!\n");
}
销毁函数
void free_deter(determinant* d)//释放空间
{
free(d->p);
d->p = NULL;
}
2.行列式的打印
void dis_deter(determinant d)//打印行列式
{
for (int i = 0; i < d.n; i++)
{
printf("|");
for (int j = 0; j < d.n; j++)
{
printf("%-3d ", *((d.p) + (i * d.n + j)));
}
printf("|\n");
}
printf("printing over!\n");
}
其中由于动态分配原因,采用*((d.p) + (i * d.n + j))来模拟二维的定位。
3.行列式的计算
贴一张行列式的计算公式
可以看出,我们只需要解决两个问题,一个是找出p1p2p3……pn的全排列,并以此找到一组a进行相加,另一个是找到p1p2p3……pn的逆序数,从而确定每一组a前面的符号。
对于全排列,我在上一文章有讲实现原理,在此不加赘述,想要了解可以自行传送~_~,https://blog.csdn.net/2301_79847688/article/details/136762462
贴个代码:
int fac(int n)//计算阶乘
{
int result=1;
for (int i = n; i > 0; i--)
{
result *= i;
}
return result;
}
void change(int* a, int* b)//交换函数
{
int c;
c = *b;
*b = *a;
*a = c;
}
void bubble_sort(int* arrange,int n)//排序
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (arrange[j] > arrange[j + 1])
change(arrange+j, arrange+j+1);
}
}
}
void tran_arrange(int* arrange, int j, int n)//改变排列
{
if (j == 0)//自然顺序做首项
{
return;
}
if (n == 2)
{
change(arrange, arrange + 1);
}
else if(n == 3)//等于3做奇偶不同的对换
{
if (j % 2 == 0)
{
change(arrange, arrange + 1);
}
else if (j % 2 == 1)
{
change(arrange + 1, arrange + 2);
}
}
else //大于3递归
{
if (j % fac(n - 1) == 0)//在后面数循环结束后,调换首数和后面一个数,产生新的组合
{
int tmp = j;
if (tmp > fac(n))
tmp = tmp % fac(n);//tmp要在fac(n)内,防止(1)越界
bubble_sort(arrange + 1,n-1);//排序方便调换
if (tmp == 0)//自然顺序做首排列,第0次
{
return;
}
if (tmp == fac(n - 1))
change(arrange, arrange + n - 1);//调换算法,第一次换最后一位
else
change(arrange, arrange + n - (tmp / fac(n - 1)) + 1);//(1)之后“/”
}
tran_arrange(arrange+1,j,n-1);
}
}
对于逆序数,对于排列中一个元素,他后面有多少比他小的数,那他就构成了多少逆序数,而排列的总逆序数,就是所有元素对应逆序数的和。
大体思想是这样,看看代码:
int count_re(int* arrange,int n)//统计逆序数
{
int count = 0;
for (int i = 0; i < n; i++)
{
for (int j = i+1; j < n; j++)
{
if (arrange[i] > arrange[j])
count++;
}
}
if (count % 2 == 1)
return -1;
else
return 1;
}
这样我们就解决了所有算法问题,只需要用循环得到每一个数再相加就可以了,看看代码:
int count_deter(determinant d)//计算行列式
{
int result = 0;//行列式最终结果
int one = 1;//行列式的每个积
int *col_arrange = (int*)malloc(sizeof(int)*d.n);//创建一个记录列排列的数组
if (col_arrange == NULL)
{
printf("%s", strerror(errno));
}
for (int i = 0; i < d.n; i++)
{
*(col_arrange+i) = i;
}//赋值
for (int r = 0; r < fac(d.n); r++)//所有行列式的结果
{
one = 1;
tran_arrange(col_arrange,r,d.n);//确定一个列的排序
for (int i = 0; i < d.n; i++)
{
int a = *(d.p+(i*d.n)+col_arrange[i]);//行列式每个数
one = a*one;
}
result += one* count_re(col_arrange, d.n);
}
free(col_arrange);
col_arrange = NULL;
return result;
}
4.总结
这便是所有内容,感谢观看~_~,贴个代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
typedef struct
{
int n;
int* p;
}determinant;
int fac(int n)//计算阶乘
{
int result=1;
for (int i = n; i > 0; i--)
{
result *= i;
}
return result;
}
void change(int* a, int* b)//交换函数
{
int c;
c = *b;
*b = *a;
*a = c;
}
void bubble_sort(int* arrange,int n)//排序
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (arrange[j] > arrange[j + 1])
change(arrange+j, arrange+j+1);
}
}
}
void tran_arrange(int* arrange, int j, int n)//改变排列
{
if (j == 0)//自然顺序做首项
{
return;
}
if (n == 2)
{
change(arrange, arrange + 1);
}
else if(n == 3)//等于3做奇偶不同的对换
{
if (j % 2 == 0)
{
change(arrange, arrange + 1);
}
else if (j % 2 == 1)
{
change(arrange + 1, arrange + 2);
}
}
else //大于3递归
{
if (j % fac(n - 1) == 0)//在后面数循环结束后,调换首数和后面一个数,产生新的组合
{
int tmp = j;
if (tmp > fac(n))
tmp = tmp % fac(n);//tmp要在fac(n)内,防止(1)越界
bubble_sort(arrange + 1,n-1);//排序方便调换
if (tmp == 0)//自然顺序做首排列,第0次
{
return;
}
if (tmp == fac(n - 1))
change(arrange, arrange + n - 1);//调换算法,第一次换最后一位
else
change(arrange, arrange + n - (tmp / fac(n - 1)) + 1);//(1)之后“/”
}
tran_arrange(arrange+1,j,n-1);
}
}
void build_deter(determinant *d)//创建行列式
{
printf("请输入行列数:>");//输入行列式
scanf("%d", &d->n);
d->p = (int*)malloc(sizeof (int)* d->n*d->n);//为行列式分配空间
if (d->p == NULL)
{
printf("%s", strerror(errno));
}
printf("请按行输入值:>");
for (int i = 0; i < d->n; i++)
{
for (int j = 0; j < d->n; j++)
{
scanf("%d",(d->p)+(i*d->n+j));
}
}
printf("building over!\n");
}
void dis_deter(determinant d)//打印行列式
{
for (int i = 0; i < d.n; i++)
{
printf("|");
for (int j = 0; j < d.n; j++)
{
printf("%-3d ", *((d.p) + (i * d.n + j)));
}
printf("|\n");
}
printf("printing over!\n");
}
int count_re(int* arrange,int n)//统计逆序数
{
int count = 0;
for (int i = 0; i < n; i++)
{
for (int j = i+1; j < n; j++)
{
if (arrange[i] > arrange[j])
count++;
}
}
if (count % 2 == 1)
return -1;
else
return 1;
}
int count_deter(determinant d)//计算行列式
{
int result = 0;//行列式最终结果
int one = 1;//行列式的每个积
int *col_arrange = (int*)malloc(sizeof(int)*d.n);//创建一个记录列排列的数组
if (col_arrange == NULL)
{
printf("%s", strerror(errno));
}
for (int i = 0; i < d.n; i++)
{
*(col_arrange+i) = i;
}//赋值
for (int r = 0; r < fac(d.n); r++)//所有行列式的结果
{
one = 1;
tran_arrange(col_arrange,r,d.n);//确定一个列的排序
for (int i = 0; i < d.n; i++)
{
int a = *(d.p+(i*d.n)+col_arrange[i]);//行列式每个数
one = a*one;
}
result += one* count_re(col_arrange, d.n);
}
free(col_arrange);
col_arrange = NULL;
return result;
}
void free_deter(determinant* d)//释放空间
{
free(d->p);
d->p = NULL;
}
int main()
{
determinant d;
build_deter(&d);
dis_deter(d);
printf("\n%d",count_deter(d));
free_deter(&d);
return 0;