基于链表的四位存储大数计算

本文介绍了如何使用链表类实现大数计算,重点在于四位存储的链表操作,包括加减乘除模运算。实验目的是提升链表操作能力和理解大数运算,通过类设计和指针操作,实现了高效的大整数计算。文章详细阐述了类结构、程序流程、技术难点与解决方案,并提供了实验验证和测试示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构的大型实验,和之前写的计算器不同的是,少了词法解析,多了链表指针操作,写完感觉,指针操作能力上了一个台阶,有时间有兴趣的亲,也可以尝试一下,下附实验报告及源码。

1.实验内容

1.1实验目的

实验通过实现基于链表类实现的大数类,从而锻炼对链表的使用和有关大数的四则运算等操作,并在此过程中加深对类的理解和运用。

 

1.2类框架图

1.2.1 Node

Node类:

1.pre和next都是Node* 类型的指针,分别指向该节点的前驱和后继。

2.num存该节点的数值,大数类实现中采取四位存一个节点的方式,考虑到short的范围,故将数值设置为short类型。

3.Node()是此类的无参构造。



 

1.2.2 myList

myList类:

 

1.此类有first,tail,mySize三个数据成员,分别代表链表类的的头指针,尾指针和节点数(此链表带一个哨兵,哨兵不计节点数)。

2.myList()和myList(const&myList r)分别为无参构造函数和拷贝构造函数。

3.getSize()返回mySize的值。

4.add_back()和add_front()分别向链表后面和前面插入节点,向前插时,插在哨兵之后。

5.erase()删除尾指针指向的节点,当只剩哨兵时,不做操作。

6.display()因为是逆向存储的,故从后开始输出节点的值,特殊处理,第一个节点需去掉前置0。

7.~myList()析构函数,逐节点移动指针并释放内存。

 

 

 

 

 

1.2.3 BigInt


BigInt类:


1.BigInt类共3个数据成员,sign,data,digit。sign仅共一次减法运算的符号判断,data即用于存储的myList类。Digit是该大数的位数。

2.该类包含BigInt(),BigInt(strings),BigInt(const &BigInt r)3个构造函数。

3.display(ostream &out)函数用于输出,可以通过改变参数,灵活地进行控制台输出或文件输出。

4.operator系列,其它都没什么特殊,只是因为‘^’操作不宜过大,故将次数值限定在了long long int范围。

5.operator- 因为需要判断正负,故在类的设计上加上了sign,来表示正负。

6.结构图中遗漏了析构函数,~BigInt()通过显示调用data的析构函数进行析构。

 

 

1.3程序流程图


2.实验验证

2.1输入形式

程序开始,需输入指令选择文件输入或键盘输入,其后选择是文件输出,还是屏幕显示。之后,便可输入表达式,表达式的形式需为 a ? b ,‘?’代表运算符,a,b分别为两大数,两两之间以空格分隔。当全部运算结束,最后输入Ctrl+Z表示结束。

 

2.2输出形式

示例:

输入: 1 + 2

输出: Digit:1  BigInt:3

 

2.3程序功能

可以较快计算大整数的加减乘除模,同时可以较快计算大整数的long long int型幂次方。支持文件/键盘读入,文件输出/屏幕显示。

 

 

 

3.调试分析

3.1技术难点

1.采用四位为一节点逆序存储,虽然能很大程度上加快运算速率,但实现上也颇为复杂。

示例: 123456789   6789->2345->1

2.因为采用的是四位存储模式,需要分别更新大数的位数,和链表的节点数。虽然看似简单,但在实际调试中,因为需要及时更新位数,稍有遗漏就会对大数之间的大小比较产生影响,从而导致整个程序出错。

3.因为不能直接在链表基础上进行四则运算,需要在大数类上对链表进行操作,需通过增加节点,删除节点等操作间接运算,又因体系规模略显庞大,调试过程很容易出错。

4.在函数内生成对象,函数一结束就会被析构,因此需要定义全局变量,或动态生成。

5.因为要提高除法的效率,但又受四位存储的限制,不能直接通过增加节点来使除数有效地逼近被除数,只能先通过增加节点的方式最大限度使除数逼近被除数,然后再用除数乘以一个int型整数的方法逼近被除数,同时将以上过程实现为循环。

 

 

 

 

3.2技术问题及解决方案

Problem1:

乘法效率过低。

Solution1:

采用四位存储模式。

 

Problem2:

除法效率过低。

Solution2:

通过先不断给除数D的拷贝对象A增加0节点,并同时给初始值为1的大整数B增加0节点,再将A乘以一个小整数的方式,找到一个大致接近被除数C的值A,不断循环减去A,并同时在答案上加上B,直至C<A。在外层循环不断重复该过程,直至被除数C小于除数D。

 

Problem3:

求幂效率过低。

Solution3:

类比矩阵多次幂的思想,利用已计算好的较低次幂的乘积直接求得高次幂。具体实现:以十进制为单位,计算一个数的1次,10次,100次,并循环该位上对应的数值次,将答案乘以现乘积……直至与幂的最高位等位。最后乘积即为所求。

 

示例: 2^421

ans=1

//对应个位1

tmp=2^1=2  ans*=tmp

//对应十位2

tmp=2^10=(2^1)^10ans*=tmp ans*=tmp

//对应百位4

tmp=2^100=(2^10)^10ans*=tmp ans*=tmp ans*=tmp ans*=tmp

//最后ans即为所求。

  

Problem4:对象当函数调用完时,会被析构。

Solution4:使用全局变量,或者动态生成变量。

 

3.3调试错误及修正方案

1.写链表类erase()函数时,应把最后一个节点的后继置为NULL,但却因失误多打了一个‘=’,导致链表遍历时,始终无法终止。一直以为是端点处理有问题,最后将‘=’去掉,就顺利通过了。

2.写除法时,始终无法跳出循环,以为是>=重载出了问题,仔细调试后发现是因为>=是基于大数位数判断的,在计算过程中未能及时修正位数,导致>=判断始终成立。随后,在减法操作中不断更新位数,最后顺利跳出循环。

3.局部变量被析构,采取全局变量或者堆区的方法。       

4.测试示例

4.1输入输出示例

1.文件输入,文件输出

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值