算法导论学习——分治矩阵乘法

头文件 结构的定义

stdafx.h

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

// TODO:  在此处引用程序需要的其他头文件
#include <iostream>

using namespace std;

#define Maxelem 10

//求两个数的最大值
int inline max(int a, int b){
	return a >= b ? a : b;
}
//求三个数的最大值
int inline max(int a, int b, int c){
	return max(max(a, b), c);
}

//求min(2^x),ST. 2^x>=number。
int inline L2n(int number){
	if ((number & number - 1) == 0)
	{
		return number;
	}
	else {
		return pow(2, (int)log2(number) + 1);
	}
}

//定义矩阵的结构
class Matrix{

public:
	int data[Maxelem][Maxelem];
	int M, N;
	//以数组复制的方式构造矩阵对象,其中起始位置为0.
	Matrix(int array[Maxelem][Maxelem], int m, int n){
		M = m;
		N = n;
		for (int i = 0; i < m; i++){
			for (int j = 0; j < n; j++){
				this->data[i][j] = array[i][j];
			}
		}
	}

	//以数组复制的方式构造矩阵对象,以strat1,end1,strat2,end2为区间
	Matrix(int array[Maxelem][Maxelem], int start1, int end1, int start2, int end2){
		M = end1 - start1 + 1;
		N = end2 - start2 + 1;
		int p = 0, q = 0;
		for (int i = 0; i < M; i++){
			for (int j = 0; j < N; j++){
				data[i][j] = array[start1 + i][start2 +j];
			}

		}

	}
	//仅构造矩阵,不填充数据
	Matrix(int m, int n) :M(m), N(n){}

	/*
	 打印输出
	*/
	void print() const {
		for (int i = 0; i <M; i++){
			for (int j = 0; j < N; j++){
				cout << data[i][j] << " ";
			}
			cout << endl;

		}
	}
	//为矩阵补充0,使其成为标准方阵
		void fill(){

		if (!(M == N && ((M & M - 1) == 0))){
			int n = L2n(max(M, N));

			for (int i = 0; i < n; i++){
				for (int j = 0; j < n; j++){
					data[i][j] = (i < M&&j < N ? data[i][j] : 0);
				}
			}
			M = n;
			N = n;

		}
	}

	/*重载二维运算符[][]*/
	int * const operator[](const int i)
	{
		return data[i];
	}

	Matrix friend operator +(Matrix m1, Matrix m2){

		Matrix op = Matrix(m1.M, m1.N);
		for (int i = 0; i < m1.M; i++)
		{
			for (int j = 0; j < m1.M; j++){
				op[i][j] = m1[i][j] + m2[i][j];
			}
		}
		return op;
	}
	Matrix friend operator -(Matrix m1, Matrix m2){

		Matrix op = Matrix(m1.M, m1.N);
		for (int i = 0; i < m1.M; i++)
		{
			for (int j = 0; j < m1.M; j++){
				op[i][j] = m1[i][j] - m2[i][j];
			}
		}
		return op;
	}
	/*
	将计算过程中补充的0清除。计算完毕后才能用的方法,不加也能得到结果,不过行列数不对。
	*/
	void clean(int m, int n){
		M = m;
		N = n;
	}
};

  算法的实现:

// strassenAlgorithm.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

//该方法只能相乘最简单的2*2矩阵。
Matrix mutilSimple(Matrix A, Matrix B){
	int a = A[0][0],b=A[0][1],c=A[1][0],d=A[1][1];
	int e = B[0][0], f = B[0][1], g = B[1][0], h = B[1][1];

	int p1 = a*(f - h);
	int p2 = (a + b)*h;
	int p3 = (c + d)*e;
	int p4 = d*(g - e);
	int p5 = (a + d)*(e + h);
	int p6 = (b - d)*(g + h);
	int p7 = (a - c)*(e + f);

	Matrix returnValue = Matrix(2, 2);
	returnValue[0][0] = p5 + p4 - p2 + p6;
	returnValue[0][1] = p1 + p2;
	returnValue[1][0] = p3 + p4;
	returnValue[1][1] = p1 + p5 - p3 - p7;

	return returnValue;
}

