我们把整数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(终值)

c语言:分治算法之大数相乘的更多相关文章

  1. 大数相乘算法C++版

    #include <iostream> #include <cstring> using namespace std; #define null 0 #define MAXN ...

  2. 大数相乘----C语言

    /* 大数相乘: 因为是大数,乘积肯定超出了能定义的范围,因此考虑用数组存储,定义三个数组,分别存储乘数,被乘数和积. 规则与平常手算一样,从个位开始分别与被乘数的每一位相乘,但是有一点不同的是:我们 ...

  3. 分治算法求乘方a^b 取余p(divide and conquer)

    传统的计算方法为循环n个a相乘.时间复杂度为O(n). 如用分治算法,效率可提升至O(lgn). 结合recursive有 double pow(int a, int n){ ) ; ) return ...

  4. Karatsuba乘法--实现大数相乘

    Karatsuba乘法 Karatsuba乘法是一种快速乘法.此算法在1960年由Anatolii Alexeevitch Karatsuba 提出,并于1962年得以发表.此算法主要用于两个大数相乘 ...

  5. leetcode 43 Multiply Strings 大数相乘

    感觉是大数相乘算法里面最能够描述.模拟演算过程的思路 class Solution { public String multiply(String num1, String num2) { if(nu ...

  6. POJ 2389 Bull Math(水~Java -大数相乘)

    题目链接:http://poj.org/problem?id=2389 题目大意: 大数相乘. 解题思路: java BigInteger类解决 o.0 AC Code: import java.ma ...

  7. 从两个平方算法到分治算法-java

    先来看看问题的来源,假设有这么一个数组: 1 2 -5 4 -2 3 -3 4 -15 我们要求出其中连续字数组的和的最大值 例如这么可以很明显看出 4+ –2 + 3 + –3 + 4 = 6 所有 ...

  8. 计算几何 平面最近点对 nlogn分治算法 求平面中距离最近的两点

    平面最近点对,即平面中距离最近的两点 分治算法: int SOLVE(int left,int right)//求解点集中区间[left,right]中的最近点对 { double ans; //an ...

  9. java版大数相乘

    在搞ACM的时候遇到大数相乘的问题,在网上找了一下,看到了一个c++版本的 http://blog.csdn.net/jianzhibeihang/article/details/4948267 用j ...

随机推荐

  1. 5. Linux文件目录管理和打包压缩与搜索命令

    1.touch:用于创建空白文件或设置文件的时间 举例:使用ls 命令查看一个文件的修改时间,然后修改这个文件,最后再通过touch命令把修改后的文件时间设置成修改之前的时间(很多黑客就是这样做的): ...

  2. Flink-v1.12官方网站翻译-P013-Timely Stream Processing

    及时的流处理 介绍 及时流处理是有状态流处理的一种扩展,其中时间在计算中起着一定的作用.其中,当你做时间序列分析时,当做基于某些时间段(通常称为窗口)的聚合时,或者当你做事件处理时,事件发生的时间很重 ...

  3. C#委托的进一步学习

    一.委托的说明 namespace LearningCsharp { class Program { //定义一个委托,使用delegate加上方法签名 //将委托理解为存储方法的"数组&q ...

  4. python爬虫selenium相关

    首先上很好用的selenium中文文档,基本上所有问题都能通过阅读此文档解决.可惜好像没找到翻译者名称. https://python-selenium-zh.readthedocs.io/zh_CN ...

  5. Java并发包源码学习系列:基于CAS非阻塞并发队列ConcurrentLinkedQueue源码解析

    目录 非阻塞并发队列ConcurrentLinkedQueue概述 结构组成 基本不变式 head的不变式与可变式 tail的不变式与可变式 offer操作 源码解析 图解offer操作 JDK1.6 ...

  6. CF-1354 E. Graph Coloring(二分图,背包,背包方案输出)

    E. Graph Coloring 链接 n个点m条边的无向图,不保证联通,给每个点标号1,2,3.1号点个数n1,2号点个数n2,3号点个数n3.且每条边的两点,标号之差绝对值为1.如果有合法方案, ...

  7. 2019牛客暑期多校训练营(第八场)A.All-one Matrices(dp)

    题意:又是最大01矩阵的模型了 这次要找的是极大0/1矩阵的个数 思路:我们像处理最大01矩阵那样处理一下边界 由于我们上左右已经无法再继续扩展 我们只需要用前缀和记录一下是否可以向下扩展(即判断当前 ...

  8. python的@是什么(函数装饰器)

    可以看菜鸟教程:https://www.runoob.com/w3cnote/python-func-decorators.html 还有一个实例:https://zhuanlan.zhihu.com ...

  9. 2019 Multi-University Training Contest 5——permutation 2

    传送门 题意: t组输入,之后每组例子有三个数n.x.y代表在一个以x为开头y为结尾的长为n的数组里面,开头和结尾数据已经固定,让你从1--n中找其他数据填入数组中 (每个数据不能重复使用),使它满足 ...

  10. Poj-3922 A simple stone game(k倍动态减法)

    题意: 游戏是这样的:两个玩家以一堆n个石头开始游戏.他们轮流从石堆里取石头,每次至少取一块.先走的人第一步最多可以拿n-1块石头.从那时起,一个玩家最多可以拿k倍于他的对手上次拿的石头.例如,如果一 ...