分治法-大整数乘法

分治法-大整数乘法问题分析:在计算机上处理一些大数据相乘时,由于计算机硬件的限制,不能直接进行相乘得到想要的结果。可以将一个大的整数乘法分而治之,将大问题变成小问题,变成简单的小数乘法再进行合并,从而解决上述问题。当分解到只有一位数时,乘法就很简单了。算法设计:分解:首先将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)
上一篇 2022年6月2日 下午8:36
下一篇 2022年6月2日 下午8:36


相关推荐

  • 基于MVP架构设计ASP.Net的应用研究

    基于MVP架构设计ASP.Net的应用研究

    2021年7月26日
    58
  • navicate premium 15 激活码【2021免费激活】「建议收藏」

    (navicate premium 15 激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.htmlMLZPB5EL5Q-eyJsaWNlbnNlSW…

    2022年3月21日
    354
  • VB实现关机程序

    VB实现关机程序下面是本人愿来写的关机程序可以适用于98/xp/2000,在程序中调用即可。现在操作系统多为2000或xp,所以需要特别注意的是应该先得到关机的特权:(要想弄懂下面的程序,先要具备vb调用api函数的知识……)其中:前面一些Public Declare都是api函数的声明.     Public Sub AdjustToken()子程序用来取得关机特权.     Public Sub Sh

    2022年7月22日
    13
  • 3D 页游测评报告

    3D 页游测评报告目前 能够实现 3D 页游的主流技术有 Silverlight XNA Flash HTML5 和 Unity3D 其中 Unity3D 作为一款专注于 3D 游戏的浏览器插件 近期在国内外页游产品线骚动异常 本人从多方收集到可注册的 Unity3D 页游测试发现 当下的 Unity3D 技术应用尤其在国内正遭遇着尴尬而无奈的窘迫境地 原因为何 大伙不妨先看看其中 7 款游戏测试数据 骑士的远征 国产 类型 SL

    2025年6月29日
    5
  • AI Agent开发完整教程:从零到一构建你的第一个智能助手

    AI Agent开发完整教程:从零到一构建你的第一个智能助手

    2026年3月15日
    1
  • 傅立叶变换的物理意义

    1、为什么要进行傅里叶变换,其物理意义是什么?傅立叶变换是数字信号处理领域一种很重要的算法。要知道傅立叶变换算法的意义,首先要了解傅立叶原理的意义。傅立叶原理表明:任何连续测量的时序或信号,都可以表

    2021年12月26日
    43

发表回复

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

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