c&行列式


code:

 #include 
#include 
#include              
#include      //计算行列式的值,要bool类型的可以直接用stdbool.h~\(≧▽≦)/~啦啦啦(c99)//
                                  
int * c,                       
      n = 0,                  
      a,                         
      sum = 0;             
int aq(int a)           /*aq计算阶乘*/              
{
    int s = 1;
    for(int i = 1; i <= a; i ++)
          s *= i;
    return s;
}
void swap(int * a, int * b)         /*swap利用地址传递交换两个数的值*/
{
    int m =* a;
    * a = * b;
    *b = m;
}
bool sa(int * l)            /*sa计算在行列式计算过程中每一项前边的符号是正还是负*/
{
    int n = 0;
    for(int i = 0; i < a-1; i ++)
         for(int j = i+1; j < a; j++)
               if(l[i]>l[j])n++;
    if(n % 2 == 0) return false;
    return true;
}
void perm(int * l,int k,int m)          /*perm整个程序里边的核心函数,找出在不同行不同列的所有组合*/
{
    int i, s = 1;
    if(k > m)
    {
        n++;            //递归次数//
        for(int j = 0; j < a; j ++)
              s *= c[ l[ j ] + a * j ];
        if( sa( l ) ) s*=-1;
      
        printf("%5d      完成度:%2.2f%%\n", sum+=s , n/( aq( a ) * 0.1 ) * 10 );
    }
    else            //全排列//
    {
        for(i = k; i <= m; i++)
        {
            swap(l + k, l + i);
            perm(l, k + 1, m);
            swap(l + k, l + i);
        }
    }
}
/*---------------------------------------------------------------*/
void main()
{
    int * b,
    i, 
    f, 
    e;
    system("color 3e");
u: system("cls");
    printf("请输入行列式的阶数:\n");
    scanf("%d", &a);//获取行列式的阶数
    b = ( int * ) malloc ( sizeof ( int ) * a );            /*malloc*/
    c = ( int * ) malloc ( sizeof ( int ) * a * a );
    for( i = 0; i < a; i++)
         * ( b + i ) = i;
    for( i = 0; i < a * a; i++)
    {
        if( i % a == 0 ){
            printf("请依次输入行列式中第%d行的值(以空格分隔):\n",i / a + 1 );
    }
        scanf("%d", c + i );
    }
    printf("\n\n");
    perm( b, 0, a - 1 );            /*计算行列式的值*/
    printf("\n行列式展开式共有%d项\n", aq( a ) );
    if ( a % 2 != 0 ) f = a + 1;
        else f = a;
    for( i = 0; i < a * a; i ++ )
    {       
        if ( i / a + 1 == f / 2 && i % a == 0) 
            printf("D = ");//输出“D = ”
        else if ( i % a == 0) 
                    printf("    ");
        if ( i % a == 0) 
            printf("┃");
        if ( ( i + 1 ) % a == 0) 
            printf("%2d", * ( c + i ) );
        else printf("%2d ", * ( c + i ) );
        if ( ( i + 1 ) % a == 0 ) 
            printf("┃");
        if ( ( i + 1 ) / a == f / 2 && ( i + 1 ) % a == 0) 
            printf(" = %d\n",sum);
        else if ( ( i + 1 ) % a == 0 ) 
                    printf("\n");
    }
    printf("\n\n");
    printf("是否继续?( 1 / 0 )\n");
    scanf("%d", &e);
    n = 0;
    if( e ==1 ) goto u;
    else if ( e == 0 ) exit( 0 );
   }

dosomethink

  • 这个程序利用了行列式的定义来计算行列式的值。也就是找出行列式中所有不同行不同列的所有组合,分别计算每个组合里的数的乘积再乘以-1的它们的逆序数次方,最后累加。(表达能力不好,看不懂可以谷歌一下)


    行列式定义
  • 看代码本身,主函数做的事无非读取行列式然后计算。这是读取行列式的代码。
    printf("请输入行列式的阶数:\n");
    scanf("%d", &a);//获取行列式的阶数
    b =  malloc ( sizeof ( int ) * a );            /*malloc*/
    c =  malloc ( sizeof ( int ) * a * a );
    for( i = 0; i < a; i++)
         * ( b + i ) = i;
          printf("hallo");
    for( i = 0; i < a * a; i++)
    {
        if( i % a == 0 ){
            printf("请依次输入行列式中第%d行的值(以空格分隔):\n",i / a + 1 );
    }
        scanf("%d", c + i );
    }

我修改了一下

    scanf("%d", &a);//获取行列式的阶数
    b = ( int * ) malloc ( sizeof ( int ) * a );            /*malloc*/
    c = ( int * ) malloc ( sizeof ( int ) * a * a );
    for( i = 0; i < a; i++)
         * ( b + i ) = i;       //不会到这行了?//
     printf("hallo\n") ;     
    for( i = 0; i < a * a; i++)
    {
        if( i % a == 0 ){
            printf("请依次输入行列式中第%d行的值(以空格分隔):\n",i / a + 1 );
        }
            
        scanf("%d", c+i );
        printf("%d | ,%d | ,%d\n",i,c[i],b[i] ); 
        
    }

下面是阶数为2的运行结果

