偶尔在算法课本上面看到矩阵相乘的算法,联想到自己曾经在蓝桥杯系统上曾经做过一道矩阵相乘的题目,当时用的是普通的矩阵相乘的方法,效率极低,勉强通过编译。所以决定研究一下Strassen矩阵相乘算法,由于本人比较懒,所以就从网上找了一些相关的资料供大家参考;

下面内容均转自 https://i.cnblogs.com/EditPosts.aspx?opt=1 ,如需转载请注明出处,https://www.cnblogs.com/zhuchenglin/p/6555495.html

题目描述

请编程实现矩阵乘法,并考虑当矩阵规模较大时的优化方法。

思路分析

根据wikipedia上的介绍:两个矩阵的乘法仅当第一个矩阵B的列数和另一个矩阵A的行数相等时才能定义。如A是m×n矩阵和B是n×p矩阵,它们的乘积AB是一个m×p矩阵,它的一个元素其中 1 ≤ i ≤ m, 1 ≤ j ≤ p。

值得一提的是,矩阵乘法满足结合律和分配率,但并不满足交换律,如下图所示的这个例子,两个矩阵交换相乘后,结果变了:

下面咱们来具体解决这个矩阵相乘的问题。

解法一、暴力解法

其实,通过前面的分析,我们已经很明显的看出,两个具有相同维数的矩阵相乘,其复杂度为O(n^3),参考代码如下:

  1. //矩阵乘法,3个for循环搞定
  2. void Mul(int** matrixA, int** matrixB, int** matrixC)
  3. {
  4. for(int i = 0; i < 2; ++i)
  5. {
  6. for(int j = 0; j < 2; ++j)
  7. {
  8. matrixC[i][j] = 0;
  9. for(int k = 0; k < 2; ++k)
  10. {
  11. matrixC[i][j] += matrixA[i][k] * matrixB[k][j];
  12. }
  13. }
  14. }
  15. }

解法二、Strassen算法

在解法一中,我们用了3个for循环搞定矩阵乘法,但当两个矩阵的维度变得很大时,O(n^3)的时间复杂度将会变得很大,于是,我们需要找到一种更优的解法。

一般说来,当数据量一大时,我们往往会把大的数据分割成小的数据,各个分别处理。遵此思路,如果丢给我们一个很大的两个矩阵呢,是否可以考虑分治的方法循序渐进处理各个小矩阵的相乘,因为我们知道一个矩阵是可以分成更多小的矩阵的。

如下图,当给定一个两个二维矩阵A B时:

这两个矩阵A B相乘时,我们发现在相乘的过程中,有8次乘法运算,4次加法运算:

矩阵乘法的复杂度主要就是体现在相乘上,而多一两次的加法并不会让复杂度上升太多。故此,我们思考,是否可以让矩阵乘法的运算过程中乘法的运算次数减少,从而达到降低矩阵乘法的复杂度呢?答案是肯定的。

1969年,德国的一位数学家Strassen证明O(N^3)的解法并不是矩阵乘法的最优算法,他做了一系列工作使得最终的时间复杂度降低到了O(n^2.80)。

他是怎么做到的呢?还是用上文A B两个矩阵相乘的例子,他定义了7个变量:

如此,Strassen算法的流程如下:

  • 两个矩阵A B相乘时,将A, B, C分成相等大小的方块矩阵:

  • 可以看出C是这么得来的:

  • 现在定义7个新矩阵(读者可以思考下,这7个新矩阵是如何想到的):

  • 而最后的结果矩阵C 可以通过组合上述7个新矩阵得到:

表面上看,Strassen算法仅仅比通用矩阵相乘算法好一点,因为通用矩阵相乘算法时间复杂度是,而Strassen算法复杂度只是。但随着n的变大,比如当n >> 100时,Strassen算法是比通用矩阵相乘算法变得更有效率。

具体实现的伪代码如下:

Strassen (N,MatrixA,MatrixB,MatrixResult)

    //splitting input Matrixes, into 4 submatrices each.
