栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

算法report2 Strassen 算法

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

算法report2 Strassen 算法

目录

一、要求

(一)内容与设计思想

(二)实验过程

(三)总结

二、代码

(一)原来的代码

1.矩阵加法.cpp

2.矩阵减法.cpp

3.普通乘法.cpp

4.Strassen.cpp

5.main.cpp

(二)Strassen算法改进

三、折线图

(一)普通乘法和Strassen算法(ms)

(二)数据规模为2的幂与不是2的幂(ms)

四、总结


一、要求

(一)内容与设计思想 1. 编程实现普通的矩阵乘法; 2. 编程实现 Strassen’s algorithm ; 3. 在不同数据规模情况下(数据规模N=2^3,2^5,2^7,2^9 )下,比较两种算法的运行时间各是多少; 4. 修改 Strassen’s algorithm ,使之适应矩阵规模 N 不是 2 的幂的情况; 5. 改进后的算法与 2 中的算法在相同数据规模下进行比较。 为便于同学操作,我们设置了课程编程题在 oj | 《算法设计与分析》第二次实验课 ,同学可以提交算法 代码到这个平台去计算和比较时间。 注意 1 : 每组样例有对应的执行次数,如果需要得到单次时间,要除以重复数。 注意 2 : 由于平台的缘故,可能会有 30ms 的波动;解决办法是多提交几次(比如 5 次)取平均数。

(二)实验过程 分别画出各个实验结果的折线图

(三)总结 对上机实践结果进行分析,问题回答,上机的心得体会及改进意见。

二、代码

起初,我是把普通乘法和Strassen算法完全分开的,后来在CSDN上查找资料时偶然地看到了一位大佬的代码,他是把矩阵乘法分开成加法和乘法,相对我的代码要简洁好多……于是我又根据这种思路改进了我的代码(或许称不上改进,基本推翻重来了)

数据的第一行有两个整数 N(1<=N<=163841≤N≤16384) 和 M (8<=M<=512)。表示以下有 N 对矩阵(必定是成对输入的),并且每个矩阵的大小都是M×M。

(一)原来的代码

其中关同步,提高cin / cout效率     

             ios::sync_with_stdio(false); //关同步,提高cin / cout效率

             cin.tie(nullptr);

因为数据实在太大了,不写它可能就运行不起来

1.矩阵加法.cpp
#include
using namespace std;

void Matrix_Sum(int n, int** MatrixA, int** MatrixB, int** MatrixSum) {
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			MatrixSum[i][j] = MatrixA[i][j] + MatrixB[i][j];
}

2.矩阵减法.cpp
#include
using namespace std;

void Matrix_Sub(int n, int** MatrixA, int** MatrixB, int** MatrixSub) {
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			MatrixSub[i][j] = MatrixA[i][j] - MatrixB[i][j];
}

3.普通乘法.cpp
#include
using namespace std;

void Matrix_Mul(int n, int** MatrixA, int** MatrixB, int** MatrixMul) {
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) {
			MatrixMul[i][j] = 0;
			for (int k = 0; k < n; k++)
				MatrixMul[i][j] = MatrixMul[i][j] + MatrixA[i][k] * MatrixB[k][j];
		}
			
}

4.Strassen.cpp
#include
#include "矩阵加法.cpp"
#include "矩阵减法.cpp"
#include "普通乘法.cpp"
using namespace std;

