分治法-大整数乘法

article/2025/9/14 6:44:48

问题分析:

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

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

算法设计:

分解:

首先将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;elselen = pblen;k = pa->c - pb->c; //k是幂差,len是最长的位数for (i = 0; i < len - ans->c; i++) {if (i < k)ta = 0;elseta = pa->s[i - k];if (i < pb->l)tb = pb->s[i];elsetb = 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=13408x10^4。

用同样的方法求得ah*bl=832x10^2,al*bh=32682x10^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)。

欢迎打赏:

 


http://chatgpt.dhexx.cn/article/5XgJZlAU.shtml

相关文章

大整数乘法

设计一个有效的算法&#xff0c;可以计算两个n位大整数的乘法运算。 如果按照我们日常的计算方法&#xff0c;应该就是将两个数逐位相乘&#xff0c;最后加起来得到最终的结果。由于是大整数乘法&#xff0c;那么我们用string来存储这两个数&#xff0c;因为是要做乘法&#x…

大整数乘法算法

一 转换为二进制求&#xff0c;推导出的公式适合十进制计算 设X和Y都是n位的二进制整数&#xff0c;现在要计算它们的乘积XY。我们可以用小学所学的方法来设计一个计算乘积XY的算法&#xff0c;但是这样做计算步骤太多&#xff0c;显得效率较低。如果将每2个1位数的乘法或加法看…

大整数乘法的详解

一.问题 由于编程语言提供的基本数值数据类型表示的数值范围有限&#xff0c;不能满足较大规模的高精度数值计算&#xff0c;因此需要利用其他方法实现高精度数值的计算&#xff0c;于是产生了大数运算。尤其是乘法运算&#xff0c;下面就是大整数的乘法的过程&#xff08;加 …

Ubuntu server树莓派版本默认用户名密码及密码修改

树莓派安装的Ubuntu server镜像&#xff0c; 默认的初始用户及密码&#xff1a; ubuntu # user ubuntu # passwd默认信息查看 在烧入镜像的内存卡中&#xff0c; 可以查看到默认的用户信息 默认密码修改 在登录界面 输入初始化的用户名和密码后&#xff0c; 会提示是第一…

2022.04.04树莓派最新镜像问题,树莓派如何设置初始化的账户和密码

树莓派最新的arm64位系统&#xff0c;更新时间是2022年4月4日&#xff0c;这个版本的树莓派取消了默认的账户密码&#xff0c;也就是原来一直使用的pi和对应的默认密码raspberry被取消了&#xff0c;现在如果想要使用的话必须自己设置&#xff0c;下面有两种方法可以设置自己的…

树莓派启用无密码 sudo

启用无密码 sudo&#xff0c;可以在不提供密码的情况下在树莓派上运行程序。 登录 Raspberry Pi 命令行界面。假设 Raspberry Pi 的默认用户名和密码分别为 pi 和 raspberry。在命令行界面中&#xff0c;键入以下命令&#xff1a; sudo nano /etc/sudoers 3. 通过添加以下行启…

最新树莓派系统PUTTY用默认用户名和密码登录不上的解决方法

最近我在树莓派配置深度学习环境&#xff0c;然后直接载了别的博主的树莓派镜像&#xff0c;发现博主给的用户名&#xff0c;密码登不上&#xff0c;于是乎&#xff0c;就打算自己配置深度学习环境&#xff0c;结果我下在了最新版本的树莓派镜像系统&#xff08;2022-04-04-ras…

树莓派默认账号密码串口登录不了的Bug解决

一、问题总结 我用的树莓派型号是树莓派Pi3,刷机用的镜像是2023版的&#xff0c;23版的镜像文件较大8G的SD卡不够用 问题描述&#xff1a;刷完机在用串口登录树莓派的时候登录不了 &#xff01;&#xff01;&#xff01; 默认账号&#xff1a;pi 默认密码&#xff1a;raspb…

树莓派raspberry pi 4 SSH默认密码无法登录解决办法

以前玩过一段时间树莓派&#xff0c;只要开通ssh就可以&#xff0c;默认用户pi,默认密码: raspberry。 远程连接就可以。 但今天再玩却死活无法登录&#xff0c;如下&#xff1a; 出了什么幺蛾子哦&#xff1f;&#xff01;&#xff01; 上网一查&#xff0c;才知道pi账号在…

【入坑树莓派】烧录系统都烧录了三次(树莓派默认账户密码错误/已删除)

