分治策略(归并排序,二分查找,x的n次方,斐波那契(Fibonacci)数列,斯特拉森(Strassen)矩阵乘法)

   权当笔记!


(一)归并排序:

#include <stdio.h>
#include <stdlib.h>
#include <string>
typedef long long LL;
using namespace std;

/* T(n) = 2T(n/2) + ⊙(n) = nlog(n) */
void Merge_sort(int *A,int x,int y,int *t) /* x表示左闭,y表示右开 */
{  
    if(y - x > 1){  
        int m = x + (y - x) / 2;  
        int p = x,q = m,i = x;  
        Merge_sort(A, x, m, t);  
        Merge_sort(A, m, y, t);  
        while(p < m || q < y){  
            if(q >= y || (p < m && A[p] <= A[q]))
                t[i++] = A[p++];  
            else t[i++] = A[q++];  
        }  
        for(i=x; i<y; i++)
            A[i] = t[i];  
    }  
}  

int main()
{
	int t[15];
	int s[] = {4, 1, 7, 6, 3, 8, 2, 5, 0, 9};
	Merge_sort(s, 0, 10, t);
	int i;
	for(i=0; i<10; i++)
		printf("%d ", s[i]);
	printf("\n");
	return 0;
}


(二)二分查找:

用递归体会一下其中的分治思想,当然也可以用while循环解决!

#include <stdio.h>
#include <stdlib.h>
#include <string>
typedef long long LL;
using namespace std;

/* T(n) = T(n/2) + ⊙(1) = log(n) */

int Binary_find(int key, int left, int right, int *a)
{
	int mid = left + (right - left) / 2;
	if(a[mid] == key) return mid;
	else if(a[mid] > key) return Binary_find(key, left, mid - 1, a);
	else if(a[mid] < key) return Binary_find(key, mid + 1, right, a);
}

int main()
{
	int a[] = {1, 3, 4, 6, 7, 9, 12, 14, 23, 24};
	int i;
	int ans;
	for(i=0; i<8; i++){
		ans = Binary_find(a[i], 0, 7, a);
		printf("%d\n", ans);
	}
	return 0;
}

(三)x的n次方:

库函数<math.h>里面的double pow(double x, double y) 更加完美,指数可以是浮点型。这里手写个double Pow(double x, int n)。

#include <stdio.h>
#include <stdlib.h>
#include <string>
typedef long long LL;
using namespace std;

/* T(n) = T(n/2) + ⊙(1) = log(n) */

double f(double x, int n)
{
	if(1 == n) return x;
	int mid = (n>>1);
	double s = f(x, mid);
	if(n & 1) return s * s * x;
	else return s * s;
}

double Pow(double x, int n)
{
	if(0 == x && n > 0) return 0.0;
	else if(0 == n) return 1.0;
	else if(n > 0) return f(x, n);
	else if(n < 0) return (1/f(x, -n));
}

int main()
{
	double x;
	int n;
	while(~scanf("%lf%d", &x, &n)){
		printf("%0.6lf\n", Pow(x, n));
		printf("%0.6lf\n", pow(x, n));
	}
}

(四)斐波那契(Fibonacci)数列:

递归是最愚蠢的做法,迭代可以是 ⊙(n) 的复杂度,矩阵快速幂可达到 ⊙(log(n)) 的复杂度。

F(n) 表示第n个斐波那契数则有这样的关系:

矩阵   F(N+1)  F(N)          =        矩阵    1     1    的 N 次方

           F(N)       F(N-1)                            1      0

可用数学归纳法证明。所以结果就是普通的矩阵快速幂。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <iostream>
using namespace std;
int cnt;

/* 时间复杂度为指数级 */
LL Fibonacci(int n)
{
	cnt++;
	if(1 == n || 2 == n) return 1;
	else return Fibonacci(n - 1) + Fibonacci(n - 2);
}

/* T(n) = ⊙(n) */
LL Fibonacci1(int n)
{
	LL a[100000];
	a[1] = a[2] = 1;
	int i;
	for(i=3; i<=n; i++)
		a[i] = a[i - 1] + a[i - 2];
	return a[n];
}

typedef struct
{
    LL a[2][2];
}Matrix;

Matrix A, B;

Matrix Matrix_mul(Matrix X, Matrix Y)  
{  
    Matrix tmp;  
    memset(tmp.a, 0, sizeof(tmp));  
    int i,j,k;  
    for(i=0; i<2; i++)  
        for(j=0; j<2; j++)  
            for(k=0; k<2; k++)
                tmp.a[i][j] += X.a[i][k] * Y.a[k][j];  
    return tmp;  
}  

/* T(n) = ⊙(logn) */
LL Fibonacci2(int n)
{
	A.a[0][0] = 1;
	A.a[0][1] = 1;
	A.a[1][0] = 1;
	A.a[1][1] = 0;
	B.a[0][0] = 1;
	B.a[0][1] = 0;
	B.a[1][0] = 0;
	B.a[1][1] = 1;
	while(n)
	{
		if(n & 1) B = Matrix_mul(B, A);
		A = Matrix_mul(A, A);
		n >>= 1;
	}
	return B.a[0][0];
}

int main()
{
	int i;
	int text = 4;
	LL ans = Fibonacci1(text);
	//long begtime = clock();
	FILETIME beg,end;  
    GetSystemTimeAsFileTime(&beg);  
	for(i=0; i<100000; i++)
		Fibonacci2(text);
    GetSystemTimeAsFileTime(&end);
    long time = (end.dwLowDateTime-beg.dwLowDateTime);  
	//long endtime = clock();
    //cout<<endtime - begtime<<endl;  
	cout << time <<endl;
	cout << ans <<endl;
}