void Strassen(int N, int** MatrixA, int** MatrixB, int** MatrixC ) {
	int n = N / 2; //分治思想
	//初始化每个小矩阵的大小
	int** MatrixA11 = new int* [n];
	int** MatrixA12 = new int* [n];
	int** MatrixA21 = new int* [n];
	int** MatrixA22 = new int* [n];
	int** MatrixB11 = new int* [n];
	int** MatrixB12 = new int* [n];
	int** MatrixB21 = new int* [n];
	int** MatrixB22 = new int* [n];
	int** MatrixC11 = new int* [n];
	int** MatrixC12 = new int* [n];
	int** MatrixC21 = new int* [n];
	int** MatrixC22 = new int* [n];

	for (int i = 0; i < n ; i++) {  //分配连续内存
		MatrixA11[i] = new int[n];
		MatrixA12[i] = new int[n];
		MatrixA21[i] = new int[n];
		MatrixA22[i] = new int[n];
		MatrixB11[i] = new int[n];
		MatrixB12[i] = new int[n];
		MatrixB21[i] = new int[n];
		MatrixB22[i] = new int[n];
		MatrixC11[i] = new int[n];
		MatrixC12[i] = new int[n];
		MatrixC21[i] = new int[n];
		MatrixC22[i] = new int[n];
	}
	//为每个小矩阵赋值,将大矩阵分割为4个小矩阵
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) {
			MatrixA11[i][j] = MatrixA[i][j];
			MatrixA12[i][j] = MatrixA[i][j + n];
			MatrixA21[i][j] = MatrixA[i + n][j];
			MatrixA22[i][j] = MatrixA[i + n][j + n];

			MatrixB11[i][j] = MatrixB[i][j];
			MatrixB12[i][j] = MatrixB[i][j + n];
			MatrixB21[i][j] = MatrixB[i + n][j];
			MatrixB22[i][j] = MatrixB[i + n][j + n];
		}		

	//存放加减法结果
	int** S1 = new int* [n];
	int** S2 = new int* [n];
	int** S3 = new int* [n];
	int** S4 = new int* [n];
	int** S5 = new int* [n];
	int** S6 = new int* [n];
	int** S7 = new int* [n];
	int** S8 = new int* [n];
	int** S9 = new int* [n];
	int** S10 = new int* [n];

	for (int i = 0; i < n; i++) {  //分配连续内存
		S1[i] = new int[n];
		S2[i] = new int[n];
		S3[i] = new int[n];
		S4[i] = new int[n];
		S5[i] = new int[n];
		S6[i] = new int[n];
		S7[i] = new int[n];
		S8[i] = new int[n];
		S9[i] = new int[n];
		S10[i] = new int[n];
	}
	//计算
	Matrix_Sub(n, MatrixA12, MatrixA22, S1);
	Matrix_Sum(n, MatrixB21, MatrixB22, S2);
	Matrix_Sum(n, MatrixA11, MatrixA22, S3);
	Matrix_Sum(n, MatrixB11, MatrixB22, S4);
	Matrix_Sub(n, MatrixA11, MatrixA21, S5);
	Matrix_Sum(n, MatrixB11, MatrixB12, S6);
	Matrix_Sum(n, MatrixA11, MatrixA12, S7);
	Matrix_Sub(n, MatrixB12, MatrixB22, S8);
	Matrix_Sub(n, MatrixB21, MatrixB11, S9);
	Matrix_Sum(n, MatrixA21, MatrixA22, S10);

	//存放乘法结果
	int** M1 = new int* [n];
	int** M2 = new int* [n];
	int** M3 = new int* [n];
	int** M4 = new int* [n];
	int** M5 = new int* [n];
	int** M6 = new int* [n];
	int** M7 = new int* [n];

	for (int i = 0; i < n; i++) {  //分配连续内存
		M1[i] = new int[n];
		M2[i] = new int[n];
		M3[i] = new int[n];
		M4[i] = new int[n];
		M5[i] = new int[n];
		M6[i] = new int[n];
		M7[i] = new int[n];
	}
	Matrix_Mul(n, S1, S2, M1);
	Matrix_Mul(n, S3, S4, M2);
	Matrix_Mul(n, S5, S6, M3);
	Matrix_Mul(n, S7, MatrixB22, M4);
	Matrix_Mul(n, MatrixA11, S8, M5);
	Matrix_Mul(n, MatrixA22, S9, M6);
	Matrix_Mul(n, S10, MatrixB11, M7);

	//finally
	//计算C
	Matrix_Sum(n, M1, M2, MatrixC11);
	Matrix_Sub(n, MatrixC11, M4, MatrixC11);
	Matrix_Sum(n, MatrixC11, M6, MatrixC11);

	Matrix_Sum(n, M4, M5, MatrixC12);
	Matrix_Sum(n, M6, M7, MatrixC21);

	Matrix_Sub(n, M2, M3, MatrixC22);
	Matrix_Sum(n, MatrixC22, M5, MatrixC22);
	Matrix_Sub(n, MatrixC22, M7, MatrixC22);

	//将C合并
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) {
			MatrixC[i][j] = MatrixC11[i][j];
			MatrixC[i][j + n] = MatrixC12[i][j];
			MatrixC[i + n][j] = MatrixC21[i][j];
			MatrixC[i + n][j + n] = MatrixC22[i][j];
		}
}

5.main.cpp
#include
#include
#include"Strassen.cpp"
#include
using namespace std;
ifstream fi("6.in", ios::in);


