C实现矩阵数据结构与计算

用C实现矩阵写的不像前面的链表等数据结构写的顺利,因为矩阵里面的内容多的多,特别是计算部分,着实花了几天时间。目前还有一小部分算法还没有实现,后续会补上。
github源码 文件夹为Matrix,主要有两个文件:Matrix.c 、Matrix.h

矩阵的数据结构的设计

矩阵是存储的一组或多组数据,所以毫无疑问,应使用顺序存储的方式存储数据元素。矩阵最直观的表示方式是用多维数组来表示,缺点在于不够活,使用前必须确定其长度,而且维度变换时十分麻烦。综合了诸多因素,我设计如下的主要使用堆的动态的矩阵数据结构:

typedef struct Dshape{
    int shape[4]; //最多四维
}Dshape;

typedef struct Matrix{
    double *array;  
    Dshape dshape; //数组结构
    int length; //长度
    int size; //空间大小
}Matrix;

我们看结构体Matrix,里面首先是一个double型的指针*array,这用于指向的矩阵元素存储块的首地址。在刚开始的设计版本中,我把指针的类型设置为void型,这样*array可以指向任何类型的数据块,但是在存取时需要类型判断和转换,比较麻烦,而且在后面矩阵的一些算法如求行列式等就更为麻烦,所以最终设定Matrix的元素类型为double型。
Dshape dshape定义了矩阵的结构,可以看到struct Dshape里定义的是一个int型的大小为4的数组,这个数组用来存储矩阵的结构信息,4个int型代表维数,最多支持4维。例如,一个2X2(二行二列)的二维矩阵的dshape为{0,0,2,2}。要注意的是一个设定:一维矩阵,即只有一行,假设这一行的元素有3个,那么该一维矩阵的dshape为{0,0,0,3},而不是{0,0,1,3}。还有一种情况,一列元素,假设有n个,那么,该列的dshape为{0,0,n,1}。把int型数组用struct包装一下,这是一个小技巧,好处是struct可以直接整体赋值,在代码中就会简洁一些,不必再用循环依次对数组赋值。存放多维矩阵元素只用一块连续的存储区域,而矩阵的结构由dshape来决定,最大的好处在于,更改数组的维数、结构非常的容易,不需要改矩阵元素的存储区域,只要改一下dshape的值就可以了。
int length保存了矩阵*array里数据元素的长度, int size则保存了矩阵*array所占空间的大小。大部分情况下,这两个值是相等的,但在有些时候,不相等,比如说做删除矩阵里的元素操作时,我只改变了length的大小,而size不变。

矩阵的创建

矩阵创建时首先要确定dshape,dshape有三种初始化方式:
例如要创建的矩阵的结构为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;

矩阵的创建构造了以下函数:
1.从数据创建数组

Matrix *creatAsMatrixFromDatas(double *data,int data_len, Dshape dshape);

浅拷贝,数据不开辟新的内存空间,array的地址就指向data的地址。

2.从数据创建数组,深拷贝,数据开辟新的内存空间,从data复制一份数据。

Matrix *creatMatrixFromDatas(double *data,int data_len, Dshape dshape);

使用示例:

Matrix *m = NULL;
m = creatMatrixFromDatas(data,data_len,dshape);

3.创建一个单一值的矩阵

Matrix *creatMatrixFromValue(double value, Dshape dshape);

4.指定初始值和步长,创建等间隔值的矩阵,结束的值根据矩阵的大小变化

Matrix *creatMatrixFromArange(double startVal, double stepVal,Dshape dshape);

5.指定初始值和结束值,创建等间隔的矩阵,间隔根据矩阵的大小变化

Matrix *creatMatrixFromLinspace(double startVal, double endVal,Dshape dshape);

6.创建全0矩阵

Matrix *creatZerosMatrix(Dshape dshape);

7.创建全1矩阵

Matrix *creatOnesMatrix(Dshape dshape);

8.创建二维单位矩阵,要求dshape里行数与列数相等。

Matrix *creatIdentitySecondOrderMatrix(Dshape dshape);

矩阵的shape相关的函数

1.初始化dshape

void initDshape(Dshape *dshape,int *shapeval);

2.修改dshape

int reshape(Matrix *m,Dshape dshape);

3.获取矩阵的维数

int getMatrixNdim(Matrix *m);

矩阵打印的函数

1.打印矩阵的shape

void printShape(Matrix *m);

2.打印矩阵

void printarray(Matrix *m);

矩阵的清空与销毁函数

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表示维数,例如要获取3X3的二维矩阵m中第(1,1)个元素(下标从0开始计算):

double elem;
getMatrixElem(m,0,0,1,1,&elem);

函数返回的int为状态指示用的,一般都设定为返回0为操作成功,返回-1为操作失败。

2.修改矩阵的元素

int modifyMatrixElem(Matrix *m,int dimen0,int dimen1,int dimen2,int dimen3,double elem);

3.获取矩阵的连续几行

Matrix *getSecondOrderMatrixRows(Matrix *m,int startRow,int endRow);

下标从0开始计算,返回一个新的矩阵,用法示例:

Matrix *n = NULL;
n = getSecondOrderMatrixRows(m,0,1); //获取矩阵m的第一行

4.获取矩阵的连续几列

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.复制矩阵

Matrix *copyMatrix(Matrix *m);

2.转置矩阵

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.二维矩阵的指定一行加、减、乘、除一个系数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.二维矩阵的指定一列加、减、乘、除一个系数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.二维矩阵的指定两行元素一一对应相加减乘除: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.二维矩阵的指定两列元素一一对应相加减乘除: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.删除二维矩阵的指定行数

int deleteSecondOrderMatrixRows(Matrix *m,int startRow,int endRow);

11.删除二维矩阵的指定列数

int deleteSecondOrderMatrixColumes(Matrix *m,int startColume,int endColume);

12.删除二维矩阵的指定一行和一列

int deleteSecondOrderMatrixRowAndColume(Matrix *m,int row,int colume);

13.按行拼接两个矩阵,要求两个矩阵一行的元素数目要相等

int spliceSecondOrderMatrixRow(Matrix *m1,Matrix *m2);

14.按列拼接两个矩阵,要求两个矩阵一列的元素数目要相等

int spliceSecondOrderMatrixColume(Matrix *m1,Matrix *m2);

15.二维矩阵整体加、减、乘、除一个系数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.求二维方阵中指定元素的代数余子式

int getSquareMatrixElemAlgebraicComplement(Matrix *m,int row,int colume,double *result);

3.求二维方阵中指定一行元素的代数余子式

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的解,结果为全0矩阵或基础解系构成的矩阵

Matrix *solveHomoLinearEquations(Matrix *A);

9.求非齐次线性方程组AX=B的解,返回NULL表示无解;一列矩阵表示唯一解;多列矩阵中,除了最后一列为特解,前面几列为基础解系

Matrix *solveNonHomoLinearEquations(Matrix *A, Matrix *B);

10.求矩阵的无穷范数

double getMatrixInfNorm(Matrix *m);

11.求矩阵的L0范数

double getMatrixL0Norm(Matrix *m);

12.求矩阵的L1范数

double getMatrixL1Norm(Matrix *m);

13.求矩阵的L2范数

double getMatrixL2Norm(Matrix *m);

14.求矩阵的L21范数

double getMatrixL21Norm(Matrix *m);

To do list

1.求特征值与特征向量
2.奇异值分解(SVD)
3.QR分解
4.最小二乘解
5.矩阵的核范数

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容