c語言:分治算法之大數相乘


我們把整數A由規模n分為n1和n2,把整數B由規模m分為m1和m2,如下圖:

則A分為n1位的A1和n2位的A1,B分為m1位的B1和m2位的B2,如下式所示:

 

 

 以此類推,我們可以把A1、A2、B1、B2繼續划分,直至最小單位。(這里在編程時需要用遞歸來實現)

上面講的很清楚了,那么A和B的相乘就可以表示為:

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

char *result = '\0';
int  pr = 1;

void getFill(char *a,char *b,int ia,int ja,int ib,int jb,int tbool,int move){
    int  r,m,n,s,j,t;
    char *stack;
    // get(a,b,0,0,0,0,1,2)
    m = a[ia] - 48; // m=1
    if( tbool ){// 直接從結果數組的標志位填入,這里用了堆棧思想    這部分實現A1xB1
        r = (jb - ib > ja - ia) ? (jb - ib) : (ja - ia); // r=0
        stack = (char *)malloc(r + 4);  // 因為執行了getFill方法,此時ia=ja,說明兩個數必定其中一個是個位數,而jb-ib的值+1即另一個數的位數 for(r = j = 0,s = jb; s >= ib; r ++,s --){  // r=j=s=0;0>=0;r++,s++   r=1,s=-1
            n = b[s] - 48;  // n=4
            stack[r] = (m * n + j) % 10; //stack[0]=(1x4+0)%10=4  通過模10來獲取result[1]位置上的數
            j = (m * n + j) / 10;  // j=(1x4+0)/10 = 0  通過整除來獲取result[1]位置上的數,如果j=0,則只需要填寫result[1]位置的數;如果j不等於0,則將j放在
        }               //            result[1]位置,前面取模獲取的值放在result[2]所在的位置 if( j ){  // 如果j 不等於0,如j=1,stack[1]=1,則將stack[1]賦值給result[1],將stack[0]賦值個result[2].由於先有stack[0],再有stack[1],而使用時先用
            stack[r] = j;  // stack[1]=1       stack[1]再用stack[0],即先進后出,所以說使用了棧的思想。
            r ++;  // r=2
        }
        // r=1
        for(r --; r >= 0; r --,pr ++)  // r=0;0>=0; pr=2
            result[pr] = stack[r];  //result[1]=stack[0]=4 
        free(stack);
        // move=2 pr=2  由於A1xB1之后后面還要加00,故將result[1]后面的兩個字節空間賦值為\0.字符串是以\0作為結束標志的,在內存中,比如字符串“abc”,實際上是4個字節的空間abc\0
        for(move = move + pr; pr < move; pr ++) // move=4;2<4;pr++   pr=3  move=4;3<4;pr++   pr=4
            result[pr] = '\0';                  // result[2]='\0'    result[3]='\0'    
    }
    else{ //與結果的某幾位相加,這里不改變標志位 pr 的值     //這部分實現A2xB1,A1xB2,A2xB2
        r = pr - move - 1;
        for(s = jb,j = 0; s >= ib; r --,s --){
            n = b[s] - 48;
            t = m * n + j + result[r];
            result[r] = t % 10;
            j = t / 10;
        }
        for( ; j ; r -- ){
            t = j + result[r];
            result[r] = t % 10;
            j = t / 10;
        }
    }
}

int  get(char *a,char *b,int ia,int ja,int ib,int jb,int t,int move){
    int m,n,s,j;

    if(ia == ja){
        getFill(a,b,ia,ja,ib,jb,t,move);
        return 1;
    }
    else if(ib == jb){
        getFill(b,a,ib,jb,ia,ja,t,move);
        return 1;
    }
    else{ // 12x45   get(a,b,0,1,0,1,1,0)
        m = (ja + ia) / 2; //     m=0
        n = (jb + ib) / 2; //     m=0
        s = ja - m;           //     s=1
        j = jb - n;           //       j=1
        get(a,b,ia,m,ib,n,t,s + j + move); //     get(a,b,0,0,0,0,1,2)
        get(a,b,ia,m,n + 1,jb,0,s + move); //      get(a,b,0,0,1,1,0,1)
        get(a,b,m + 1,ja,ib,n,0,j + move); //      get(a,b,1,1,0,0,0,1)
        get(a,b,m + 1,ja,n + 1,jb,0,0 + move); // get(a,b,1,1,1,1,0,0)
    }
    return 0;
}

