1. 程式人生 > >n階行列式計算----c語言實現(完結)

n階行列式計算----c語言實現(完結)

#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>//包含的標頭檔案不解釋
typedef bool int      //因為標準c裡邊沒有bool型別才這麼做
#define false 0
#define true 1
//定義幾個全域性變數,無奈之舉
int *c,  //將整個行列式的值存到c指向的空間裡
    n = 0,//記錄當前的行列式計算進行了多少步
    a, //方便傳遞行列式的階數
    sum = 0;   //記錄每一步行列式計算所累加的結果
int aq(int a)              //計算階乘的函式,就不多解釋了
{
    int s = 1;
    for (int i = 1; i <= a; i ++)
        s *= i;
    return s;
}
void swap(int *a, int *b)  //利用地址傳遞,交換兩個數的值
{
    int m = * a;
    * a = * b;
    *b = m;
}
bool sa(int *l) //計算在行列式計算過程中每一項前邊的符號是正還是負
{
    int n = 0;//n為行列式展開式每一項的逆序數
    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; //若為正,則返回false
    return true;//否則返回true
}
void perm(int *l, int k, int m) //整個程式裡邊的核心函式,找出在不同行不同列的所有組合
{
    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; //確定這一項的符號
        //輸出當前sum內的值(即到當前為止所得到的結果是多少)
        //輸出執行的完成程度(即當前執行的次數除以總次數)
        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, //一個輔助變數,在遞迴函式中將b指向的空間內的值進行全排列,也即行列式展開式不同組合的下標
        i, //迴圈中的輔助變數
        f, //在格式化輸出行列式的輔助變數
        e;//判斷是否退出程式的標誌位
    system("color 3e");//設定程式執行的前景色和背景色
u: system("cls");//清空螢幕
    printf("請輸入行列式的階數:\n");
    scanf("%d", &a);//獲取行列式的階數
    b = ( int *) malloc ( sizeof ( int ) * a ); //為變數申請空間
    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 );
}
過了很久之後,加了一些註釋,若是各位看官還有不清楚的請百度去,或者直接問我,願意解答。