for i <- 0 to N/2
for j <- 0 to N/2
A11[i][j] <- MatrixA[i][j]; //a矩阵块
A12[i][j] <- MatrixA[i][j + N / 2]; //b矩阵块
A21[i][j] <- MatrixA[i + N / 2][j]; //c矩阵块
A22[i][j] <- MatrixA[i + N / 2][j + N / 2];//d矩阵块 B11[i][j] <- MatrixB[i][j]; //e 矩阵块
B12[i][j] <- MatrixB[i][j + N / 2]; //f 矩阵块
B21[i][j] <- MatrixB[i + N / 2][j]; //g 矩阵块
B22[i][j] <- MatrixB[i + N / 2][j + N / 2]; //h矩阵块
//here we calculate M1..M7 matrices .
//递归求M1
HalfSize <- N/2
AResult <- A11+A22
BResult <- B11+B22
Strassen( HalfSize, AResult, BResult, M1 ); //M1=(A11+A22)*(B11+B22) p5=(a+d)*(e+h)
//递归求M2
AResult <- A21+A22
Strassen(HalfSize, AResult, B11, M2); //M2=(A21+A22)B11 p3=(c+d)*e
//递归求M3
BResult <- B12 - B22
Strassen(HalfSize, A11, BResult, M3); //M3=A11(B12-B22) p1=a*(f-h)
//递归求M4
BResult <- B21 - B11
Strassen(HalfSize, A22, BResult, M4); //M4=A22(B21-B11) p4=d*(g-e)
//递归求M5
AResult <- A11+A12
Strassen(HalfSize, AResult, B22, M5); //M5=(A11+A12)B22 p2=(a+b)*h
//递归求M6
AResult <- A21-A11
BResult <- B11+B12
Strassen( HalfSize, AResult, BResult, M6); //M6=(A21-A11)(B11+B12) p7=(c-a)(e+f)
//递归求M7
AResult <- A12-A22
BResult <- B21+B22
Strassen(HalfSize, AResult, BResult, M7); //M7=(A12-A22)(B21+B22) p6=(b-d)*(g+h) //计算结果子矩阵
C11 <- M1 + M4 - M5 + M7; C12 <- M3 + M5; C21 <- M2 + M4; C22 <- M1 + M3 - M2 + M6;
//at this point , we have calculated the c11..c22 matrices, and now we are going to
//put them together and make a unit matrix which would describe our resulting Matrix.
for i <- 0 to N/2
for j <- 0 to N/2
MatrixResult[i][j] <- C11[i][j];
MatrixResult[i][j + N / 2] <- C12[i][j];
MatrixResult[i + N / 2][j] <- C21[i][j];
MatrixResult[i + N / 2][j + N / 2] <- C22[i][j];