//矩阵乘法 必须用了fill方法才能相乘
Matrix mutilMerge(Matrix A,Matrix B){
	if (A.M == 2 && B.M == 2){
		return mutilSimple(A, B);
	}
	int k = A.M;
	Matrix
		a = Matrix(A.data, 0, k / 2 - 1, 0, k / 2 - 1),
		b = Matrix(A.data, 0, k / 2 - 1, k / 2, k - 1),
		c = Matrix(A.data, k / 2, k - 1, 0, k / 2 - 1),
		d = Matrix(A.data, k / 2, k - 1, k / 2, k - 1),

		e = Matrix(B.data, 0, k / 2 - 1, 0, k / 2 - 1),
		f = Matrix(B.data, 0, k / 2 - 1, k / 2, k - 1),
		g = Matrix(B.data, k / 2, k - 1, 0, k / 2 - 1),
		h = Matrix(B.data, k / 2, k - 1, k / 2, k - 1),
		op = Matrix(k, k),

		p1 = mutilMerge(a, f - h),
		p2 = mutilMerge(a + b, h),
		p3 = mutilMerge(c + d, e),
		p4 = mutilMerge(d, g - e),
		p5 = mutilMerge(a + d, e + h),
		p6 = mutilMerge(b - d, g + h),
		p7 = mutilMerge(a - c, e + f),

		op1=p5+p4-p2+p6,
		op2=p1+p2,
		op3=p3+p4,
		op4 = p1 + p5 - p3 - p7; 

	int x1 = 0, y1 = 0, x2 = 0, y2 = 0, x3 = 0,y3=0,x4=0, y4 = 0; //4个变量的游标
	int u = 0, v = 0;
	for (int i = 0; i < k; i++)
	{
		for (int j = 0; j < k; j++){

			if (i >= 0 && i <= k / 2 - 1 && j >= 0 && j <= k / 2 - 1){
				op[i][j] = op1[x1][y1];
				y1++;
				if (y1 == op1.M) { y1 = 0; x1++; }
			}
			if (i >= 0 && i <= k / 2 - 1 && j >= k / 2 && j <= k - 1){
				op[i][j] = op2[x2][y2];
				y2++;
				if (y2 == op2.M) { y2 = 0; x2++; }
			}
			if (i >= k/2 && i <= k - 1 && j >= 0 && j <= k / 2 - 1){

				op[i][j] = op3[x3][y3];
				y3++;
				if (y3 == op3.M) { y3 = 0; x3++; }
			}

			if (i >= k / 2 && i <= k - 1 && j >= k/2 && j <= k - 1){
				op[i][j] = op4[x4][y4];
				y4++;
				if (y4 == op4.M) { y4 = 0; x4++; }
			}

		}
	}

	return op;

}
Matrix zeroclear( Matrix result,int M,int N){
	result.M = M;
	result.N = N;
	return result;
}
int _tmain(int argc, _TCHAR* argv[])
{

	int matrixA[Maxelem][Maxelem] = {
		{ 10, 3, 3 ,7,4},
		{ 5, 3, 8,2,1 },
		{ -2, 3, 7, 5, 2 },
		{1,10,-2,1,8},
		{3,3,3,3,3}
	};

	int matrixB[Maxelem][Maxelem] = {
		{ -4, 6, 1,2,1 },
		{ 9, 10, 8,0,3 },
		{ 2, 3, -7 ,-1,-1},
		{ 1, -6, 2, 1, 7 },
		{1,2,3,4,5}
	};

	Matrix ma = Matrix(matrixA,5,5);
	Matrix mb = Matrix(matrixB,5,5);

	cout << "A="<<endl;

	ma.print();
	cout << "B="<<endl;
	mb.print();

	ma.fill();
	mb.fill();
	Matrix result = mutilMerge(ma, mb);

	cout << "A×B=" << endl;
	result.clean(5, 5);
	result.print();
	cout << "B×A=" << endl;
	result = mutilMerge(mb, ma);
	result.clean(5, 5);
	result.print();
	system("pause");

	return 0;
}

  

时间: 2024-10-19 02:42:37

算法导论学习——分治矩阵乘法的相关文章

算法导论--动态规划(矩阵链乘法)

矩阵链乘法问题 给定一个n个矩阵的序列?A1,A2,A3...An?,我们要计算他们的乘积:A1A2A3...An.因为矩阵乘法满足结合律,加括号不会影响结果.可是不同的加括号方法.算法复杂度有非常大的区别: 考虑矩阵链:?A1,A2,A3?.三个矩阵规模分别为10×100.100×5.5×50 假设按((A1A2)A3)方式,须要做10?100?5=5000次,再与A3相乘,又须要10?5?50=2500,共须要7500次运算: 假设按(A1(A2A3))方式计算.共须要100?5?50+10

算法导论 学习资源

