用C實現(xiàn)矩陣寫的不像前面的鏈表等數(shù)據(jù)結(jié)構(gòu)寫的順利,因為矩陣里面的內(nèi)容多的多嚣艇,特別是計算部分承冰,著實花了幾天時間。目前還有一小部分算法還沒有實現(xiàn)食零,后續(xù)會補上困乒。
github源碼 文件夾為Matrix,主要有兩個文件:Matrix.c 贰谣、Matrix.h
矩陣的數(shù)據(jù)結(jié)構(gòu)的設(shè)計
矩陣是存儲的一組或多組數(shù)據(jù)娜搂,所以毫無疑問,應(yīng)使用順序存儲的方式存儲數(shù)據(jù)元素吱抚。矩陣最直觀的表示方式是用多維數(shù)組來表示百宇,缺點在于不夠活型酥,使用前必須確定其長度乌企,而且維度變換時十分麻煩。綜合了諸多因素瓢对,我設(shè)計如下的主要使用堆的動態(tài)的矩陣數(shù)據(jù)結(jié)構(gòu):
typedef struct Dshape{
int shape[4]; //最多四維
}Dshape;
typedef struct Matrix{
double *array;
Dshape dshape; //數(shù)組結(jié)構(gòu)
int length; //長度
int size; //空間大小
}Matrix;
我們看結(jié)構(gòu)體Matrix憋肖,里面首先是一個double型的指針*array因痛,這用于指向的矩陣元素存儲塊的首地址。在剛開始的設(shè)計版本中岸更,我把指針的類型設(shè)置為void型鸵膏,這樣*array可以指向任何類型的數(shù)據(jù)塊,但是在存取時需要類型判斷和轉(zhuǎn)換怎炊,比較麻煩谭企,而且在后面矩陣的一些算法如求行列式等就更為麻煩,所以最終設(shè)定Matrix的元素類型為double型评肆。
Dshape dshape定義了矩陣的結(jié)構(gòu)债查,可以看到struct Dshape里定義的是一個int型的大小為4的數(shù)組,這個數(shù)組用來存儲矩陣的結(jié)構(gòu)信息瓜挽,4個int型代表維數(shù)盹廷,最多支持4維。例如久橙,一個2X2(二行二列)的二維矩陣的dshape為{0俄占,0,2淆衷,2}缸榄。要注意的是一個設(shè)定:一維矩陣,即只有一行祝拯,假設(shè)這一行的元素有3個甚带,那么該一維矩陣的dshape為{0,0,0欲低,3}辕宏,而不是{0畜晰,0砾莱,1,3}凄鼻。還有一種情況腊瑟,一列元素,假設(shè)有n個块蚌,那么闰非,該列的dshape為{0,0峭范,n财松,1}。把int型數(shù)組用struct包裝一下纱控,這是一個小技巧辆毡,好處是struct可以直接整體賦值,在代碼中就會簡潔一些甜害,不必再用循環(huán)依次對數(shù)組賦值舶掖。存放多維矩陣元素只用一塊連續(xù)的存儲區(qū)域,而矩陣的結(jié)構(gòu)由dshape來決定尔店,最大的好處在于眨攘,更改數(shù)組的維數(shù)、結(jié)構(gòu)非常的容易嚣州,不需要改矩陣元素的存儲區(qū)域鲫售,只要改一下dshape的值就可以了。
int length保存了矩陣*array里數(shù)據(jù)元素的長度该肴, int size則保存了矩陣*array所占空間的大小情竹。大部分情況下,這兩個值是相等的沙庐,但在有些時候鲤妥,不相等,比如說做刪除矩陣里的元素操作時拱雏,我只改變了length的大小棉安,而size不變。
矩陣的創(chuàng)建
矩陣創(chuàng)建時首先要確定dshape铸抑,dshape有三種初始化方式:
例如要創(chuàng)建的矩陣的結(jié)構(gòu)為4行5列的二維矩陣贡耽,
方法一:
Dshape dshape;
dshape.shape[0] = 0;
dshape.shape[1] = 0;
dshape.shape[2] = 4;
dshape.shape[3] = 5;
方法二:
int a[]={0,0,4,5};
Dshape dshape;
initDshape(&dshape,a);
方法三:
Matrix *a; //a已是一個4行5列的二維矩陣
Dshape dshape;
dshape = a->dshape;
矩陣的創(chuàng)建構(gòu)造了以下函數(shù):
1.從數(shù)據(jù)創(chuàng)建數(shù)組
Matrix *creatAsMatrixFromDatas(double *data,int data_len, Dshape dshape);
淺拷貝,數(shù)據(jù)不開辟新的內(nèi)存空間蒲赂,array的地址就指向data的地址阱冶。
2.從數(shù)據(jù)創(chuàng)建數(shù)組,深拷貝,數(shù)據(jù)開辟新的內(nèi)存空間滥嘴,從data復(fù)制一份數(shù)據(jù)木蹬。
Matrix *creatMatrixFromDatas(double *data,int data_len, Dshape dshape);
使用示例:
Matrix *m = NULL;
m = creatMatrixFromDatas(data,data_len,dshape);
3.創(chuàng)建一個單一值的矩陣
Matrix *creatMatrixFromValue(double value, Dshape dshape);
4.指定初始值和步長,創(chuàng)建等間隔值的矩陣若皱,結(jié)束的值根據(jù)矩陣的大小變化
Matrix *creatMatrixFromArange(double startVal, double stepVal,Dshape dshape);
5.指定初始值和結(jié)束值镊叁,創(chuàng)建等間隔的矩陣,間隔根據(jù)矩陣的大小變化
Matrix *creatMatrixFromLinspace(double startVal, double endVal,Dshape dshape);
6.創(chuàng)建全0矩陣
Matrix *creatZerosMatrix(Dshape dshape);
7.創(chuàng)建全1矩陣
Matrix *creatOnesMatrix(Dshape dshape);
8.創(chuàng)建二維單位矩陣走触,要求dshape里行數(shù)與列數(shù)相等晦譬。
Matrix *creatIdentitySecondOrderMatrix(Dshape dshape);
矩陣的shape相關(guān)的函數(shù)
1.初始化dshape
void initDshape(Dshape *dshape,int *shapeval);
2.修改dshape
int reshape(Matrix *m,Dshape dshape);
3.獲取矩陣的維數(shù)
int getMatrixNdim(Matrix *m);
矩陣打印的函數(shù)
1.打印矩陣的shape
void printShape(Matrix *m);
2.打印矩陣
void printarray(Matrix *m);
矩陣的清空與銷毀函數(shù)
1.清空矩陣
void clearMatrix(Matrix *m);
2.銷毀矩陣
void destroyMatrix(Matrix *m);
獲取矩陣的元素
1.獲取矩陣的元素
int getMatrixElem(Matrix *m,int dimen0,int dimen1,int dimen2,int dimen3,double *elem);
dimen表示維數(shù),例如要獲取3X3的二維矩陣m中第(1,1)個元素(下標從0開始計算):
double elem;
getMatrixElem(m,0,0,1,1,&elem);
函數(shù)返回的int為狀態(tài)指示用的互广,一般都設(shè)定為返回0為操作成功敛腌,返回-1為操作失敗。
2.修改矩陣的元素
int modifyMatrixElem(Matrix *m,int dimen0,int dimen1,int dimen2,int dimen3,double elem);
3.獲取矩陣的連續(xù)幾行
Matrix *getSecondOrderMatrixRows(Matrix *m,int startRow,int endRow);
下標從0開始計算惫皱,返回一個新的矩陣像樊,用法示例:
Matrix *n = NULL;
n = getSecondOrderMatrixRows(m,0,1); //獲取矩陣m的第一行
4.獲取矩陣的連續(xù)幾列
Matrix *getSecondOrderMatrixColumes(Matrix *m,int startColume,int endColume);
5.獲取矩陣的子矩陣
Matrix *getSecondOrderSubMatrix(Matrix *m,int startRow,int startColume,int endRow,int endColume);
6.獲取矩陣刪除指定一行和一列之后的子矩陣
Matrix *getSecondOrderLeftSubMatrix(Matrix *m,int row,int colume);
矩陣的基本操作
1.復(fù)制矩陣
Matrix *copyMatrix(Matrix *m);
2.轉(zhuǎn)置矩陣
int transposeSecondOrderMatrix(Matrix *m);
3.求二維矩陣的跡
double getSecondOrderMatrixTrace(Matrix *m);
4.交換二維矩陣的兩行
int swapSecondOrderMatrixRow(Matrix *m, int row1,int row2);
5.交換二維矩陣的兩列
int swapSecondOrderMatrixColume(Matrix *m, int colume1,int colume2);
6.二維矩陣的指定一行加、減逸吵、乘凶硅、除一個系數(shù)k
int kAddSecondOrderMatrixRow(Matrix *m, int row,double k);
int kSubSecondOrderMatrixRow(Matrix *m, int row,double k);
int kMulSecondOrderMatrixRow(Matrix *m, int row,double k);
int kDivSecondOrderMatrixRow(Matrix *m, int row,double k);
7.二維矩陣的指定一列加、減扫皱、乘足绅、除一個系數(shù)k
int kAddSecondOrderMatrixColume(Matrix *m, int colume,double k);
int kSubSecondOrderMatrixColume(Matrix *m, int colume,double k);
int kMulSecondOrderMatrixColume(Matrix *m, int colume,double k);
int kDivSecondOrderMatrixColume(Matrix *m, int colume,double k);
8.二維矩陣的指定兩行元素一一對應(yīng)相加減乘除:row1 = row1 +-*/ row2
int addSecondOrderMatrixRows(Matrix *m, int row1,int row2);
int subSecondOrderMatrixRows(Matrix *m, int row1,int row2);
int mulSecondOrderMatrixRows(Matrix *m, int row1,int row2);
int divSecondOrderMatrixRows(Matrix *m, int row1,int row2);
9.二維矩陣的指定兩列元素一一對應(yīng)相加減乘除:colume1 = colume1 +-*/ colume2
int addSecondOrderMatrixColumes(Matrix *m, int colume1, int colume2);
int subSecondOrderMatrixColumes(Matrix *m, int colume1, int colume2);
int mulSecondOrderMatrixColumes(Matrix *m, int colume1, int colume2);
int divSecondOrderMatrixColumes(Matrix *m, int colume1, int colume2);
10.刪除二維矩陣的指定行數(shù)
int deleteSecondOrderMatrixRows(Matrix *m,int startRow,int endRow);
11.刪除二維矩陣的指定列數(shù)
int deleteSecondOrderMatrixColumes(Matrix *m,int startColume,int endColume);
12.刪除二維矩陣的指定一行和一列
int deleteSecondOrderMatrixRowAndColume(Matrix *m,int row,int colume);
13.按行拼接兩個矩陣,要求兩個矩陣一行的元素數(shù)目要相等
int spliceSecondOrderMatrixRow(Matrix *m1,Matrix *m2);
14.按列拼接兩個矩陣韩脑,要求兩個矩陣一列的元素數(shù)目要相等
int spliceSecondOrderMatrixColume(Matrix *m1,Matrix *m2);
15.二維矩陣整體加氢妈、減、乘段多、除一個系數(shù)k
int kAddMatrix(Matrix *m,double k);
int kSubMatrix(Matrix *m,double k);
int kMulMatrix(Matrix *m,double k);
int kDivMatrix(Matrix *m,double k);
16.兩個矩陣相加首量,得到一個新的矩陣,要求兩個矩陣的shape要一致
Matrix *addSecondOrderMatrixs(Matrix *m1,Matrix *m2);
17.兩個矩陣相減进苍,得到一個新的矩陣加缘,要求兩個矩陣的shape要一致
Matrix *subSecondOrderMatrixs(Matrix *m1,Matrix *m2);
18.兩個矩陣求點乘,得到一個新的矩陣觉啊,要求兩個矩陣的shape要一致
Matrix *dotSecondOrderMatrixs(Matrix *m1,Matrix *m2);
19.兩個矩陣求叉乘拣宏,m1為m X n矩陣,m2為n X p矩陣杠人,乘積返回一個m X p矩陣
Matrix *mulSecondOrderMatrixs(Matrix *m1,Matrix *m2);
矩陣的高級操作
1.求一個二維方陣的行列式
int detSquareMatrixs(Matrix *m,double *result);
2.求二維方陣中指定元素的代數(shù)余子式
int getSquareMatrixElemAlgebraicComplement(Matrix *m,int row,int colume,double *result);
3.求二維方陣中指定一行元素的代數(shù)余子式
Matrix *getSquareMatrixRawAlgebraicComplement(Matrix *m,int row);
4.求二維方陣的伴隨矩陣
Matrix *getSquareMatrixAdjointMatrix(Matrix *m);
5.求解二維方陣的逆矩陣
Matrix *invSquareMatrix(Matrix *m);
6.求二維矩陣的最簡階梯陣
Matrix *getEchelonMatrix(Matrix *m);
7.求二維矩陣的秩
int getSecondOrderMatrixRank(Matrix *m ,int *rank);
8.求齊次線性方程組AX=0的解,結(jié)果為全0矩陣或基礎(chǔ)解系構(gòu)成的矩陣
Matrix *solveHomoLinearEquations(Matrix *A);
9.求非齊次線性方程組AX=B的解勋乾,返回NULL表示無解宋下;一列矩陣表示唯一解;多列矩陣中辑莫,除了最后一列為特解学歧,前面幾列為基礎(chǔ)解系
Matrix *solveNonHomoLinearEquations(Matrix *A, Matrix *B);
10.求矩陣的無窮范數(shù)
double getMatrixInfNorm(Matrix *m);
11.求矩陣的L0范數(shù)
double getMatrixL0Norm(Matrix *m);
12.求矩陣的L1范數(shù)
double getMatrixL1Norm(Matrix *m);
13.求矩陣的L2范數(shù)
double getMatrixL2Norm(Matrix *m);
14.求矩陣的L21范數(shù)
double getMatrixL21Norm(Matrix *m);
To do list
1.求特征值與特征向量
2.奇異值分解(SVD)
3.QR分解
4.最小二乘解
5.矩陣的核范數(shù)