荷兰国旗问题、矩阵相乘之Strassen算法

winograd 算法 winograd 算 法 的 代 码 立即下载

      第四十一章~四十二章:荷兰国旗问题、矩阵相乘之Strassen算法


前言

    本文要讲的两个问题:荷兰国旗和矩阵相乘之Strassen算法都跟分治法相关,故把这两个问题放到了一起。所谓分治,便是分而治之的意思,好比打战时面对敌人庞大的武装部队,采取避其主力,各个击破的策略。

    有何问题,欢迎随时不吝指正,thanks。



第十一章、荷兰国旗问题

题目描述

现有红白蓝三个不同颜色的小球,乱序排列在一起,请重新排列这些小球,使得红白蓝三色的同颜色的球在一起。这个问题之所以叫荷兰国旗,是因为我们可以将红白蓝三色小球想象成条状物,有序排列后正好组成荷兰国旗。如下图所示:

    


思路分析

    初看此题,我们貌似除了暴力解决并无好的办法,但联想到我们所熟知的快速排序算法呢?我们知道,快速排序时基于分治模式处理的,对一个典型子数组A[p...r]排序的分治过程为三个步骤:

  1. 分解:A[p..r]被划分为俩个(可能空)的子数组A[p ..q-1]和A[q+1 ..r],使得A[p ..q-1] <= A[q] <= A[q+1 ..r]
  2. .解决:通过递归调用快速排序,对子数组A[p ..q-1]和A[q+1 ..r]排序。
  3. 合并。

    也就是说,快速排序的主要思想便是依托于一个partition分治过程,每一趟排序的过程中,选取的主元都会把整个数组排列成一大一小的序列,继而递归排序完整个数组。

    如下伪代码所示:

快速排序算法的关键是PARTITION过程,它对A[p..r]进行就地重排:
PARTITION(A, p, r)
1  x ← A[r]
2  i ← p - 1
3  for j ← p to r - 1
4       do if A[j] ≤ x
5             then i ← i + 1
6                  exchange A[i] <-> A[j]
7  exchange A[i + 1] <-> A[r]
8  return i + 1

继而递归完成整个排序过程:

QUICKSORT(A, p, r)
1 if p < r
2    then q ← PARTITION(A, p, r)   //关键
3         QUICKSORT(A, p, q - 1)
4         QUICKSORT(A, q + 1, r)

举个例子如下:i 指向数组头部前一个位置,j 指向数组头部元素,j 在前,i 在后,双双从左向右移动。

① j 指向元素2时,i 也指向元素2,2与2互换不变
     i p/j
   2   8   7   1   3   5   6   4(主元)


② 于是j 继续后移,直到指向了1,1 <= 4,于是i++,i 指向8,故j 所指元素1 与 i 所指元素8 位置互换:
            i         j
   2   1   7   8   3   5   6   4


③ j 继续后移,指到了元素3,3 <= 4,于是同样i++,i 指向7,故j 所指元素3 与 i 所指元素7 位置互换:
                i         j
   2   1   3   8   7   5   6   4


④ j 一路后移,没有再碰到比主元4小的元素:
   i                   j
   2   1   3   8   7   5   6   4


⑤ 最后,A[i + 1] <-> A[r],即8与4交换,所以,数组最终变成了如下形式:
        2   1   3   4   7   5   6   8

ok,至此快速排序第一趟完成。就这样,4把整个数组分成了俩部分,2 1 3,7 5 6 8,再递归对这俩部分分别进行排序。

全部过程可以参看此文:快速排序算法,或看下我以前在学校里画的图:

    而我们面对的问题是,重新排列使得所有球排列成三个不同颜色的球,是否可以设定三个指针,借鉴partition过程呢?

解法一、partition分治

    通过前面的分析得知,这个问题,类似快排中partition过程。只是需要用到三个指针,一前begin,一中current,一后end,俩俩交换。

  1. current遍历,整个数组序列,current指1不动,
  2. current指0,与begin交换,而后current++,begin++,
  3. current指2,与end交换,而后,current不动,end--。

    为什么,第三步,current指2,与end交换之后,current不动了列,对的,正如algorithm__所说:current之所以与begin交换后,current++、begin++,是因为此无后顾之忧。而current与end交换后,current不动,end--,是因有后顾之忧。

    读者可以试想,你最终的目的无非就是为了让0、1、2有序排列,试想,如果第三步,current与end交换之前,万一end之前指的是0,而current交换之后,current此刻指的是0了,此时,current能动么?不能动啊,指的是0,还得与begin交换列。

    ok,说这么多,你可能不甚明了,直接引用下gnuhpc的图,就一目了然了:

    

    

    参考代码如下:

  1. //引用自gnuhpc  
  2. while( current<=end )        
  3. {             
  4.   if( array[current] ==0 )             
  5.    {                 
  6.       swap(array[current],array[begin]);                  
  7.       current++;                  
  8.       begin++;            
  9.    }             
  10.    else if( array[current] == 1 )            
  11.    {                 
  12.       current++;            
  13.    }   
  14.             
  15.    else //When array[current] =2   
  16.    {               
  17.       swap(array[current],array[end]);                
  18.       end--;            
  19.    }      
  20. }  

    本章完。



