花了半天時間,寫了這個n階行列式計算的程序,應該算是比較優美吧,有很多地方多次做了優化,程序占用內存不是很大,要是說小吧,也不合適,因為里邊有一個遞歸,而且遞歸的深度還比較深。時間復雜度具體沒有細看,應該不會太大。
看我的程序運行的截圖:
ok,先看程序。
C Code
看我的程序運行的截圖:
ok,先看程序。
C Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
105
106
107 |
#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/( a q( 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 ); } |
過了很久之后,加了一些注釋,若是各位看官還有不清楚的請百度去,或者直接問我,願意解答。
里邊還有好多地方可以調整,若有更好的調整方法,請聯系我,不勝感激。
里邊還有好多地方可以調整,若有更好的調整方法,請聯系我,不勝感激。