请输入行列式的阶数:
2
hallo
请依次输入行列式中第1行的值(以空格分隔):
1 2
0 | ,1 | ,0
1 | ,2 | ,1
请依次输入行列式中第2行的值(以空格分隔):
3 4
2 | ,3 | ,0
3 | ,4 | ,0


    4      完成度:50.00%
   -2      完成度:100.00%

行列式展开式共有2项
D = ┃ 1  2┃ = -2
    ┃ 3  4┃

我不懂的是hallo就出现了一次,说明循环只经过第一个for的函数体一次,但是从1 | ,2 | ,1这行输出看却经过了。不懂。

  • 然后是计算,下面是用来计算的perm函数
void perm(int * l,int k,int m)          /*perm整个程序里边的核心函数,找出在不同行不同列的所有组合*/
{
    int i, s = 1;
    if(k > m)
    {
        n++; 
        for(int j = 0; j < a; j ++)
              s *= c[ l[ j ] + a * j ];
        if( sa( l ) ) s*=-1;
      
        printf("%5d      完成度:%2.2f%%\n", sum+=s , n/( aq( a ) * 0.1 ) * 10 );
    }
    else  
    {
        for(i = k; i <= m; i++)
        {
            swap(l + k, l + i);
            perm(l, k + 1, m);
            swap(l + k, l + i);
        }
    }
}

这里涉及了全排列算法,这里是用了递归的全排列算法。我参考了一篇博客。

全排列是将一组数按一定顺序进行排列,如果这组数有n个,那么全排列数为n!个。现以{1, 2, 3, 4, 5}为

例说明如何编写全排列的递归算法。

1、首先看最后两个数4, 5。 它们的全排列为4 5和5 4, 即以4开头的5的全排列和以5开头的4的全排列。

由于一个数的全排列就是其本身,从而得到以上结果。

2、再看后三个数3, 4, 5。它们的全排列为3 4 5、3 5 4、 4 3 5、 4 5 3、 5 3 4、 5 4 3 六组数。

即以3开头的和4,5的全排列的组合、以4开头的和3,5的全排列的组合和以5开头的和3,4的全排列的组合.

从而可以推断,设一组数p = {r1, r2, r3, ... ,rn}, 全排列为perm(p),pn = p - {rn}。

因此perm(p) = r1perm(p1), r2perm(p2), r3perm(p3), ... , rnperm(pn)。当n = 1时perm(p} = r1。

为了更容易理解,将整组数中的所有的数分别与第一个数交换,这样就总是在处理后n-1个数的全排列。

前面都懂,就是最后一句没懂

为了更容易理解,将整组数中的所有的数分别与第一个数交换,这样就总是在处理后n-1个数的全排列。

博客里的算法示例

#include   

int n = 0;  

void swap(int *a, int *b) 
{     
    int m;     
    m = *a;     
    *a = *b;     
    *b = m; 
}  
void perm(int list[], int k, int m) 
{     
    int i;     
    if(k > m)     
    {          
        for(i = 0; i <= m; i++)             
            printf("%d ", list[i]);         
        printf("\n");         
        n++;     
    }     
    else     
    {         
        for(i = k; i <= m; i++)         
        {             
            swap(&list[k], &list[i]);             
            perm(list, k + 1, m);             
            swap(&list[k], &list[i]);         
        }     
    } 
} 
int main() 
{     
    int list[] = {1, 2, 3, 4, 5};     
    perm(list, 0, 4);     
    printf("total:%d\n", n);     
    return 0; 
}  

运行结果显示n=120,但n=1以后我就不知道怎么回事了。
swap(&list[k], &list[i]); perm(list, k + 1, m); swap(&list[k], &list[i]);
第5次递归后,k>m了,执行
for(i = 0; i <= m; i++) printf("%d ", list[i]); printf("\n"); n++;
输出12345,然后n++。这之后应该执行perm函数后面的那个swap函数了吧,这时&list[k], &list[i]里的i是多少呢?接下来又怎么回事呢。

来补个坑

上面的问题总算搞懂了。

打印hallo的语句不在for语句里面。。。

全排列以{A,B,C}为例:
第一次,A和A互换位置 (A和A互换位置,位置不变),还是A,{B,C}; {B,C}继续做全排列(递归);恢复A和A的位置。
第二次,A和B互换位置(第二个数与第一个数交换),变成B,{A,C}; {A,C}继续做全排列(递归);恢复A和B的位置。
第三次,A和C互换位置(第三个数与第一个数交换),变成C,{B,A}; {B,A}继续做全排列(递归);恢复A和C的位置。

这就是“将整组数中的所有的数分别与第一个数交换,这样就总是在处理后n-1个数的全排列。”

以上是deepin论坛里的网友给的解答,非常感谢他。原理正如他说的那样,但是我跟着代码演算的过程是这样的(相关链接里的第一个链接的程序,{1,2,3})


c&行列式_第1张图片
DeepinScreenshot.png

从原理到代码级别的实现还是有点难度啊,不过食用代码的过程我也吸收了不少营养(递归、全排列、用malloc动态分配内存)。

来点感悟

写程序是用代码实现人的想法,所以怎么把想法转变成代码呢,暂时觉得是这样的:设计main的草图)造main需要的零件)造零件需要的零件)....)组装零件)打磨打磨?加点润滑油?涂点漆?扔进垃圾桶?

相关链接

全排列算法原理和实现
n阶行列式计算

你可能感兴趣的:(c&行列式)