第四十二章:矩阵相乘之Strassen算法

题目描述

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

思路分析

    根据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算法是比通用矩阵相乘算法变得更有效率。

    如下图所示:

解法三、持续优化

    根据wikipedia上的介绍,后来,Coppersmith–Winograd 算法把 N* N大小的矩阵乘法的时间复杂度降低到了:,而2010年,Andrew Stothers再度把复杂度降低到了,一年后的2011年,Virginia Williams把复杂度最终定格为:

矩阵乘法的strassen算法(C++实现) 一般情况下矩阵乘法需要三个for循环,时间复杂度为O(n^3),现在我们将矩阵分块如图:( 来自MIT算法导论 ) 一般算法需要八次乘法 r = a * e + b * g ; s = a * f + b * h ; t = c * e + d * g; u = c * f + d * h; strassen将其变成7次乘法,因为大家都知道乘法比加减法消耗更多,所有时间复杂更高! strassen的处理是: 令: p1 = a * ( f - h ) p2 = ( a + b ) * h p3 = ( c +d ) * e p4 = d * ( g - e ) p5 = ( a + d ) * ( e + h ) p6 = ( b - d ) * ( g + h ) p7 = ( a - c ) * ( e + f ) 那么我们可以知道: r = p5 + p4 + p6 - p2 s = p1 + p2 t = p3 + p4 u = p5 + p1 - p3 - p7 立即下载

相关推荐

2025年MathorCup数学应用挑战赛【B题完整论文】附参考代码(免费分享)

摘。

RS_handy的博客 2694

程序员编程艺术PDF

《程序员编程艺术》 链接:https://pan.baidu.com/s/1XWk-E2DIJwYRlXNGwB_LHA 提取码:nptd

林夕07 1774

强网杯Web题ezphp解题全记录:利用PHP反序列化与条件竞争拿下服务器

本文详细解析了强网杯Web题目ezphp的解题过程,通过PHP反序列化与条件竞争漏洞的组合利用,成功获取服务器权限。文章深入剖析了反序列化链的构造、文件上传绕过技巧以及条件竞争的实际应用,为CTF选手和Web安全研究者提供了宝贵的实战经验。

weixin_29006187的博客 383

程序员编程艺术第四十一章~四十二章:荷兰国旗、矩阵相乘Strassen算法

第四十一章~四十二章:荷兰国旗问题、矩阵相乘之Strassen算法前言    本文要讲的两个问题:荷兰国旗和矩阵相乘之Strassen算法 都跟分治法相关,故把这两个问题放到了一起。所谓分治,便是分而治之的意思,好比打战时面对敌人的庞大武装,采取避其主力,各个击破的策略。    有何问题,欢迎随时不吝指正,thanks。第十一章、荷兰国旗问题题目描述现有红白蓝三个不同颜色的小球,乱序排列在一起,请

结构之法 算法之道 6万+

【ROS学习笔记】13.ROS中的坐标管理系统

文章目录1 机器人中的坐标变换2 TF功能包TF坐标变换如何实现?TF的一个小案例3 小程序:小海龟跟随实验打开小程序查看当前的TF树坐标相对位置关系可视化1(tf_echo)坐标相对位置关系可视化2(rviz) 本节学习ROS中的坐标管理系统。 (部分图摘自:b站【古月居】古月·ROS入门21讲) 1 机器人中的坐标变换 机器人运动学的核心,描述任意两个坐标系之中任意两个向量之间的变换,可以用一个4×4的变换矩阵(Transformation Matrices)来描述它的平移和旋转变化。 变换矩阵中有包括

takedachia的博客 4338

Linux下CUDA 11.8与vllm的完美搭配:从环境配置到避坑指南