int main() {
	clock_t startTime_For_Normal_Multipilication;
	clock_t endTime_For_Normal_Multipilication;

	clock_t startTime_For_Strassen;
	clock_t endTime_For_Strassen;

	time_t start, end;

    int N;
    fi >> N;
    int n=N;
	int M; //矩阵大小
	fi >> M;

	int** MatrixA = new int* [M];
	int** MatrixB = new int* [M];
	int** MatrixC = new int* [M];
	int** MatrixT = new int* [M]; //用于检测结果是否正确
	for (int i = 0; i < M; i++) {
		MatrixA[i] = new int[M];
		MatrixB[i] = new int[M];
		MatrixC[i] = new int[M];
		MatrixT[i] = new int[M];
	}
    int i,j;
    int time1=0;
    int time2=0;
    while(N--){
        for(i=0;i> MatrixA[i][j];
            }
        }
        for(i=0;i> MatrixB[i][j];
            }
        }
        //Mul
        startTime_For_Normal_Multipilication = clock();
        Matrix_Mul(M, MatrixA, MatrixB, MatrixT);
        endTime_For_Normal_Multipilication = clock();
        time1+=endTime_For_Normal_Multipilication - startTime_For_Normal_Multipilication;
        //cout << "print:" << endl;
        //print(MatrixT, M);
   
        //Strassen
        startTime_For_Strassen = clock();
        Strassen(M, MatrixA, MatrixB, MatrixC);
        endTime_For_Strassen = clock();
        time2+=endTime_For_Strassen - startTime_For_Strassen;
        //cout << "print:" << endl;
        //print(MatrixC, M);
    }

    cout << "Mul:" << time1 << endl;
    cout << "Strassen:" << time2;

	return 0;
}

(二)Strassen算法改进 矩阵规模 不是 2 的幂 当n为奇数时,先给矩阵加一行一列0,使之成为一个偶数矩阵。
#include 
using namespace std;

void Strassen(int N, int **MatrixA, int **MatrixB, int **MatrixC){
    int halfsize=N/2;
    if (N<=16)
        normal(MatrixA,MatrixB,MatrixC,N);
    else{
        int** A11;
        int** A12;
        int** A21;
        int** A22;

        int** B11;
        int** B12;
        int** B21;
        int** B22;

        int** C11;
        int** C12;
        int** C21;
        int** C22;

        int** M1;
        int** M2;
        int** M3;
        int** M4;
        int** M5;
        int** M6;
        int** M7;
        int** a_re;
        int** b_re;
        A11=new int *[halfsize];
        A12=new int *[halfsize];
        A21=new int *[halfsize];
        A22=new int *[halfsize];

        B11=new int *[halfsize];
        B12=new int *[halfsize];
        B21=new int *[halfsize];
        B22=new int *[halfsize];

        C11=new int *[halfsize];
        C12=new int *[halfsize];
        C21=new int *[halfsize];
        C22=new int *[halfsize];

        M1=new int *[halfsize];
        M2=new int *[halfsize];
        M3=new int *[halfsize];
        M4=new int *[halfsize];
        M5=new int *[halfsize];
        M6=new int *[halfsize];
        M7=new int *[halfsize];

        a_re=new int *[halfsize];
        b_re=new int *[halfsize];

        A11=new int *[halfsize];
        A12=new int *[halfsize];
        A21=new int *[halfsize];
        A22=new int *[halfsize];

        B11=new int *[halfsize];
        B12=new int *[halfsize];
        B21=new int *[halfsize];
        B22=new int *[halfsize];

        C11=new int *[halfsize];
        C12=new int *[halfsize];
        C21=new int *[halfsize];
        C22=new int *[halfsize];

        M1=new int *[halfsize];
        M2=new int *[halfsize];
        M3=new int *[halfsize];
        M4=new int *[halfsize];
        M5=new int *[halfsize];
        M6=new int *[halfsize];
        M7=new int *[halfsize];

        a_re=new int *[halfsize];
        b_re=new int *[halfsize];

        for(int i=0;i>MatrixA[row][column];
    for(int row=0;row>MatrixB[row][column];
    return 0;
}

void Printm(int **MatrixA,int Size){
    for(int row=0;row>time>>Size; 
    int N=1;
    while(Size>N)
        N*=2;
    while(time){
        MatrixA=new int *[N];
        MatrixB=new int *[N];
        MatrixC=new int *[N];
        for (int i=0;i 
  

三、折线图

(一)普通乘法和Strassen算法(ms)

(二)数据规模为2的幂与不是2的幂(ms)

然而k=300时运行时间在一百左右

四、总结

朴素矩阵的时间复杂度是O(n^3),而Strassen算法的时间复杂度是O(n^2.807),维度比较大的矩阵使用Strassen算法时时间可能更短,乘法运算相对朴素矩阵有所减少

在Strassen算法中,由于涉及到大量读写操作,这些读写操作都需要大量循环,当读写次数超出使用Strassen乘法的收益时,更适宜用朴素矩阵

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/297633.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号