为什么会烧录了三次&#xff1f;我因为实在不知道问题出在哪&#xff0c;所以只能推倒重来三次。。。 三次&#xff0c;两次连接不上WiFi&#xff0c;好不容易一次连接上了&#xff0c;出现了下面这幅画面 再三确认了默认用户名是pi&#xff0c;密码raspberry&#xff0c;奈何…

树莓派用默认账号和密码登录不上怎么办;修改树莓派的密码

目录 一、重置树莓派的默认账号和密码 二、修改树莓派的密码 三、超级用户和普通用户的切换 一、重置树莓派的默认账号和密码 在SD卡中根目录建立文件userconf 在userconf中输入如下内容&#xff1a; pi:$6$/4.VdYgDm7RJ0qM1$FwXCeQgDKkqrOU3RIRuDSKpauAbBvP11msq9X58c8Q…

树莓派默认密码_树莓派介绍:没有显示器,怎样远程控制树莓派?

树莓派(Raspberry Pi)是学习计算机知识、架设服务器的好工具&#xff0c;价格低廉&#xff0c;可玩性高。 由于树莓派系统开始时默认是不开启ssh连接的&#xff0c;没有开启ssh就无法连接电脑&#xff0c;后续的操作也就无从谈起。 准备工作 1.烧录好系统的树莓派3B主板 2.普…

树莓派默认密码_树莓派快速指南,从购买到开机

本文给树莓派初学者&#xff0c;或者准备入手树莓派的同学看&#xff0c;主要包括什么是树莓派&#xff0c;入门树莓派需要那些配件&#xff0c;如何烧录树莓派系统&#xff0c;和树莓派的开机指南。如果你不知道学习树莓派需要那些配件&#xff0c;或者购买了树莓派不知道怎么…

树莓派的登录

一、串口登录&#xff1a; 由于树莓派在默认情况下&#xff0c;树莓派的串口和蓝牙链接。而我们要进行串口登录就得断开蓝牙&#xff0c;把串口用来进行数据通信。 1.打开SD卡根目录的"config.txt"文件&#xff0c;将以下内容添加在最后并且保存。 dtoverlaypi3-m…

树梅派raspberrypi的su密码root密码是什么

入手了树梅派4B,上电后&#xff0c;安装portainer的时候想获得root权限&#xff0c;输入su&#xff0c;恩&#xff1f;密码是多少&#xff1f;不记得了&#xff0c;输了好几遍登录密码也不对&#xff0c;无法进入了。 查了一下&#xff0c;原来树莓派的Raspbian系统root用户默…

【mysql】mysql 模糊查询 like 语句

mysql 模糊查询 like 语句 一 like 语句 %xxx%&#xff1a;查询 username 字段中包含 xxx 的记录。 select * from user where username like ‘%xxx%’; %xxx&#xff1a;查询 username 字段中以 xxx 结尾的记录。 select * from user where username like ‘%xxx’; xx…

mybatis模糊查询like语句怎么写

写法为&#xff1a;1、使用“${...}”&#xff0c;语法为“like ${...}”&#xff1b;2、使用“#{...}”&#xff0c;语法为“like #{...}”&#xff1b;3、使用CONCAT函数连接参数形式&#xff0c;语法为“like CONCAT(%,#{...},%)”。 本教程操作环境&#xff1a;windows7系统…

mysql like模糊查询表名_mysql模糊查询like/REGEXP

增删改查是mysql最基本的功能&#xff0c;而其中查是最频繁的操作&#xff0c;模糊查找是查询中非常常见的操作&#xff0c;于是模糊查找成了必修课。 like模式 like意思是长得像&#xff0c;有两个模式&#xff1a;_和% _表示单个字符&#xff0c;通常用来查询定长的数据&…

模糊查询like用法实例(Bee)

like通过两个匹配符%和_进行模糊查询. %: 匹配任意个任意字符 _: 匹配一个字符 以下以userid为例, 在数据库中的值如下图所示: V1.11及之前版本&#xff0c; 使用Op.like&#xff0c; 需要判断值是否为空字段&#xff0c;是否只含有匹配符(%和_) Op.like可以创建比左右匹配…

sql模糊查询 like

like 经常与where 字句和通配符在一块进行使用&#xff0c;表示像啥啥&#xff0c;模糊查询 通配符 主要是 _ 和 %   &#xff05; 百分号表示零个&#xff0c;一个或多个字符   _ 下划线表示单个字符 **注意&#xff1a;**1、 MS Access使用问号&#xff08;?&#xff09…