分治法-大整数乘法

分治法-大整数乘法问题分析:在计算机上处理一些大数据相乘时,由于计算机硬件的限制,不能直接进行相乘得到想要的结果。可以将一个大的整数乘法分而治之,将大问题变成小问题,变成简单的小数乘法再进行合并,从而解决上述问题。当分解到只有一位数时,乘法就很简单了。算法设计:分解:首先将2个大整数a(n位)、b(m位)分解为两部分:ah和al、bh和blah表示大整数a的高位,al表示大整数a的…

大家好,又见面了,我是你们的朋友全栈君。

问题分析:

在计算机上处理一些大数据相乘时,由于计算机硬件的限制,不能直接进行相乘得到想要的结果。可以将一个大的整数乘法分而治之,将大问题变成小问题,变成简单的小数乘法再进行合并,从而解决上述问题。

分治法-大整数乘法

当分解到只有一位数时,乘法就很简单了。

算法设计:

分解:

首先将2个大整数a(n位)、b(m位)分解为两部分:ah和al、bh和bl

ah表示大整数a的高位,al表示大整数a的低位,a=ah*10^{\frac{n}{2}}+al,ah、al为n/2位。

bh表示大整数b的高位,bl表示大整数b的低位,b=bh*10^{\frac{m}{2}}+bl,bh、bl为m/2位。

2个大整数a(n位)、b(m位)相乘转换成了4个乘法运算ah*bh、ah*bl、al*bh、al*bl,而乘数的位数变为了原来的一半。

求解子问题:

继续分解两个乘法运算,直到分解有一个乘数位1位数时停止分解,进行乘法运算并记录结果。

合并:

将计算出的结果相加并回溯,求出最终结果。

#include<stdlib.h>
#include<cstring>
#include <iostream>

using namespace std;
#define M 100
char sa[1000];
char sb[1000];
typedef struct _Node {
    int s[M];
    int l;
    int c;
} Node, *pNode;

void cp(pNode src, pNode des, int st, int l) {
    int i, j;
    for (i = st, j = 0; i < st + l; i++, j++) {
        des->s[j] = src->s[i];
    }
    des->l = l;
    des->c = st + src->c;
}

void add(pNode pa, pNode pb, pNode ans) {
    int i, cc, k, palen, pblen, len;
    int ta, tb;
    pNode temp;
    //保证pa是高次幂
    if ((pa->c < pb->c)) {
        temp = pa;
        pa = pb;
        pb = temp;
    }
    ans->c = pb->c;  //结果的幂取最少的幂
    cc = 0;
    palen = pa->l + pa->c; //pa的长度
    pblen = pb->l + pb->c; //pb的长度
    //选取最长的长度
    if (palen > pblen)
        len = palen;
    else
        len = pblen;
    k = pa->c - pb->c; 
    //k是幂差,len是最长的位数
    for (i = 0; i < len - ans->c; i++) {
        if (i < k)
            ta = 0;
        else
            ta = pa->s[i - k];
        if (i < pb->l)
            tb = pb->s[i];
        else
            tb = 0;
        if (i >= pa->l + k)
            ta = 0;
        ans->s[i] = (ta + tb + cc) % 10;
        cc = (ta + tb + cc) / 10;
    }
    if (cc)
        ans->s[i++] = cc;
    ans->l = i;
}

void mul(pNode pa, pNode pb, pNode ans) {
    int i, cc, w;
    int ma = pa->l >> 1, mb = pb->l >> 1;
    Node ah, al, bh, bl;
    Node t1, t2, t3, t4, z;
    pNode temp;
    if (!ma || !mb) {
    //如果pa是一位数,则和pb交换
        if (!ma) {
            temp = pa;
            pa = pb;
            pb = temp;
        }
        ans->c = pa->c + pb->c;
        w = pb->s[0]; //pb必为一位数
        cc = 0;
        for (i = 0; i < pa->l; i++) {
            //pa必为2位数以上
            ans->s[i] = (w * pa->s[i] + cc) % 10;
            cc = (w * pa->s[i] + cc) / 10;
        }
        if (cc)
            ans->s[i++] = cc;
        ans->l = i;
        return;
    }
    cp(pa, &ah, ma, pa->l - ma); //高位升幂
    cp(pa, &al, 0, ma);           //低位幂不变
    cp(pb, &bh, mb, pb->l - mb);
    cp(pb, &bl, 0, mb);

    mul(&ah, &bh, &t1); 
    mul(&ah, &bl, &t2);
    mul(&al, &bh, &t3);
    mul(&al, &bl, &t4);

    add(&t3, &t4, ans);
    add(&t2, ans, &z);
    add(&t1, &z, ans);
}


int main() {
    Node ans, a, b;
    cout << "输入大整数 a:" << endl;
    cin >> sa;
    cout << "输入大整数 b:" << endl;
    cin >> sb;
    a.l = strlen(sa);
    b.l = strlen(sb);
    int z = 0, i;
    for (i = a.l - 1; i >= 0; i--)
        a.s[z++] = sa[i] - '0';
    a.c = 0;
    z = 0;
    for (i = b.l - 1; i >= 0; i--)
        b.s[z++] = sb[i] - '0';
    b.c = 0;
    mul(&a, &b, &ans);
    cout << "最终结果为:";
    for (i = ans.l - 1; i >= 0; i--)
        cout << ans.s[i];
    cout << endl;
    return 0;
}