(五)斯特拉森(Strassen)矩阵乘法:

参考了网上的做法,重写了此矩阵乘法,用了一个4阶矩阵验证。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <iostream>
typedef long long LL;
using namespace std;

typedef int INT;
#define N 4 

typedef struct matrix
{
	INT a[N][N];
	matrix()
	{
		memset(a, 0, sizeof(a));
	}
}Matrix;

void Matrix_mul(const Matrix A, const Matrix B, Matrix &C)
{
	memset(C.a, 0, sizeof(C.a));
	int i,j,k;
	for(i=0; i<2; i++)
		for(j=0; j<2; j++)
			for(k=0; k<2; k++)
				C.a[i][j] += A.a[i][k] * B.a[k][j];
}

void Matrix_add(const int n, const Matrix A, const Matrix B, Matrix &C)
{
	memset(C.a, 0, sizeof(C.a));
	int i,j;
	for(i=0; i<n; i++)
		for(j=0; j<n; j++)
			C.a[i][j] = A.a[i][j] + B.a[i][j];
}

void Matrix_sub(const int n, const Matrix A, const Matrix B, Matrix &C)
{
	memset(C.a, 0, sizeof(C.a));
	int i,j;
	for(i=0; i<n; i++)
		for(j=0; j<n; j++)
			C.a[i][j] = A.a[i][j] - B.a[i][j];
}

void Strassen(INT n, const Matrix A, const Matrix B, Matrix &C)
{
	Matrix A11, A12, A21, A22;
	Matrix B11, B12, B21, B22;
	Matrix C11, C12, C21, C22;
	Matrix M1, M2, M3, M4, M5, M6, M7;
	Matrix At, Bt, Mt, Mt1;

	if(2 == n) Matrix_mul(A, B, C);
	else{
		n /= 2;
		int i, j;
		for(i=0; i<n; i++)
			for(j=0; j<n; j++){
				A11.a[i][j] = A.a[i][j];
				A12.a[i][j] = A.a[i][j + n];
				A21.a[i][j] = A.a[i + n][j];
				A22.a[i][j] = A.a[i + n][j + n];
				B11.a[i][j] = B.a[i][j];
				B12.a[i][j] = B.a[i][j + n];
				B21.a[i][j] = B.a[i + n][j];
				B22.a[i][j] = B.a[i + n][j + n];
			}

		Matrix_sub(n, A12, A22, At);
		Matrix_add(n, B21, B22, Bt);
		Strassen(n, At, Bt, M1);

		Matrix_add(n, A11, A22, At);
		Matrix_add(n, B11, B22, Bt);
		Strassen(n, At, Bt, M2);

		Matrix_sub(n, A11, A21, At);
		Matrix_add(n, B11, B12, Bt);
		Strassen(n, At, Bt, M3);

		Matrix_add(n, A11, A12, At);
		Strassen(n, At, B22, M4);

		Matrix_sub(n, B12, B22, Bt);
		Strassen(n, A11, Bt, M5);

		Matrix_sub(n, B21, B11, Bt);
		Strassen(n, A22, Bt, M6);

		Matrix_add(n, A21, A22, At);
		Strassen(n, At, B11, M7);

		/* sub_C */
		Matrix_add(n, M6, M1, Mt);
		Matrix_add(n, Mt, M2, Mt1);
		Matrix_sub(n, Mt1, M4, C11);

		Matrix_add(n, M5, M4, C12);

		Matrix_add(n, M6, M7, C21);

		Matrix_sub(n, M5, M3, Mt);
		Matrix_add(n, Mt, M2, Mt1);
		Matrix_sub(n, Mt1, M7, C22);

		for(i=0; i<n; i++)
			for(j=0; j<n; j++){
				C.a[i][j] = C11.a[i][j];
				C.a[i][j + n] = C12.a[i][j];
				C.a[i + n][j] = C21.a[i][j];
				C.a[i + n][j + n] = C22.a[i][j];
			}
	}
}

int main()
{
	Matrix A, B, C;
	A.a[0][0] = 1;
	A.a[0][1] = 0;
	A.a[0][2] = 2;
	A.a[0][3] = 1;
	A.a[1][0] = 0;
	A.a[1][1] = 3;
	A.a[1][2] = 1;
	A.a[1][3] = 2;
	A.a[2][0] = 0;
	A.a[2][1] = 0;
	A.a[2][2] = 2;
	A.a[2][3] = 2;
	A.a[3][0] = 2;
	A.a[3][1] = 3;
	A.a[3][2] = 0;
	A.a[3][3] = 1;

	B.a[0][0] = 2;
	B.a[0][1] = 1;
	B.a[0][2] = 0;
	B.a[0][3] = 0;
	B.a[1][0] = 0;
	B.a[1][1] = 1;
	B.a[1][2] = 1;
	B.a[1][3] = 1;
	B.a[2][0] = 1;
	B.a[2][1] = 0;
	B.a[2][2] = 2;
	B.a[2][3] = 2;
	B.a[3][0] = 3;
	B.a[3][1] = 0;
	B.a[3][2] = 2;
	B.a[3][3] = 1;

	Strassen(N, A, B, C);

	int i,j;
	for(i=0; i<N; i++){
		for(j=0; j<N; j++)
			printf("%-4d", C.a[i][j]);
		printf("\n");
	}
	return 0;
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值