Strassen 矩阵相乘算法(转)的更多相关文章

  1. Java实验项目四——多线程矩阵相乘算法的设计

    Program:多线程矩阵相乘算法的设计 Description:利用多线程实现矩阵相乘,因为各个线程的运算互不影响, 所以不用使用锁,代码如下: thread.OperateMatrix类,实现矩阵 ...

  2. C语言 · 矩阵相乘 · 算法提高

    算法提高 矩阵相乘   时间限制:1.0s   内存限制:256.0MB      问题描述 小明最近在为线性代数而头疼,线性代数确实很抽象(也很无聊),可惜他的老师正在讲这矩阵乘法这一段内容. 当然 ...

  3. 实现两个矩阵相乘的C语言程序

    程序功能:实现两个矩阵相乘的C语言程序,并将其输出 代码如下: #include "stdafx.h" #include "windows.h" void Mu ...

  4. Java实现 蓝桥杯 算法提高 矩阵相乘

    算法提高 矩阵相乘 时间限制:1.0s 内存限制:256.0MB 问题描述 小明最近在为线性代数而头疼,线性代数确实很抽象(也很无聊),可惜他的老师正在讲这矩阵乘法这一段内容. 当然,小明上课打瞌睡也 ...

  5. 利用Hadoop实现超大矩阵相乘之我见(二)

    前文 在<利用Hadoop实现超大矩阵相乘之我见(一)>中我们所介绍的方法有着“计算过程中文件占用存储空间大”这个缺陷,本文中我们着重解决这个问题. 矩阵相乘计算思想 传统的矩阵相乘方法为 ...

  6. 利用Hadoop实现超大矩阵相乘之我见(一)

    前记 最近,公司一位挺优秀的总务离职,欢送宴上,她对我说“你是一位挺优秀的程序员”,刚说完,立马道歉说“对不起,我说你是程序员是不是侮辱你了?”我挺诧异,程序员现在是很低端,很被人瞧不起的工作吗?或许 ...

  7. Python+MapReduce实现矩阵相乘

    算法原理 map阶段 在map阶段,需要做的是进行数据准备.把来自矩阵A的元素aij,标识成p条<key, value>的形式,key="i,k",(其中k=1,2,. ...

  8. java 写一个 map reduce 矩阵相乘的案例

    1.写一个工具类用来生成 map reduce 实验 所需 input 文件 下面两个是原始文件 matrix1.txt 1 2 -2 0 3 3 4 -3 -2 0 2 3 5 3 -1 2 -4 ...

  9. dp方法论——由矩阵相乘问题学习dp解题思路

    前篇戳:dp入门——由分杆问题认识动态规划 导语 刷过一些算法题,就会十分珍惜“方法论”这种东西.Leetcode上只有题目.讨论和答案,没有方法论.往往答案看起来十分切中要害,但是从看题目到得到思路 ...

随机推荐

  1. idea的debug模式启动运行慢

    今天发现idea的debug模式启动运行特别慢,查找原因是因为在多个方法上打了断点导致,关闭断点问题解决. 关闭断点方法为: 

  2. docker安装mongodb并备份

    安装 官方镜像地址: https://hub.docker.com/_/mongo?tab=description 可以查看对应的dockerfile, 通过观察docker-entrypoint.s ...

  3. Velocity日期格式化

    1.pom.xml添加依赖 <dependency> <groupId>velocity-tools</groupId> <artifactId>vel ...

  4. 通过Comparable来实现对自身的比较

    import org.apache.commons.lang.builder.CompareToBuilder; import org.apache.commons.lang.builder.Equa ...

  5. GDAL指定自定义的金字塔目录

    缘起 对于一般的遥感影像文件,金字塔文件默认都是与影像文件放在同一个目录下,金字塔文件名一般与源影像文件名相同,但后缀名不同.或者金字塔内建于影像内部,但这不是这里所涉及的. 在使用ArcGIS桌面版 ...

  6. 【iOS】ARC-MRC下的单例及其应用

    单例的应用十分普遍,单例模式使一个类仅仅有一个实例. *易于供外界訪问. *方便控制实例个数,节约系统资源. *OC中的常见单例: 如:UIApplication,  NSNotificationCe ...

  7. 关于docker 意外停止,重新快速启动措施

    1. 我们要重启这个镜像,需要知道这个镜像ID,类似这个: 7079ff99e10ac326726a364348853c0e508cad8ce00ae970f3c800f172a40252 那么你可以 ...

  8. MySQL读取配置文件的顺序、启动方式、启动原理

    一.MySQL读取配置文件的顺序 读取顺序:/etc/my.cnf > /etc/mysql/my.cnf > /usr/etc/my.cnf > ~/.my.cnf 命令验证:[r ...

  9. 从MySQL全库备份中恢复某个库和某张表

    在Mysqldump官方工具中,如何只恢复某个库呢? 全库备份 [root@HE1 ~]# mysqldump -uroot -p --single-transaction -A --master-d ...

  10. 理解 CI 和 CD 之间的区别(翻译)

    博客搬迁至https://blog.wangjiegulu.com RSS订阅:https://blog.wangjiegulu.com/feed.xml 原文链接:https://blog.wang ...