int  main(){
    char *a,*b;
    int  n,flag;

    a = (char *)malloc(1000);  // 分配所需的內存空間 1000字節
    b = (char *)malloc(1000);
    printf("The program will computer a*b\n");
    printf("Enter a b:");
    scanf("%s %s",a,b);
    result = (char *)malloc(strlen(a) + strlen(b) + 2);
    flag = pr = 1;
    result[0] = '\0';
    if(a[0] == '-' && b[0] == '-')
        get(a,b,1,strlen(a)-1,1,strlen(b)-1,1,0);
    if(a[0] == '-' && b[0] != '-'){
        flag = 0;
        get(a,b,1,strlen(a)-1,0,strlen(b)-1,1,0);
    }
    if(a[0] != '-' && b[0] == '-'){
        flag = 0;
        get(a,b,0,strlen(a)-1,1,strlen(b)-1,1,0);
    }
    if(a[0] != '-' && b[0] != '-')
        get(a,b,0,strlen(a)-1,0,strlen(b)-1,1,0); // get(a,b,0,1,0,1,1,0)
    if(!flag)
        printf("-");
    if( result[0] )
        printf("%d",result[0]);
    for(n = 1; n < pr ; n ++)
        printf("%d",result[n]);
    printf("\n");
    free(a);
    free(b);
    free(result);
    system("pause");
    return 0;
}
void getFill(char *a,char *b,int ia,int ja,int ib,int jb,int tbool,int move){
    int  r,m,n,s,j,t;
    char *stack;
    // get(a,b,0,0,1,1,0,1)   計算A1xB2
    m = a[ia] - 48; // m=1    m為A1的值
    if( tbool ){// 直接從結果數組的標志位填入,這里用了堆棧思想
        r = (jb - ib > ja - ia) ? (jb - ib) : (ja - ia); 
        stack = (char *)malloc(r + 4);
        for(r = j = 0,s = jb; s >= ib; r ++,s --){  
            n = b[s] - 48;  // n=4
            stack[r] = (m * n + j) % 10;
            j = (m * n + j) / 10;  
        }
        if( j ){
            stack[r] = j;
            r ++;
        }
        for(r --; r >= 0; r --,pr ++) 
            result[pr] = stack[r]; 
        free(stack);
        
        for(move = move + pr; pr < move; pr ++) 
            result[pr] = '\0';                   
    }
    else{ //與結果的某幾位相加,這里不改變標志位 pr 的值
        r = pr - move - 1;  // pr=4 move=1  r=4-1-1=2
        for(s = jb,j = 0; s >= ib; r --,s --){ // s=jb=1,j=0;1>=1;r--,s--
            n = b[s] - 48;   // n=5   n為B2的值
            t = m * n + j + result[r];  // t=1*5+0+result[2]=5+0=5
            result[r] = t % 10;  // result[2]=5   將兩個數相乘的結果模10得到result[2]上的值,
            j = t / 10;    // j=0   將兩個數相乘的結果整除10得到是否需要進一位,
        }
        // r=1,s=0
        for( ; j ; r -- ){
            t = j + result[r];
            result[r] = t % 10;
            j = t / 10;
        }
    }
}