本文详细介绍了在Linux系统中为CUDA 11.8环境部署vLLM的完整实战指南。针对cu118与vLLM的版本兼容性核心问题,提供了从Python、PyTorch版本选择,到关键依赖vllm-nccl-cu11的安装避坑,以及环境调优、生产级容器化部署的全面解决方案,帮助开发者高效构建稳定的大模型推理服务。

weixin_29095049的博客 308

Strassen:一种高效的矩阵相乘算法

Q1:如何提高矩阵相乘效率? 矩阵乘法是种极其耗时的运算。 以C = A • B为例,其中A和B都是 n x n 的方阵。根据矩阵乘法的定义,计算过程如下: A1: 简单分治法 前提:假定A,B都是n等于2的次幂的方阵 基本思路:计算C=A*B时,将C,A,B矩阵进行分块操作,对每个分块的矩阵进行乘法运 算,运算完毕后重新对得到的C11,C12,C21,C22进行组合操作。 确定递归终止条件:当分块矩阵得到的阶数为1 时,得到的C即是A和B中两个元素的乘积。 每个公式需要计算两次矩阵乘法和一次矩阵加法,

weixin_40982849的博客 3755

数字锁相环的原理与FPGA实现

数字锁相环是锁相环电路的全数字实现。锁相环电路能够实现对输入信号的相位进行跟踪,进而在噪声中提取纯净的有用信号。以上就是今天要讲的内容,本文简单地介绍了锁相环的原理,然后,在Vivado仿真平台上,通过verilog做仿真验证。最终仿真结果能够实现锁定,但锁定时间较长,表明参数仍可做调整。

weixin_45857378的博客 8510

《算法导论》学习心得(二)—— 矩阵乘法之Strassen算法

在开始之前,请点击下载源码。提起矩阵乘法,你也许会说不就是三次循环就解决问题了吗,这有什么好说的。是啊,三个循环确实是完事了,时间效率是O(n^3),这是我们上第一节线代老师就清清楚楚的告诉我们的,但是他没有告诉你还有比这更好的矩阵乘法,时间效率为O(n^{log_2 7}) = O(n^{2.807}),也许你觉得这没有什么,就提高了0.2几,没啥,但是你想过没有,当N=100,10000的时候呢,Strassen算法和传统方法又有多少差别呢,让我们来看一下Strassen算法和传统方法的效率对比图:

学习之旅 6033

以太网测试用例(光模块线缆、网卡类设备、交换类设备)

LeCroy力科网络测试相关的测试用例分享:光模块/DAC/ACC/AEC/AOC测试,网卡类产品测试/GPU/DPU/SmartNIC,交换类产品测试。涉及物理层的FEC,SKEW,Tx/Rx Taps和Layer23层的网络性能测试/吞吐量延迟抖动丢包率背靠背性能,以及RDMA带状况的网络协议分析。同步提供400G高速的以太网的损伤,提供定量,可重复的负面压力测试环境。

专注有线以太网性能测试--丹麦信雅纳网络(Xena Networks) 1996

华为OD机试真题 新系统【进制转换后自定义排序】

华为OD机试 新系统真题【进制转换后自定义排序】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【进制转换后自定义排序】多语言题解。

qq_45776114的博客 597

Winograd

from:Coppersmith–Winograd algorithm - HandWiki Inlinear algebra, theCoppersmith–Winograd algorithm, named after Don Coppersmith andShmuel Winograd, was the asymptotically fastest knownmatrix multiplication algorithmfrom 1990 until 2010. It can multi...

maxzcl的博客 645

基于NB-IoT的智慧路灯监控系统(NB-IoT专栏—实战篇1:项目简介)

基于NB-IoT技术的城市道路智慧路灯监控系统,在每个照明节点上安装一个集成了NB-IoT模组的单灯控制器,单灯控制器再经运营商的网络,与路灯控制平台实现双向通信,路灯控制平台直接对每个灯进行控制,包括开关灯控制、光照检测、自动调节明暗、电耗分析等操作。

不脱发的程序猿 5万+

程序员编程艺术第四十一章 四十二章 荷兰国旗 矩阵相乘Strassen算法

程序员编程艺术第四十一章 四十二章 荷兰国旗 矩阵相乘Strassen算法

gdfyug的博客 319

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

算法系列

[算法系列之一]堆排序 (sjf0115) [算法系列之二]二叉树各种遍历 (sjf0115) [算法系列之三]二叉树中序前序序列(或后序)求解树 (sjf0115) [算法系列之四]优先级队列 (sjf0115) [算法系列之五]快速排序 (sjf0115) [算法系列之六]二叉查找树 (sjf0115) [算法系列之七]Manacher算法之最大回文子串 (sjf0115) ...

