概念:
分治法是编程界排名前五的重要算法之一,但是它本身并不是一种具体的算法,也没有典型的数据结构,而是一种编程思想,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。
适合用分治法求解的问题是通常在递归的每一步都会生成全新的子问题。
方法:
分:分解。分解步骤将问题划分为一些子问题,子问题的形式与原问题一样,只是规模够小。
治:解决。解决步骤递归地求解出子问题。如果子问题的规模足够小,则停止递归,直接求解。当子问题足够大,需要递归求解时,我们称之为递归情况。当子问题变得足够小,不再需要递归时,我们说递归已经触底,进入了基本情况。
合:合并。合并步骤将子问题的解组合为原问题的解。
算法经典实例:
1、最大子数组问题: 给定n个整数(可能为负数)组成的序列a[1],a[2]…a[n],求该序列a[i],a[i+1]…a[j]的子段和的最大值。
分析: 1): 暴力求解找出所有的组合,共有C(n,2)种选择,时间复杂度Θ(n^2)。2): 利用分治法求解最大字数组的思想是把每一个数组一分为二,每次考虑最大字数组所在的三种可能情况:跨中点,中点左侧,中点右侧。算法的计算量主要在于跨中点这种情况,中点单侧主要是控制划分深度,所以每一层计算复杂度是Θ(n),二分以后深度为logn,因此分治法的计算复杂度是Θ(nlogn)。
#include<iostream>
#include<vector>
#include<string>
using namespace std;
struct ret
{
int begin;
int end;
int sum;
};
ret FindMaxCrossSubarray(int *array,int low, int high) {
int mid = (low + high) / 2;
//右
int sumright = array[mid+1];
int tempsum = array[mid + 1];
int end = mid+1;
for(int i= mid+2; i <= high; i++){
tempsum += array[i];
if (tempsum > sumright){
sumright = tempsum;
end = i;
}
}
//左
int sumleft = array[mid];//应该选一个最小值
tempsum = array[mid];
int start = mid;
for (int i = mid-1; i >= low; i--) {
tempsum += array[i];
if (tempsum > sumleft) {
sumleft = tempsum;
start = i;
}
}
ret temp;
temp.begin = start;
temp.end = end;
temp.sum = sumleft + sumright;
return temp;
}
ret FindMaxSubarray(int *array,int low,int high) {
if (low == high)//递归触底
{ret temp;
temp.begin = low;
temp.end = high;
temp.sum = array[low];
return temp;
};
//分治合
int mid = (low + high) / 2;
ret left=FindMaxSubarray(array,low, mid);
ret right=FindMaxSubarray(array, mid+1, high);
ret cross=FindMaxCrossSubarray(array,low, high);
if (left.sum >= right.sum && left.sum >= cross.sum)
return left;
if (right.sum >= left.sum && right.sum >= cross.sum)
return right;
return cross;
}
int main(){
int temp[9] = { -2,1,-3,4,-1,2,1,-5,4};
ret result = FindMaxSubarray(temp,0,8);
cout << result.begin << endl;
cout << result.end << endl;
cout << result.sum << endl;
getchar();
}
2、归并排序:
void mergesort(int *array,int begin, int mid, int end) {
if (begin >= end)
return;
int *array1 = (int *)malloc(sizeof(int)*(mid-begin+1));
for (int i = 0; i <= mid - begin; i++) {
array1[i] = array[begin+i];
}
int *array2 = (int *)malloc(sizeof(int)*(end - mid));
for (int i = 0; i <= end-mid-1; i++) {
array2[i] = array[mid+1 + i];
}
int a1 = 0;
int a2 = 0;
for (int i = begin; i <= end; i++) {
if (((array1[a1] <= array2[a2])&&a1<= mid - begin)||(a2>end - mid - 1))
array[i] = array1[a1++];
else
array[i] = array2[a2++];
}
}
void merge(int *array, int begin, int end) {
if (begin >= end)
return;
int mid = (begin + end) / 2;
merge(array, begin, mid);
merge(array, mid+1, end);
mergesort(array, begin, mid, end);
}
int main() {
int temp[] = {5,3,4,7,8,1,2,9,10,6};
merge(temp,0,9);
for (int i = 0; i < 10; i++)
{
cout << temp[i] << " ";
}
getchar();
}
3、施特拉森(strassen)矩阵问题:
1)普通解法:o(n^3)
SQUARE-MATRIX-MULTIPLY(A, B)
n = A.rows
let C be a new nxn matrix
for i = 1 to n
for j = 1 to n
c[i][j] = 0
for k = 1 to n
c[i][j] += a[i][k] * b[k][j]
return C
2) strassen算法:
- 首先把每个矩阵分割为4份:
对于二阶矩阵
a11 a12 b11 b12
A = a21 a22 B = b21 b22
- 接着,计算7次矩阵乘法:
x1 = (a11 + a22) * (b11 + b22);
x2 = (a21 + a22) * b11;
x3 = a11 * (b12 - b22);
x4 = a22 * (b21 - b11);
x5 = (a11 + a12) * b22;
x6 = (a21 - a11) * (b11 + b12);
x7 = (a12 - a22) * (b21 + b22); - 最后,根据这7个结果就可以计算出C矩阵:
C11 = X5 + X4 - X2 + X6
C12 = X1 + X2
C21 = X3 + X4
C22 = X5 + X1 - X3 - X7
根据以上的方法,我们就可以计算4阶矩阵了,先将4阶矩阵A和B划分成四块2阶矩阵,分别利用公式计算它们的乘积,再使用步骤1和3来计算出最后结果。
ma11 ma12 mb11 mb12
A4 = ma21 ma22 B4 = mb21 mb22
其中
a11 a12 a13 a14 b11 b12 b13 b14
ma11 = a21 a22 ; ma12 = a23 a24; mb11 = b21 b22; mb12 = b23 b24
a31 a32 a33 a34 b31 b32 b33 b34
ma21 = a41 a42 ; ma22 = a43 a44; mb21 = b41 b42; mb22 = b43 b44
// 计算2X2矩阵
void Multiply2X2(float& fOut_11, float& fOut_12, float& fOut_21, float& fOut_22,
float f1_11, float f1_12, float f1_21, float f1_22,
float f2_11, float f2_12, float f2_21, float f2_22)
{
const float x1((f1_11 + f1_22) * (f2_11 + f2_22));
const float x2((f1_21 + f1_22) * f2_11);
const float x3(f1_11 * (f2_12 - f2_22));
const float x4(f1_22 * (f2_21 - f2_11));
const float x5((f1_11 + f1_12) * f2_22);
const float x6((f1_21 - f1_11) * (f2_11 + f2_12));
const float x7((f1_12 - f1_22) * (f2_21 + f2_22));
fOut_11 = x1 + x4 - x5 + x7;
fOut_12 = x3 + x5;
fOut_21 = x2 + x4;
fOut_22 = x1 - x2 + x3 + x6;
}
// 计算4X4矩阵
void Multiply(CLAYMATRIX& mOut, const CLAYMATRIX& m1, const CLAYMATRIX& m2)
{
float fTmp[7][4];
// (ma11 + ma22) * (mb11 + mb22)
Multiply2X2(fTmp[0][0], fTmp[0][1], fTmp[0][2], fTmp[0][3],
m1._11 + m1._33, m1._12 + m1._34, m1._21 + m1._43, m1._22 + m1._44,
m2._11 + m2._33, m2._12 + m2._34, m2._21 + m2._43, m2._22 + m2._44);
// (ma21 + ma22) * mb11
Multiply2X2(fTmp[1][0], fTmp[1][1], fTmp[1][2], fTmp[1][3],
m1._31 + m1._33, m1._32 + m1._34, m1._41 + m1._43, m1._42 + m1._44,
m2._11, m2._12, m2._21, m2._22);
// ma11 * (mb12 - mb22)
Multiply2X2(fTmp[2][0], fTmp[2][1], fTmp[2][2], fTmp[2][3],
m1._11, m1._12, m1._21, m1._22,
m2._13 - m2._33, m2._14 - m2._34, m2._23 - m2._43, m2._24 - m2._44);
// ma22 * (mb21 - mb11)
Multiply2X2(fTmp[3][0], fTmp[3][1], fTmp[3][2], fTmp[3][3],
m1._33, m1._34, m1._43, m1._44,
m2._31 - m2._11, m2._32 - m2._12, m2._41 - m2._21, m2._42 - m2._22);
// (ma11 + ma12) * mb22
Multiply2X2(fTmp[4][0], fTmp[4][1], fTmp[4][2], fTmp[4][3],
m1._11 + m1._13, m1._12 + m1._14, m1._21 + m1._23, m1._22 + m1._24,
m2._33, m2._34, m2._43, m2._44);
// (ma21 - ma11) * (mb11 + mb12)
Multiply2X2(fTmp[5][0], fTmp[5][1], fTmp[5][2], fTmp[5][3],
m1._31 - m1._11, m1._32 - m1._12, m1._41 - m1._21, m1._42 - m1._22,
m2._11 + m2._13, m2._12 + m2._14, m2._21 + m2._23, m2._22 + m2._24);
// (ma12 - ma22) * (mb21 + mb22)
Multiply2X2(fTmp[6][0], fTmp[6][1], fTmp[6][2], fTmp[6][3],
m1._13 - m1._33, m1._14 - m1._34, m1._23 - m1._43, m1._24 - m1._44,
m2._31 + m2._33, m2._32 + m2._34, m2._41 + m2._43, m2._42 + m2._44);
// 第一块
mOut._11 = fTmp[0][0] + fTmp[3][0] - fTmp[4][0] + fTmp[6][0];
mOut._12 = fTmp[0][1] + fTmp[3][1] - fTmp[4][1] + fTmp[6][1];
mOut._21 = fTmp[0][2] + fTmp[3][2] - fTmp[4][2] + fTmp[6][2];
mOut._22 = fTmp[0][3] + fTmp[3][3] - fTmp[4][3] + fTmp[6][3];
// 第二块
mOut._13 = fTmp[2][0] + fTmp[4][0];
mOut._14 = fTmp[2][1] + fTmp[4][1];
mOut._23 = fTmp[2][2] + fTmp[4][2];
mOut._24 = fTmp[2][3] + fTmp[4][3];
// 第三块
mOut._31 = fTmp[1][0] + fTmp[3][0];
mOut._32 = fTmp[1][1] + fTmp[3][1];
mOut._41 = fTmp[1][2] + fTmp[3][2];
mOut._42 = fTmp[1][3] + fTmp[3][3];
// 第四块
mOut._33 = fTmp[0][0] - fTmp[1][0] + fTmp[2][0] + fTmp[5][0];
mOut._34 = fTmp[0][1] - fTmp[1][1] + fTmp[2][1] + fTmp[5][1];
mOut._43 = fTmp[0][2] - fTmp[1][2] + fTmp[2][2] + fTmp[5][2];
mOut._44 = fTmp[0][3] - fTmp[1][3] + fTmp[2][3] + fTmp[5][3];
}
完整版:
int Strassen(int N, int **MatrixA, int **MatrixB, int **MatrixC)
{
int HalfSize = N/2;
int newSize = N/2;
if ( N <= 64 )//choosing the threshhold is extremely important, try N<=2 to see the result
{
MUL(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** AResult;
int** BResult;
//making a 1 diminsional pointer based array.
A11 = new int *[newSize];
A12 = new int *[newSize];
A21 = new int *[newSize];
A22 = new int *[newSize];
B11 = new int *[newSize];
B12 = new int *[newSize];
B21 = new int *[newSize];
B22 = new int *[newSize];
C11 = new int *[newSize];
C12 = new int *[newSize];
C21 = new int *[newSize];
C22 = new int *[newSize];
M1 = new int *[newSize];
M2 = new int *[newSize];
M3 = new int *[newSize];
M4 = new int *[newSize];
M5 = new int *[newSize];
M6 = new int *[newSize];
M7 = new int *[newSize];
AResult = new int *[newSize];
BResult = new int *[newSize];
int newLength = newSize;
//making that 1 diminsional pointer based array , a 2D pointer based array
for ( int i = 0; i < newSize; i++)
{
A11[i] = new int[newLength];
A12[i] = new int[newLength];
A21[i] = new int[newLength];
A22[i] = new int[newLength];
B11[i] = new int[newLength];
B12[i] = new int[newLength];
B21[i] = new int[newLength];
B22[i] = new int[newLength];
C11[i] = new int[newLength];
C12[i] = new int[newLength];
C21[i] = new int[newLength];
C22[i] = new int[newLength];
M1[i] = new int[newLength];
M2[i] = new int[newLength];
M3[i] = new int[newLength];
M4[i] = new int[newLength];
M5[i] = new int[newLength];
M6[i] = new int[newLength];
M7[i] = new int[newLength];
AResult[i] = new int[newLength];
BResult[i] = new int[newLength];
}
//splitting input Matrixes, into 4 submatrices each.
for (int i = 0; i < N / 2; i++)
{
for (int j = 0; j < N / 2; j++)
{
A11[i][j] = MatrixA[i][j];
A12[i][j] = MatrixA[i][j + N / 2];
A21[i][j] = MatrixA[i + N / 2][j];
A22[i][j] = MatrixA[i + N / 2][j + N / 2];
B11[i][j] = MatrixB[i][j];
B12[i][j] = MatrixB[i][j + N / 2];
B21[i][j] = MatrixB[i + N / 2][j];
B22[i][j] = MatrixB[i + N / 2][j + N / 2];
}
}
//here we calculate M1..M7 matrices .
//M1[][]
ADD( A11,A22,AResult, HalfSize);
ADD( B11,B22,BResult, HalfSize);
Strassen( HalfSize, AResult, BResult, M1 ); //now that we need to multiply this , we use the strassen itself .
//M2[][]
ADD( A21,A22,AResult, HalfSize); //M2=(A21+A22)B11
Strassen(HalfSize, AResult, B11, M2); //Mul(AResult,B11,M2);
//M3[][]
SUB( B12,B22,BResult, HalfSize); //M3=A11(B12-B22)
Strassen(HalfSize, A11, BResult, M3); //Mul(A11,BResult,M3);
//M4[][]
SUB( B21, B11, BResult, HalfSize); //M4=A22(B21-B11)
Strassen(HalfSize, A22, BResult, M4); //Mul(A22,BResult,M4);
//M5[][]
ADD( A11, A12, AResult, HalfSize); //M5=(A11+A12)B22
Strassen(HalfSize, AResult, B22, M5); //Mul(AResult,B22,M5);
//M6[][]
SUB( A21, A11, AResult, HalfSize);
ADD( B11, B12, BResult, HalfSize); //M6=(A21-A11)(B11+B12)
Strassen( HalfSize, AResult, BResult, M6); //Mul(AResult,BResult,M6);
//M7[][]
SUB(A12, A22, AResult, HalfSize);
ADD(B21, B22, BResult, HalfSize); //M7=(A12-A22)(B21+B22)
Strassen(HalfSize, AResult, BResult, M7); //Mul(AResult,BResult,M7);
//C11 = M1 + M4 - M5 + M7;
ADD( M1, M4, AResult, HalfSize);
SUB( M7, M5, BResult, HalfSize);
ADD( AResult, BResult, C11, HalfSize);
//C12 = M3 + M5;
ADD( M3, M5, C12, HalfSize);
//C21 = M2 + M4;
ADD( M2, M4, C21, HalfSize);
//C22 = M1 + M3 - M2 + M6;
ADD( M1, M3, AResult, HalfSize);
SUB( M6, M2, BResult, HalfSize);
ADD( AResult, BResult, C22, HalfSize);
//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 (int i = 0; i < N/2 ; i++)
{
for (int j = 0 ; j < N/2 ; j++)
{
MatrixC[i][j] = C11[i][j];
MatrixC[i][j + N / 2] = C12[i][j];
MatrixC[i + N / 2][j] = C21[i][j];
MatrixC[i + N / 2][j + N / 2] = C22[i][j];
}
}
// dont forget to free the space we alocated for matrices,
for (int i = 0; i < newLength; i++)
{
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[] C11[i];delete[] C12[i];delete[] C21[i];
delete[] C22[i];
delete[] M1[i];delete[] M2[i];delete[] M3[i];delete[] M4[i];
delete[] M5[i];delete[] M6[i];delete[] M7[i];
delete[] AResult[i];delete[] BResult[i] ;
}
delete[] A11;delete[] A12;delete[] A21;delete[] A22;
delete[] B11;delete[] B12;delete[] B21;delete[] B22;
delete[] C11;delete[] C12;delete[] C21;delete[] C22;
delete[] M1;delete[] M2;delete[] M3;delete[] M4;delete[] M5;
delete[] M6;delete[] M7;
delete[] AResult;
delete[] BResult ;
}//end of else
return 0;
}
int ADD(int** MatrixA, int** MatrixB, int** MatrixResult, int MatrixSize )
{
for ( int i = 0; i < MatrixSize; i++)
{
for ( int j = 0; j < MatrixSize; j++)
{
MatrixResult[i][j] = MatrixA[i][j] + MatrixB[i][j];
}
}
return 0;
}
int SUB(int** MatrixA, int** MatrixB, int** MatrixResult, int MatrixSize )
{
for ( int i = 0; i < MatrixSize; i++)
{
for ( int j = 0; j < MatrixSize; j++)
{
MatrixResult[i][j] = MatrixA[i][j] - MatrixB[i][j];
}
}
return 0;
}
int MUL( int** MatrixA, int** MatrixB, int** MatrixResult, int MatrixSize )
{
for (int i=0;i<MatrixSize ;i++)
{
for (int j=0;j<MatrixSize ;j++)
{
MatrixResult[i][j]=0;
for (int k=0;k<MatrixSize ;k++)
{
MatrixResult[i][j]=MatrixResult[i][j]+MatrixA[i][k]*MatrixB[k][j];
}
}
}
return 0;
}
void FillMatrix( int** MatrixA, int** MatrixB, int length)
{
for(int row = 0; row<length; row++)
{
for(int column = 0; column<length; column++)
{
MatrixB[row][column] = (MatrixA[row][column] = rand() %5);
//matrix2[row][column] = rand() % 2;//ba hazfe in khat 50% afzayeshe soorat khahim dasht
}
}
}
void PrintMatrix(int **MatrixA,int MatrixSize)
{
cout<<endl;
for(int row = 0; row<MatrixSize; row++)
{
for(int column = 0; column<MatrixSize; column++)
{
cout<<MatrixA[row][column]<<"\t";
if ((column+1)%((MatrixSize)) == 0)
cout<<endl;
}
}
cout<<endl;
}