void getFill(char *a,char *b,int ia,int ja,int ib,int jb,int tbool,int move){
    int  r,m,n,s,j,t;
    char *stack;
    // get(a,b,1,1,0,0,0,1)  計算A2xB1
    m = a[ia] - 48; // m=2   m為A2的值
    if( tbool ){// 直接從結果數組的標志位填入,這里用了堆棧思想
        r = (jb - ib > ja - ia) ? (jb - ib) : (ja - ia); 
        stack = (char *)malloc(r + 4);
        for(r = j = 0,s = jb; s >= ib; r ++,s --){  
            n = b[s] - 48; 
            stack[r] = (m * n + j) % 10;
            j = (m * n + j) / 10; 
        }
        if( j ){
            stack[r] = j;
            r ++;
        }
        // r=1
        for(r --; r >= 0; r --,pr ++) 
            result[pr] = stack[r];
        free(stack);
        for(move = move + pr; pr < move; pr ++) 
            result[pr] = '\0';                
    }
    else{ //與結果的某幾位相加,這里不改變標志位 pr 的值
        r = pr - move - 1;  // pr=4 move=1  r=4-1-1=2
        for(s = jb,j = 0; s >= ib; r --,s --){ // s=jb=0,j=0;0>=0;r--,s--
            n = b[s] - 48;   // n=4   n為B1的值
            t = m * n + j + result[r];  // t=2*4+0+result[2]=8+5=13   兩個數相乘的結果加上前面A1xB2的結果
            result[r] = t % 10;  // result[2]=3    將兩個數相乘的結果加上前面A1xB2的結果模10得到最后result[2]的值
            j = t / 10;    // j=1  r=1 s=-1   整除10看是否需要進一位,如果需要進一位,則將j與原來result[1]相加,result[1]再對10取模,即可確定result[1]的值
        }
        // r=1,s=-1
        for( ; j ; r -- ){
            t = j + result[r];  // t=1+4=5          
            result[r] = t % 10;  // result[1]=5
            j = t / 10;  // j=0 r=0
        }
    }
}


void getFill(char *a,char *b,int ia,int ja,int ib,int jb,int tbool,int move){
    int  r,m,n,s,j,t;
    char *stack;
    // get(a,b,1,1,1,1,0,0)   計算A2xB2
    m = a[ia] - 48; // m=2   m為A2的值
    if( tbool ){// 直接從結果數組的標志位填入,這里用了堆棧思想
        r = (jb - ib > ja - ia) ? (jb - ib) : (ja - ia); 
        stack = (char *)malloc(r + 4);
        for(r = j = 0,s = jb; s >= ib; r ++,s --){ 
            n = b[s] - 48;  
            stack[r] = (m * n + j) % 10;
            j = (m * n + j) / 10; 
        }
        if( j ){
            stack[r] = j;
            r ++;
        }
        for(r --; r >= 0; r --,pr ++)  
            result[pr] = stack[r]; 
        free(stack);
        
        for(move = move + pr; pr < move; pr ++) 
            result[pr] = '\0';               
    }
    else{ //與結果的某幾位相加,這里不改變標志位 pr 的值
        r = pr - move - 1;  // pr=4 move=0  r=4-0-1=3
        for(s = jb,j = 0; s >= ib; r --,s --){ // s=jb=1,j=0;1>=1;r--,s--
            n = b[s] - 48;   // n=5    n為B2的值
            t = m * n + j + result[r];  // t=2*5+0+result[3]=10+0=10  將兩個數相乘再加上原來這個位置的值
            result[r] = t % 10;  // result[3]=0   模10得到這個位置上的值,
            j = t / 10;    // j=1  r=2 s=0        整除10看是否需要進一位,如果需要進一位,則j+result[2]得到最終的值
        } 
        // r=2,s=-1
        for( ; j ; r -- ){
            t = j + result[r];  // t=1+result[2]=1+3=4          
            result[r] = t % 10;  // result[2]=4
            j = t / 10;  // j=0 r=1
        }
    }
}

總結:

get(a,b,0,0,0,0,1,2) 1x4 00 result[1]=4(初值)
get(a,b,0,0,1,1,0,1) 1x5  0  result[2]=5(初值)
get(a,b,1,1,0,0,0,1) 2x4  0  result[2]=3(初值)  result[1]=5  (終值)
get(a,b,1,1,1,1,0,0) 2x5      result[3]=0(終值) result[2]=4(終值)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM