• 《算法导论》——矩阵乘法的Strassen算法


    前言:

      很多朋友看到我写的《算法导论》系列,可能会觉得云里雾里,不知所云。这里我再次说明,本系列博文时配合《算法导论》一书,给出该书涉及的算法的c++实现。请结合《算法导论》一书阅读该系列博文。我这里有该书的电子版,有需要的朋友可以留言。

    正题:

      今天讨论的算法是矩阵乘法的Strassen算法,该算法的精髓在于减少n/2矩阵*n/2矩阵的次数。首先,作一些写该算法的基础工作:

    /*
        * 矩阵的加法运算
        */
        void Add(int** matrixA, int** matrixB, int** matrixResult,int length)
        {
            for(int i = 0; i < length; i++) {
                for(int j = 0; j < length; j++) {
                    matrixResult[i][j] = matrixA[i][j] + matrixB[i][j];
                }
            }
        }
    
        /*
        * 矩阵的减法运算
        */
        void Sub(int** matrixA, int** matrixB, int** matrixResult,int length)
        {
            for(int i = 0; i < length; i++) {
                for(int j = 0; j < length; j++) {
                    matrixResult[i][j] = matrixA[i][j] - matrixB[i][j];
                }
            }
        }
    
        /*
        * 矩阵乘法
        */
        void Mul(int** matrixA, int** matrixB, int** matrixResult){
            for(int i = 0; i < 2; ++i) {
                for(int j = 0; j < 2; ++j) {
                    matrixResult[i][j] = 0;
                    for(int k = 0; k < 2; ++k) {
                        matrixResult[i][j] += matrixA[i][k] * matrixB[k][j];
                    }
                }
            }
        }
    View Code

    接着进入核心部分:

    void Strassen(int** matrixA, int** matrixB, int** matrixResult,int length)
        {
            int halfLength=length/2;
            int** a11=new int*[halfLength];
            int** a12=new int*[halfLength];
            int** a21=new int*[halfLength];
            int** a22=new int*[halfLength];
    
            int** b11=new int*[halfLength];
            int** b12=new int*[halfLength];
            int** b21=new int*[halfLength];
            int** b22=new int*[halfLength];
    
            int** s1=new int*[halfLength];
            int** s2=new int*[halfLength];
            int** s3=new int*[halfLength];
            int** s4=new int*[halfLength];
            int** s5=new int*[halfLength];
            int** s6=new int*[halfLength];
            int** s7=new int*[halfLength];
    
            int** matrixResult11=new int*[halfLength];
            int** matrixResult12=new int*[halfLength];
            int** matrixResult21=new int*[halfLength];
            int** matrixResult22=new int*[halfLength];        
    
            int** temp=new int*[halfLength];
            int** temp1=new int*[halfLength];
            if(halfLength==1){
                Mul(matrixA, matrixB, matrixResult);
            }else{
                //首先将矩阵A,B 分为4块
                for(int i = 0; i < halfLength; i++) {    
                    a11[i]=new int[halfLength];
                    a12[i]=new int[halfLength];
                    a21[i]=new int[halfLength];
                    a22[i]=new int[halfLength];
    
                    b11[i]=new int[halfLength];
                    b12[i]=new int[halfLength];
                    b21[i]=new int[halfLength];
                    b22[i]=new int[halfLength];
    
                    s1[i]=new int[halfLength];
                    s2[i]=new int[halfLength];
                    s3[i]=new int[halfLength];
                    s4[i]=new int[halfLength];
                    s5[i]=new int[halfLength];
                    s6[i]=new int[halfLength];
                    s7[i]=new int[halfLength];
    
                    matrixResult11[i]=new int[halfLength];
                    matrixResult12[i]=new int[halfLength];
                    matrixResult21[i]=new int[halfLength];
                    matrixResult22[i]=new int[halfLength];
    
                    temp[i]=new int[halfLength];
                    temp1[i]=new int[halfLength];
                    for(int j = 0; j < halfLength; j++) {
                        a11[i][j]=matrixA[i][j];
                        a12[i][j]=matrixA[i][j+halfLength];
                        a21[i][j]=matrixA[i+halfLength][j];
                        a22[i][j]=matrixA[i+halfLength][j+halfLength];
                        b11[i][j]=matrixB[i][j];
                        b12[i][j]=matrixB[i][j+halfLength];
                        b21[i][j]=matrixB[i+halfLength][j];
                        b22[i][j]=matrixB[i+halfLength][j+halfLength];
                    }                
                }
    
                //计算s1
                Sub(b12, b22, temp,halfLength);
                Strassen(a11, temp, s1,halfLength);
                //计算s2
                Add(a11, a12, temp,halfLength);
                Strassen(temp, b22, s2,halfLength);
                //计算s3
                Add(a21, a22, temp,halfLength);
                Strassen(temp, b11, s3,halfLength);
                //计算s4
                Sub(b21, b11, temp,halfLength);
                Strassen(a22, temp, s4,halfLength);
                //计算s5
                Add(a11, a22, temp1,halfLength);
                Add(b11, b22, temp,halfLength);
                Strassen(temp1, temp, s5,halfLength);
                //计算s6
                Sub(a12, a22, temp1,halfLength);
                Add(b21, b22, temp,halfLength);
                Strassen(temp1, temp, s6,halfLength);
                //计算s7
                Sub(a11, a21, temp1,halfLength);
                Add(b11, b12, temp,halfLength);
                Strassen(temp1, temp, s7,halfLength);
    
                //计算matrixResult11
                Add(s5, s4, temp1,halfLength);
                Sub(temp1, s2, temp,halfLength);
                Add(temp, s6, matrixResult11,halfLength);
                //计算matrixResult12
                Add(s1, s2, matrixResult12,halfLength);
                //计算matrixResult21
                Add(s3, s4, matrixResult21,halfLength);
                //计算matrixResult22
                Add(s5, s1, temp1,halfLength);
                Sub(temp1, s3, temp,halfLength);
                Sub(temp, s7, matrixResult22,halfLength);
    
                //结果送回matrixResult中
                for(int i = 0; i < halfLength; i++) {
                    for(int j = 0; j < halfLength; j++) {
                        matrixResult[i][j]=matrixResult11[i][j];
                        matrixResult[i][j+halfLength]=matrixResult12[i][j];
                        matrixResult[i+halfLength][j]=matrixResult21[i][j];
                        matrixResult[i+halfLength][j+halfLength]=matrixResult22[i][j];
                    }
                    delete(a11[i]);
                    delete(a12[i]);
                    delete(a21[i]);
                    delete(a22[i]);
    
                    delete(b11[i]);
                    delete(b12[i]);
                    delete(b21[i]);
                    delete(b22[i]);
    
                    delete(s1[i]);
                    delete(s2[i]);
                    delete(s3[i]);
                    delete(s4[i]);
                    delete(s5[i]);
                    delete(s6[i]);
                    delete(s7[i]);
    
                    delete(matrixResult11[i]);
                    delete(matrixResult12[i]);
                    delete(matrixResult21[i]);
                    delete(matrixResult22[i]);
    
                    delete(temp[i]);
                    delete(temp1[i]);
                }
                delete(a11);
                delete(a12);
                delete(a21);
                delete(a22);
    
                delete(b11);
                delete(b12);
                delete(b21);
                delete(b22);
    
                delete(s1);
                delete(s2);
                delete(s3);
                delete(s4);
                delete(s5);
                delete(s6);
                delete(s7);
    
                delete(matrixResult11);
                delete(matrixResult12);
                delete(matrixResult21);
                delete(matrixResult22);
    
                delete(temp);
                delete(temp1);
            }
        }

    该算法看着或许有些冗长,几乎一半都在进行动态指针的初始化和删除。利用该算法计算矩阵乘的时间复杂度为θ(n^lg7)。

    测试一下吧:

    #include "stdafx.h"
    #include <iostream>
    #include "SquareMatrix.h"
    
    using namespace std;
    using namespace dksl;
    
    
    //STRASSEN矩阵乘法算法
    
    
    const int N=8; //常量N用来定义矩阵的大小
    int _tmain(int argc, _TCHAR* argv[])
    {
        int **a=new int*[4];
        int **b=new int*[4];
        int **c=new int*[4];
        for(int i=0;i<4;i++)
            {
                a[i]=new int[4];
                b[i]=new int[4];
                c[i]=new int[4];
            for(int j=0;j<4;j++)
            {
                a[i][j]=1;
                b[i][j]=2;
            }
        }
        Strassen(a,b,c,4);
        for(int i=0;i<4;i++)
        {
            for(int j=0;j<4;j++)
                cout<<c[i][j]<<" ";
            cout<<endl;
        }
        system("PAUSE");
        return 0;
    }

  • 相关阅读:
    Arpa's weak amphitheater and Mehrdad's valuable Hoses
    Arpa's loud Owf and Mehrdad's evil plan
    穷游中国在统题
    2016 ACM Amman Collegiate Programming Contest D Rectangles
    区间求和
    Redis 连接池的问题
    eBay 使用ReviseInventoryStatusCall调整库存和价格
    eBay Notification介绍
    Quartz.Net 配置模板范例
    Quartz.net misfire实践
  • 原文地址:https://www.cnblogs.com/DKSL/p/3150338.html
Copyright © 2020-2023  润新知