代码解释:

1、将两个输入的大数,倒序存储在数组s[]中,l表示长度,c表示幂,c初始为0。

2、cp函数:将一个n位的数,分成两个n/2的数并存储,记录它的长度和次幂。

3、mul函数,不断地分解,直到有一个乘数为1位数时停止分解,进行乘法并记录结果。

4、add函数,将分解得到的数,进行相加合并。

代码流程:

初始化:将a、b倒序存储在数组a.s[],b.s[]中。

分治法-大整数乘法

分解:cp函数:将一个n位的数,分成两个n/2的数并存储,记录它的长度和次幂。ah表示高位,al表示低位,l用来表示数的长度,c表示次幂。

分治法-大整数乘法

转换为4次乘法运算:ah*bh,ah*bl,al*bh,al*bl:

分治法-大整数乘法

 求解子问题:

ah*bh,ah*bl,al*bh,al*bl

分治法-大整数乘法

继续求解子问题:

上述4个乘法运算都有一个乘数为1位数,可以直接进行乘法运算。以ahh*bhh为例:

分治法-大整数乘法3首先和1相乘得到3存储在下面数组的第0位,然后3和4相乘得到12,先存储12%10=2,然后存储进位12/10=1,那样结果就为倒序的321,结果的次幂是两个乘数次幂之和

4个乘法运算结果如下图:

分治法-大整数乘法

合并:

合并子问题结果,返回给ah*bh,将上面4个乘法运算的结果加起来返回给ah*bh。

分治法-大整数乘法

由此得到ah*bh=13408×10^4。

用同样的方法求得ah*bl=832×10^2,al*bh=32682×10^2,al*bl=2028。将这4个子问题结果加起来,合并得到原问题a*b=137433428。

算法复杂度分析:

假设两个n位大整数相乘的时间复杂度为T(n),则:

分治法-大整数乘法

 当n>1时,可以递推求解如下:

分治法-大整数乘法

 递推最终的规模为1,令n=2^x,则x=logn,那么有:

分治法-大整数乘法

大整数乘法的时间复杂度为O(n^2)。

空间复杂度:

程序中变量占用了一些辅助空间,都是常数阶,但合并时结点数组占用的辅助空间为O(n),递归调用所使用的栈空间时O(logn)。所以,空间复杂度为O(n)。

欢迎打赏:

分治法-大整数乘法

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/136924.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Failed to load JavaHL Library. These are the errors that were encountered: no libsvnjavahl-1 in java

    Failed to load JavaHL Library. These are the errors that were encountered: no libsvnjavahl-1 in javaFailed to load JavaHL Library. These are the errors that were encountered: no libsvnjavahl-1 in java

    2022年4月23日
    40
  • 什么是SOAP,有哪些应用

    什么是SOAP,有哪些应用SOAP是一种轻量级协议,用于在分散型、分布式环境中交换结构化信息。SOAP利用XML技术定义一种可扩展的消息处理框架,它提供了一种可通过多种底层协议进行交换的消息结构。这种框架的设计思想是要独立于任何一种特定的编程模型和其他特定实现的语义。SOAP规范还定义了HTTP消息是怎样传输SOAP消息的。MSMQ、SMTP、TCP/IP都可以做SOAP的传输协议。转载于:ht…

    2022年7月24日
    6
  • sql mysql创建 视图索引_SQLServer中在视图上使用索引(转载)「建议收藏」

    sql mysql创建 视图索引_SQLServer中在视图上使用索引(转载)「建议收藏」在SQLServer中,视图是一个保存的T-SQL查询。视图定义由SQLServer保存,以便它能够用作一个虚拟表来简化查询,并给基表增加另一层安全。但是,它并不占用数据库的任何空间。实际上,在你查询它之前,视图并不做任何事情。索引视图在SQLServer2000和2005中,你能够给视图增加索引。但是,如果视图只是一个保存在数据库中的查询定义,在运行前没有自己的数据,你如何给那个定义建立…

    2022年7月22日
    17
  • stat函数百度百科_strel函数

    stat函数百度百科_strel函数stat函数的简单使用stat函数是用来获取文件的各种属性的一个linux下的常用API函数。函数原型为intstat(constchar*path,structstat*buf);stat定义如下:structstat{dev_tst_dev;//文件的设备编号ino_tst_ino;//节点mode_tst_m…

    2022年8月21日
    5
  • 什么是单页面应用开发工具_单页面和多页面的区别及优缺点

    什么是单页面应用开发工具_单页面和多页面的区别及优缺点单页面应用开发MPA与SPA简介MPAMPA(Multi-pageApplication)多页面应用指的就是最传统的HTML网页设计,早期的网站都是这样的设计,所之称为「网页设计」。使用MPA在使用者浏览Web时会依据点击需求切换页面,浏览器会不停的重载页面(Reload),整个操作也常感觉卡卡。如果使用这样的设计在WebApp中,使用者体验比较差,整体流畅度扣分…

    2022年10月13日
    2
  • mysql基本总结

    mysql基本总结

    2022年1月27日
    47

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号