使用分治法和大整数求斐波那契数列的前n项

Author Avatar
w-xuefeng 11月 27, 2017
  • 在其它设备中阅读本文章

简介

  • 目的:使用 分治法大整数 求斐波那契数列的前n项。
  • 思路:使用数组存储大整数,将求斐波那契数列的第n项转换为求矩阵幂的运算。
  • 公式如下:
    function

引用头文件

    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>

定义结构体

    typedef struct largeNumber&#123;//大整数结构体	
        int length;//大整数的长度
        int *number;//使用数组存储大整数
    &#125;largeNum;

    typedef struct matrix&#123;//2*2矩阵结构体
        largeNum RowCol00,RowCol01,RowCol10,RowCol11;//由4个大整数组成
    &#125;Matrix;

函数的声明与定义

函数声明清单


    int max(int,int);
    //返回两个整数中较大的值
    
    int min(int,int);
    //返回两个整数中较小的值
    
    int sub(int,int);
    //返回两个整数的差的绝对值
    
    largeNum largeNumApplyRoom(largeNum);
    //为一个大整数申请空间,使用前必须定义长度
    
    largeNum initlargeNumber(int,int *);
    //初始化一个大整数
    
    largeNum initlargeNumToZero(largeNum,int);
    //初始化一个定长的大整数且各个数位都为0
    
    largeNum formatAddZero(largeNum,int);
    //格式话较短的大整数在其前补0到定长
    
    largeNum maxLargeNumLength(largeNum,largeNum);
    //返回两个大整数中长度较长的大整数
    
    largeNum minLargeNumLength(largeNum,largeNum);
    //返回两个大整数中长度较短的大整数
    
    largeNum largeNumAdd(largeNum,largeNum);
    //大整数的加法运算
    
    largeNum largeNumMultiply(largeNum, largeNum);
    //大整数的乘法运算
    
    int *largeNumCheckNum(int *,int);
    //检测大整数进位
    
    void largeNumPrintf(largeNum);
    //输出大整数
    
    Matrix initMatrix(largeNum,largeNum,largeNum,largeNum);
    //初始化一个2*2的矩阵
    
    Matrix matrixMultiply(Matrix,Matrix);
    //定义矩阵的乘法
    
    Matrix matrixPower(matrix,int);
    //矩阵的幂运算
    
    void matrixPrintf(Matrix);
    //输出矩阵

函数的定义

    largeNum largeNumApplyRoom(largeNum a)&#123;
    //为一个大整数申请空间,使用前必须定义长度    
        a.number = (int *)malloc(sizeof(int)*a.length);    
        return a;    
    &#125;
    
    largeNum initlargeNumber(int length,int *number)&#123;
    //初始化一个大整数    
        largeNum a;    	
        a.length = length;    
        a = largeNumApplyRoom(a);    
        for (int i = 0; i < a.length; i++)&#123;    		
            a.number[i] = number[i];    
        &#125;    
        return a;    
    &#125;
    
    largeNum initlargeNumToZero(largeNum a,int length)&#123;
    //初始化一个定长的大整数且各个数位都为0    
        a.length = length;    
        a = largeNumApplyRoom(a);    
        for (int i = 0; i < a.length; i++)	&#123;    		
            a.number[i] = 0;    
        &#125;    
        return a;    
    &#125;
    
    largeNum formatAddZero(largeNum a,int length)&#123;
    //格式话较短的大整数在其前补0到定长    
        if (length <= a.length )&#123;    
            return a;    
        &#125;    
        largeNum resault;    
        resault.length = length;    
        resault = initlargeNumToZero(resault,resault.length);    
        for (int i = length-1,j = a.length-1; j >= 0 ; i--,j--)&#123;    
            resault.number[i] = a.number[j];    
        &#125;    
        return resault;    
    &#125;
    
    int max(int a,int b)&#123;
    //返回两个整数中较大的值    
        return a >= b ? a : b ;    
    &#125;    
    
    int min(int a,int b)&#123;
    //返回两个整数中较小的值    
        return a <= b ? a : b ;    
    &#125;
    
    int sub(int a,int b)&#123;
    //返回两个整数的差的绝对值    
        return max(a,b) - min(a,b);    
    &#125;
    
    largeNum maxLargeNumLength(largeNum a,largeNum b)&#123;
    //返回两个大整数中长度较长的大整数    
        return a.length >= b.length? a : b ;
    &#125;
    
    largeNum minLargeNumLength(largeNum a,largeNum b)&#123;
    //返回两个大整数中长度较短的大整数    
        return a.length <= b.length? a : b ;    
    &#125;
    
    largeNum largeNumAdd(largeNum a,largeNum b)&#123;
    //大整数的加法运算    
        largeNum sum;    
        if (a.length == b.length)&#123;    
            sum.length = a.length + 1;    
            sum = initlargeNumToZero(sum,sum.length);    
            for (int i = a.length - 1; i >= 0; i--)&#123;    
                sum.number[i+1] += (a.number[i]+ b.number[i]);    
                if (sum.number[i+1] > 9)&#123;    
                    sum.number[i] +=  (sum.number[i+1]/10);    
                    sum.number[i+1] %= 10;    
                &#125;    			
            &#125;    
            return sum;    	
        &#125;else&#123;    
            return largeNumAdd(formatAddZero(minLargeNumLength(a,b),max(a.length,b.length)),maxLargeNumLength(a,b));
        &#125;    
    &#125;
    
    int *largeNumCheckNum(int *a,int length)&#123;
    //检测大整数进位    
        for (int i = length-1; i >= 1; i--)&#123;    
            if (a[i] > 9)&#123;    
                a[i-1] += (a[i]/10);    
                a[i] %= 10;    
            &#125;    
        &#125;    	
        if (a[0] > 9)&#123;    
                int *b;    
                b = (int*)malloc(sizeof(int)*(length+1));    
                b[0] = a[0]/10;
                b[1] = a[0]%10;    
                for (int j = 2; j < length+1; j++)&#123;    				
                    b[j] = a[j-1];    
                &#125;    
                free(a);    
                return b;
        &#125;
        return a;    
    &#125;
    
    largeNum largeNumMultiply(largeNum a, largeNum b)&#123;
    //大整数的乘法    
        largeNum product;    
        product.length = a.length + b.length;    
        int **tempProduct;    
        tempProduct = (int**)malloc(sizeof(int*)*a.length);    
        for (int t = 0; t < a.length; t++)&#123;    
            tempProduct[t] = (int*)malloc(sizeof(int)*b.length);    
        &#125;    
        product = initlargeNumToZero(product,product.length);    
        for (int j = b.length - 1; j >= 0; j--)&#123;    		
            for (int i = a.length - 1; i >= 0; i--)&#123;    			
                tempProduct[i][j] = a.number[i] * b.number[j];    
                product.number[i+j+1] += tempProduct[i][j];    
            &#125;    
        &#125;
    
        product.number = largeNumCheckNum(product.number,product.length);    
        return product;
    &#125;
    
    void largeNumPrintf(largeNum a)&#123;
     //输出大整数    
        int sign = 0;    
        for (int i = 0; i < a.length; i++)&#123;    
            if (a.number[i] != 0)&#123;    
                sign = 1;    
            &#125;
            if(!sign)&#123;
                if (i+1 == a.length)&#123;    
                    printf("0");break;
                &#125;    
                continue;    
            &#125;    
            printf("%d", a.number[i]);    
        &#125;    
    &#125;
    
    Matrix initMatrix(largeNum a,largeNum b,largeNum c,largeNum d)&#123;
    //初始化一个2*2的矩阵
        Matrix matrix;    
        matrix.RowCol00 = a;
        matrix.RowCol01 = b;
        matrix.RowCol10 = c;
        matrix.RowCol11 = d;    
        return matrix;
    &#125;
    
    void matrixPrintf(Matrix a)&#123;
    //输出矩阵    
        printf("|");largeNumPrintf(a.RowCol00);printf("\t");largeNumPrintf(a.RowCol01);printf("|\n");    
        printf("|");largeNumPrintf(a.RowCol10);printf("\t");largeNumPrintf(a.RowCol11);printf("| ");    
    &#125;
    
    Matrix matrixMultiply(Matrix a,Matrix b)&#123;
    //定义矩阵的乘法    
        Matrix product;    
        product.RowCol00 = largeNumAdd(largeNumMultiply(a.RowCol00,b.RowCol00),largeNumMultiply(a.RowCol01,b.RowCol10));
        product.RowCol01 = largeNumAdd(largeNumMultiply(a.RowCol00,b.RowCol01),largeNumMultiply(a.RowCol01,b.RowCol11));
        product.RowCol10 = largeNumAdd(largeNumMultiply(a.RowCol10,b.RowCol00),largeNumMultiply(a.RowCol11,b.RowCol10));
        product.RowCol11 = largeNumAdd(largeNumMultiply(a.RowCol10,b.RowCol01),largeNumMultiply(a.RowCol11,b.RowCol11));    
        return product;
    &#125;
    
    Matrix matrixPower(matrix a,int n)&#123;
    //定义矩阵的幂运算,这里用到了分治思想    
        if (n==1)&#123;    
            return a;    
        &#125;else if (n==2)&#123;    
            return matrixMultiply(a,a);    
        &#125;else if(n > 2 && n % 2 == 0)&#123;    
            return matrixMultiply(matrixPower(a,n/2),matrixPower(a,n/2));    
        &#125;else&#123;    
            return matrixMultiply(matrixMultiply(matrixPower(a,(n-1)/2),matrixPower(a,(n-1)/2)),a);    
        &#125;
    
    &#125;    

主函数


    void feibonaqi(int n)&#123;
        largeNum a,b,c,d;
        Matrix resault;
        int Anumber[1] = &#123;1&#125;;int Bnumber[1] = &#123;1&#125;;
        int Cnumber[1] = &#123;1&#125;;int Dnumber[1] = &#123;0&#125;;
        a = initlargeNumber(1,Anumber);b = initlargeNumber(1,Bnumber);
        c = initlargeNumber(1,Cnumber);d = initlargeNumber(1,Dnumber);	
        //初始化四个大整数1,1,1,0  
        Matrix matrix = initMatrix(a,b,c,d);	
        //初始化矩阵
        resault = matrixPower(matrix,n-1);
        //计算矩阵的(n-1)次方
        matrixPrintf(matrix);printf("^");printf("(%d-1)\t", n);printf("=\n\n");
        matrixPrintf(resault);
        //输出结果矩阵
        printf("\n\n");
        printf("f(%d)=",n);
        largeNumPrintf(resault.RowCol00);
        //输出斐波那契数列第n项结果
        printf("\n\n");
    &#125;

    int main()&#123;
        int maxI;
        printf("input a number to be max item:\n");
        scanf("%d",&maxI);	
        for (int i = 1; i <= maxI; ++i)&#123;
            feibonaqi(i);
        &#125;
        return 0;
    &#125;

测试截图

feibo

feibo

本博客遵循署名 4.0 协议国际版 (CC BY 4.0)协议
本文链接:https://xuefeng.is-a.dev/archives/feibo

(●'◡'●)
如果你觉得不错或者对你有帮助, 你可以替我买一杯咖啡 ☕
If you think it's good or helpful,   you can buy me a cup of coffee ☕
buy me a coffce via ailpay Ailpay
buy me a coffce via wechat Wechat