学习的过程会遇到些问题,发现了一些比较好的资源,每章都会看下别人写的总结,自己太懒了,先记录下别人写的吧,呵呵. 1  Tanky Woo的,每次差不多都看他的 <算法导论>学习总结 - 1.前言 <算法导论>学习总结 - 2.第一章 && 第二章 && 第三章 <算法导论>学习总结 - 3.第四章 && 第五章 <算法导论>学习总结 - 4.第六章(1) 堆排序 <算法导论>学习总结 - 5.第六

算法导论 之 动态规划 - 矩阵链相乘

1 引言 在大学期间,我们学过高等数学中的线性规划,其中有关于矩阵相乘的章节:只有当矩阵A的列数与矩阵B的行数相等时,A×B才有意义.一个m×n的矩阵A(m,n)左乘一个n×p的矩阵B(n,p),会得到一个m×p的矩阵C(m,p).矩阵乘法满足结合律,但不满足交换律. 假设现要计算A×B×C×D的值,因矩阵乘法满足结合律,不满足交换律,即:A.B.C.D相邻成员的相乘顺序不会影响到最终的计算结果,比如: A×(B×(C×D)).A×((B×C)×D).(A×B)×(C×D).A×(B×C)×D.

算法导论学习---红黑树具体解释之插入(C语言实现)

前面我们学习二叉搜索树的时候发如今一些情况下其高度不是非常均匀,甚至有时候会退化成一条长链,所以我们引用一些"平衡"的二叉搜索树.红黑树就是一种"平衡"的二叉搜索树,它通过在每一个结点附加颜色位和路径上的一些约束条件能够保证在最坏的情况下基本动态集合操作的时间复杂度为O(nlgn).以下会总结红黑树的性质,然后分析红黑树的插入操作,并给出一份完整代码. 先给出红黑树的结点定义: #define RED 1 #define BLACK 0 ///红黑树结点定义,与普通

【算法导论学习-015】数组中选择第i小元素(Selection in expected linear time)

1.算法思想 问题描述:从数组array中找出第i小的元素(要求array中没有重复元素的情况),这是个经典的"线性时间选择(Selection in expected linear time)"问题. 思路:算法导论215页9.2 Selection in expect linear time 2.java实现 思路:算法导论216页伪代码 /*期望为线性时间的选择算法,输入要求,array中没有重复的元素*/ public static int randomizedSelect(i

算法导论学习---红黑树详解之插入(C语言实现)

前面我们学习二叉搜索树的时候发现在一些情况下其高度不是很均匀,甚至有时候会退化成一条长链,所以我们引用一些"平衡"的二叉搜索树.红黑树就是一种"平衡"的二叉搜索树,它通过在每个结点附加颜色位和路径上的一些约束条件可以保证在最坏的情况下基本动态集合操作的时间复杂度为O(nlgn).下面会总结红黑树的性质,然后分析红黑树的插入操作,并给出一份完整代码. 先给出红黑树的结点定义: #define RED 1 #define BLACK 0 ///红黑树结点定义,与普通的二

【算法导论学习-014】计数排序(CountingSortTest)

参考:<算法导论>P194页 8.2节 Counting sort 1.Counting sort的条件 待排序数全部分布在0~k之间,且k是已知数:或者分布在min~max之间,等价于分布在0~max-min之间,max和min是已知数. 2.java 实现 /** * 创建时间:2014年8月17日 下午3:22:14 项目名称:Test * * @author Cao Yanfeng * @since JDK 1.6.0_21 类说明: 计数排序法,复杂度O(n), 条件:所有数分布在0

【算法导论学习-015】基数排序(Radix sort)

1.<算法导论>P197页 8.3节Radix sort 2.java实现 这里仅仅对[算法导论学习-014]计数排序 的参数进行了修改,同时仅仅修改了一行代码. /** * 创建时间:2014年8月17日 下午4:05:48 * 项目名称:Test * @author Cao Yanfeng * @since JDK 1.6.0_21 * 类说明: 利用计数排序实现基数排序 * 条件:待排序的所有数位数相同,注意,即便不相同,也可以认为是最多那个位数,如下面的例子可以认为都是3位数 */ p

【算法导论学习-016】两个已排过序的等长数组的中位数(median of two sorted arrays)

问题来源 <算法导论>P223 9.3-8: Let X[1..n] and Y[1..n] be two arrays, each containing nnumbers already in sorted order. Give an O(lgn)-time algorithm to find themedian of all 2n elements in arrays X and Y. 翻译过来即:求两个等长(n个元素)的已排序数组A和B的中位数 方案1:对两个数组进行归并直到统计到第n