iteye_4972的博客 219

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

快速矩阵乘法 strassen算法、coppersmith-winograd算法

竹杖芒鞋轻胜马,一蓑烟雨任平生 首页 标签 分类 归档 关于 快速矩阵乘法 发表于 2016-07-19 | 分类于 算法 , 性能优化 | 0 | 阅读次数: 5055 矩阵乘法 矩阵乘法是高性能计算以及深度学习的基石之一,矩阵乘法的优化一直是相关业界的关注重点。 矩阵乘法的定义非常简单,定义见:wiki。 最简单的矩阵乘法实现 最简单的矩阵乘法实现,时间复杂度为O^3。 static void mm_generate(float* matA,float* matB,float* matC,cons

xzf_cellery的博客 4333

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

深度学习(十)——花式卷积(2)

深度学习(十)——花式卷积(二)

antkillerfarm的专栏 3270

快速矩阵乘法的算法实现

快速矩阵乘法

qq_42327795的博客 1万+

快速矩阵乘法的研究——下

快速矩阵乘法的研究 本文我们只看一个算法,就是 Coppersmith 和 Winograd 提出的O(2.39)O(2.39)O(2.39)的矩阵乘法。请确保前两篇内容已经掌握理解。 https://blog.youkuaiyun.com/jxt1234and2010/article/details/88588208 https://blog.youkuaiyun.com/jxt1234and2010/article/...

jxt1234and2010的专栏 1337

Coppersmith-Winograd 算法

转自:https://www.douban.com/group/topic/29658298/ 对正整数 $q$,定义张量 $T$,其对应的多项式为 $p(X,Y,Z)=\sum_{i=1}^q (X_0Y_iZ_i+X_iY_0Z_i+X_iY_iZ_0)$。对于 $\epsilon>0$,定义张量 $T(\epsilon)$,其对应的多项式为\begin{align}...

2446

[算法系列之十五]Strassen矩阵相乘算法

引言 Strassen矩阵乘法是一种典型的分治算法。目前为止,我们已经见过一些分治策略的算法了,例如归并排序和Karatsuba大数快速乘法。现在,让我们看看分治策略的背后原理是什么。 同动态规划不同,在动态规划中,为了得到最终的答案,我们需要把一个大的问题“展开”为几个子问题(“expand” the solutions of sub-problems),但是在这里,我们会更多的谈到如何把...

SmartSi 1535

Winograd算法

Winograd算法描述如下: 选择一个多项式,它的值要比大。然后,把它分解为k+1个互质的实系数多项式相乘,例如, 设。求解,得到。 计算出 和    ,这里,i=0,1,...,k 。 计算出   , 这里,i=0,1,...,k 。 通过使用,计算出。 完成。就是的乘积。 ...

qingsong1001的专栏 1805

荷兰国旗问题(分三块)

——堆排序扩展问题 已知一个几乎有序的数组,几乎有序是指,如果把数组排好序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。 分析: 假设k的值等于7,那么我们申请一个可以容纳8个数的小根堆。将数组下标从0到7的数字放入小根堆中。接着从这个小根堆中弹出一个数,那么这么数就是该数组最小的数,然后再向着个堆中添加一个数,再弹出……这样可...

菜鸟变大鸟的博客 1万+

矩阵乘法-strassen算法

 1.矩阵相乘的朴素算法 时间复杂度T(n)=Θ(n3),朴素矩阵相乘算法,思想明了,编程实现简单。时间复杂度是Θ(n^3)。伪码如下 for i ← 1 to n     do for j ← 1 to n        do c[i][j] ← 0           for k ← 1 to n              do  c[i][j] ← c[i][j] + a[i][...

严霜九月 5605

三色排序问题/(荷兰国旗问题)(C++版)

题目: 有一个只由0,1,2三种元素构成的整数数组,请使用交换、原地排序而不是使用计数进行排序。 给定一个只含0,1,2的整数数组A及它的大小,请返回排序后的数组。 算法复杂度: 时间 O(N) 空间 O(1) 贴代码: void swap(int *p1, int *p2) { int temp = *p1; *p1 = *p2; *p2 = te

decode 4496
上一篇: AVI格式的详细分析
下一篇: Windows中的时间(SYSTEMTIME和FILETIME)
小人物2014
博客等级 码龄19年 66粉丝 99原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值