北邮22信通:(8)实验1 题目五:大整数加减法(搬运官方代码)

北邮22信通一枚~   

跟随课程进度每周更新数据结构与算法的代码和文章 

持续关注作者  解锁更多邮苑信通专属代码~

上一篇文章:

北邮22信通:(7)实验1 题目四:一元多项式(节省内存版)_青山如墨雨如画的博客-CSDN博客

下一篇文章:

*****声明*****

本代码由官方提供,不是作者的算法。

本代码仅供研究学习使用,请不要用于其他用途。

有问题的友友也可以在评论区留言,我们可以一起讨论。

本代码在DEVC++中可以运行。

*****声明完毕*****

1.实验要求:

利用链表实现大整数加减法操作;32位极其直接操作的数据最大为32bit,若超过32bit,则需要单独设计算法。在这里,可以用链表的每个节点存储大整数的每一位的十进制数字,则可以进行大整数的算术运算,该实验仅实现加减法操作。

要求:

随机产生2个1~50位的字符串,并存储到新的链表中;

打印运算结果。

考虑链表结构的设计,是否有更节省空间的数据结构。

2.代码部分:

#include <iosfwd>
#include <iostream>
#include <stack>
#include "time.h"
using namespace std;

struct Node
{
    int data;
    Node  *next;
};
class BigInteger
{
public:
    BigInteger();
    BigInteger(int a[], int n, bool pos);
    friend BigInteger add(BigInteger &int1, BigInteger &int2);  //int1 + int2
    friend BigInteger sub(BigInteger &int1, BigInteger &int2);  //int1 - int2
    int getLength();                   //获取链表长度
    void print();
    ~BigInteger();
private:
    Node *first;
    int length;
    bool positive = true;   //记录整数的正负
};

BigInteger::BigInteger()
{
    first = new Node;
    first->data = 0;
    first->next = NULL;
    length = 1;
}

BigInteger::BigInteger(int a[], int n, bool pos = true)	//引用和声明只能有一个默认参数定义
{
    if (n < 1)
    {
        throw "integer length should be at least 1";
    }
    //尾插法 不带头结点的链表
    first = new  Node;
    Node *r = first;  //指向最后一个结点
    for (int i = 0; i<n - 1; i++)
    {
        r->data = a[i];
        Node *s = new Node; //(1)生成新结点
        s->next = NULL;

        r->next = s;  //(2) 链接在尾结点后面
        r = s; //(3) 尾指针后移
    }
    r->data = a[n-1];
    r->next = NULL;
    length = n;
	positive = pos;
}
BigInteger::~BigInteger() {}

BigInteger sub(BigInteger &int1, BigInteger &int2) {      //都可以转换成正数的加减法
    BigInteger newint = BigInteger();
    newint.length = 0;              //友元能直接访问私有变量
    if ((!int1.positive)&&(!int2.positive)){    //-int1-(-int2) = -int1 + int2
		int2.positive = true;
        newint = add(int1,int2);
		int2.positive = false;
        return newint;
    }
    else if (!int1.positive){
        int1.positive = true;
        newint = add(int1,int2);
        newint.positive = false;
        int1.positive = false;
        return newint;
    }
    else if (!int2.positive){
        int2.positive = true;
        newint = add(int1,int2);
        int2.positive = false;
        return newint;
    }
    // 这里开始的处理,int1和int2应都为正整数
    Node *cursor = new Node;    //游标用来创建新的链表
    Node *tobedelete = cursor;      //临时的头结点
    cursor->next = newint.first;    
    Node *int1_first = int1.first;     //遍历int1
    Node *int2_first = int2.first;     //遍历int2
    stack<Node*> substk;  //定义一个栈用来处理高位的连续0  如77772-77771 = 1 ,需要把前面的0都删除
    int flag = 0;   //记录减法的借位
    //首先遍历到 min(int1.length, int2.length)位,之后至少有一个指针为NULL
    for (int i = 0; i < int1.length && i < int2.length; i++)
    {
        int tmp = int1_first->data - int2_first->data - flag;
        if (tmp < 0){
            tmp += 10;
            if (tmp == 0){
                substk.push(cursor);    //1000 - 99 = 901
            }
            else{
                while (!substk.empty())      //有出现不为0的位,就把栈清空
                    substk.pop();
            }
            flag = 1;
        }
        else if ((tmp == 0)&&(cursor->next!=newint.first)){  //个位为0不入栈,入栈的是0前面的结点
            substk.push(cursor);
            flag = 0;
        }
        else{
            while (!substk.empty())
                substk.pop();
            flag = 0;
        }
        cursor->next->data = tmp;       //在结果链表中插入新节点
        cursor->next->next = new Node;
        cursor = cursor->next;
        cursor->next->next = NULL;
        int1_first = int1_first->next;
        int2_first = int2_first->next;
        newint.length++;
    }
    //减完位数相同的部分,讨论接下来的情况
    if ((int1_first == NULL) && (int2_first == NULL)){
        if (!flag == 0)        //最高位有借位说明结果是负的,在后面计算补码
            newint.positive = false;
    }
    else if(int1_first == NULL){
        // int2位数多,结果一定是负数
        newint.positive = false;
        while (int2_first != NULL){
            int tmp = 0 - int2_first->data - flag;
            if (tmp < 0){
                tmp += 10;
                if (tmp == 0){
                    substk.push(cursor);
                }
                else{
                    while (!substk.empty())
                        substk.pop();
                }
                flag = 1;
            }
            else if (tmp == 0){
                substk.push(cursor);
                flag = 0;
            }
            else{
                while (!substk.empty())
                    substk.pop();
                flag = 0;
            }
            cursor->next->data = tmp;
            cursor->next->next = new Node;
            cursor = cursor->next;
            cursor->next->next = NULL;
            newint.length++;
            int2_first = int2_first->next;
        }
    }
    else{
        while (int1_first != NULL){
            // int1位数高,结果必为正
            int tmp = int1_first->data - flag;
            if (tmp < 0){
                tmp += 10;
                if (tmp == 0){
                    substk.push(cursor);
                }
                else{
                    while (!substk.empty())
                        substk.pop();
                }
                flag = 1;
            }
            else if (tmp == 0){
                substk.push(cursor);
                flag = 0;
            }
            else{
                while (!substk.empty())
                    substk.pop();
                flag = 0;
            }
            cursor->next->data = tmp;
            cursor->next->next = new Node;
            cursor = cursor->next;
            cursor->next->next =NULL;
            newint.length++;
            int1_first = int1_first->next;
        }
    }
    //删除初始化的临时节点
    delete tobedelete;
    //删除末尾的临时节点
    tobedelete = cursor->next;
    cursor->next = NULL;
    delete tobedelete;
    //删除最后的连续0节点
    while (!substk.empty()){
        cursor = substk.top();
        if (cursor->next == newint.first)  //个位不能被删除(删除的也不是个位,tobedelete已经被释放了)
            break;
        substk.pop();
        tobedelete = cursor->next;
        cursor->next = NULL;
        newint.length--;
        delete tobedelete;
    }
    if (!newint.positive){
        //得到的newint为负数,需要补码操作,如9-16 -> 93,100-93 = 7
        int a[int2.length+1];
        for (int i = 0; i < int2.length;i++)
            a[i] = 0;
        a[int2.length] = 1;
        newint.positive = true;
        BigInteger complement = BigInteger(a,newint.length + 1);
        tobedelete = newint.first;
        newint = sub(complement,newint);    //newint的地址换了,构造了一个新对象
        newint.positive = false;
        while (tobedelete != NULL){
            Node *tobed = tobedelete;
            tobedelete = tobedelete->next;
            delete tobed;
        }
    }
    return newint;
}

BigInteger add(BigInteger &int1, BigInteger &int2) {
    BigInteger newint = BigInteger();  //定义新的大整数作为返回值
    newint.length = 0;
    if ((!int1.positive)&&(!int2.positive))
        newint.positive = false;
    else if(!int1.positive){
        int1.positive = true;
        newint = sub(int2,int1);
        int1.positive = false;
        return newint;
    }
    else if(!int2.positive){
        int2.positive = true;
        newint = sub(int1,int2);
        int2.positive = false;
        return newint;
    }
    // 这里开始的处理,int1和int2应都为正整数
    Node *cursor = new Node;    //创建一个游标指针用于构建newint
    Node *tobedelete = cursor;  //记录临时用的节点位置,最后删掉,防止内存泄漏
    cursor->next = newint.first;
    Node *int1_first = int1.first;
    Node *int2_first = int2.first;
    int flag = 0;  //记录加法的进位
    //首先遍历到 min(int1.length, int2.length)位,之后至少有一个指针为NULL
    for (int i = 0; i < int1.length && i < int2.length; i++)
    {
        int tmp = int1_first->data + int2_first->data + flag;
        if (tmp >= 10){
            tmp -= 10;
            flag = 1;
        } else
            flag = 0;
        cursor->next->data = tmp;
        cursor->next->next = new Node;
        cursor = cursor->next;
        int1_first = int1_first->next;
        int2_first = int2_first->next;
        newint.length++;
    }
    if ((int1_first == NULL) && (int2_first == NULL)){

    }
    else if(int1_first == NULL){
        // int2的位数多
        while (int2_first != NULL){
            int tmp = int2_first->data + flag;
            if (tmp >= 10){
                tmp -= 10;
                flag = 1;
            } else
                flag = 0;
            cursor->next->data = tmp;
            cursor->next->next = new Node;
            cursor = cursor->next;
            newint.length++;
            int2_first = int2_first->next;
        }
    }
    else{
        while (int1_first != NULL){
            // int1的位数多
            int tmp = int1_first->data + flag;
            if (tmp >= 10){
                tmp -= 10;
                flag = 1;
            } else
                flag = 0;
            cursor->next->data = tmp;
            cursor->next->next = new Node;
            cursor = cursor->next;
            newint.length++;
            int1_first = int1_first->next;
        }
    }
    delete tobedelete; //删除初始化的临时节点,防止内存泄漏
    if (flag != 1){
        //如果最后没有进位,删除末尾的临时节点,防止内存泄漏

        tobedelete = cursor->next;
        cursor->next = NULL;
        delete tobedelete;
        return newint;
    }
    else{
        //如果有进位,则将数据赋到末尾节点
        cursor->next->data = 1;
        cursor->next->next = NULL;
        newint.length++;
    }
    return newint;
}

int BigInteger::getLength() //O(1)
{
    return this->length;
}

void BigInteger::print() {
    stack<int> s;
    Node *p = first;
    while (p != NULL){
        s.push(p->data);
        p = p->next;
    }
    if(!positive)
        cout << "-";
    while (!s.empty()){
        int tmp = s.top();
        cout << tmp;
        s.pop();
    }
}

int main()
{
    //从低位到高位
    //{个,十,百,千,万,...}
   
    int nums1[2] = {2,3};
    BigInteger int1(nums1, 2);
	
    int nums2[2] = {2,3};
    BigInteger int2(nums2, 2);

    // srand((unsigned )time(NULL));    //随机数种子
    
    // int n = rand() % 50 +1;
    // int nums1[n];
    // for(int i = 0; i < n; i++)
    // {
    //     nums1[i] = rand()%10;
    // }
    // if(nums1[n-1] == 0)
    //     nums1[n-1] = 1;
    // BigInteger int1(nums1,n);

    // n = rand() % 50 + 1;
    // int nums2[n];
    // for(int i = 0; i < n; i++)
    // {
    //     nums2[i] = rand()%10;
    // }
    // if(nums2[n-1] == 0)
    //     nums2[n-1] = 1;
    // BigInteger int2(nums2, n);

    cout << "int1: ";
    int1.print();
    cout << endl;
    cout << "int2: ";
    int2.print();
    cout << endl;

    try
    {
        cout << "*********************" << endl;
        BigInteger newint = add(int1,int2);
        newint.print();
        cout << "=";
        int1.print();
        cout << "+";
        int2.print();
        cout << endl;

        cout << "*********************" << endl;
        BigInteger subint = sub(int1,int2);
        subint.print();
        cout << "=";
        int1.print();
        cout << "-";
        int2.print();
        cout << endl;
    }
    catch (const char* e)
    {
        cout << e << endl;
        return 0;
    }
    return 0;
}

程序运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/4291.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【人人都能读标准】17. 底层算法:ECMAScript的错误处理机制

本文为《人人都能读标准》—— ECMAScript篇的第17篇。我在这个仓库中系统地介绍了标准的阅读规则以及使用方式&#xff0c;并深入剖析了标准对JavaScript核心原理的描述。 我们在11.程序完整执行过程说过&#xff0c;一个程序的运行会经历三个阶段&#xff1a;初始化Realm环境…

MyBatis-面试题

文章目录1.什么是MyBatis?2.#{}和${}的区别是什么&#xff1f;3.MyBatis的一级、二级缓存4.MyBatis的优缺点5.当实体类中的属性名和表中的字段名不一样 &#xff0c;怎么办 &#xff1f;6.模糊查询like语句该怎么写?7.Mybatis是如何进行分页的&#xff1f;分页插件的原理是什…

渗透测试之冰蝎实战

渗透测试之冰蝎实战1.基本使用2.命令执行&虚拟终端3.文件管理4.反弹shell5.内网资产扫描6.内网穿透7.数据库管理“冰蝎”是一款动态二进制加密网站管理客户端 下载地址 1.基本使用 运行冰蝎&#xff0c;打开传输协议&#xff1a; 生成一个php远程马&#xff1a; 点击生成…

【测试基础】之07 linux基础

Linux操作系统Linux操作系统介绍操作系统&#xff1a;管理计算机硬件与软件 资源的计算机程序&#xff0c;同时也是计算机系统的内核与基石。简单地说&#xff0c;操作系统就是出于用户与计算机系统硬件之间用于传递信息的系统程序软件。例如&#xff1a;操作系统会在接收到用户…

金三银四,你准备好面试了吗? (附30w字软件测试面试题总结)

不知不觉&#xff0c;已是3月下旬。最近有很多小伙伴都在跟我谈论春招面试的问题&#xff0c;其实对于面试&#xff0c;我也没有太多的经验&#xff0c;只能默默地把之前整理的软件测试面试题分享给Ta。今天就来大致的梳理一下软件测试的面试体系&#xff08;每一部分最后都有相…

Vue3学习笔记(5.0)

Vue.js循环语句 v-for指令需要以site in sites形式的特殊语法&#xff0c;sites是源数据数组并且site是数组元素迭代的别名。 v-for可以绑定数据到数组来渲染一个列表&#xff1a; <!--* Author: RealRoad1083425287qq.com* Date: 2023-03-26 16:26:51* LastEditors: Mei…

图解redis的client的实现

目录 1.引言 2.客户端属性 2.1套接字描述符 2.2 name 2.3 客户端标志 2.4输入缓冲区 2.5命令与命令参数 2.6命令实现的函数 2.7输出缓冲区 2.8身份验证 2.9 时间 3.客户端的创建的关闭 3.1普通客户端的创建 3.2普通客户端的关闭 3.AOF的伪客户端 1.引言 Redis服务…

(数字图像处理MATLAB+Python)第二章数字图像处理基础-第三、四节:数字图像的生成和数值描述

文章目录一&#xff1a;数字图像的生成与表示&#xff08;1&#xff09;图像信号的数字化&#xff08;2&#xff09;数字图像类型二&#xff1a;数字图像的数值描述&#xff08;1&#xff09;常用坐标系&#xff08;2&#xff09;数字图像的数据结构&#xff08;3&#xff09;常…

Typora使用

Typora Typora 是一款支持实时预览的 Markdown 文本编辑器。 1. 基础操作 1.1标题 # 一级标题## 二级标题### 三级标题#### 四级标题##### 五级标题###### 六级标题1.2 引用 > 引用内容1 > 引用内容2 >> 引用内容31.3 斜体 *斜体* _斜体_1.4 加粗…

mysql整理

文章目录概述SQLDDLDMLDQL单表查询多表查询DQL的执行顺序DCL管理用户控制权限函数约束事务存储引擎索引概述语法性能分析索引的使用SQL的优化insert优化主键优化Order by优化其它优化存储对象视图存储过程基本操作变量IF条件判断参数循环条件处理程序存储函数触发器锁全局锁表级…

Mysql-缓冲池 buffer pool

缓冲池 buffer pool innodb中的数据是以【页】的形式存储在磁盘上的表空间内&#xff0c;但是【磁盘的速度】和【内存】相比简直不值一提&#xff0c;而【内存的速度】和【cpu的速度】同样不可同日而语&#xff0c;对于数据库而言&#xff0c;I/O成本永远是不可忽略的一项成本…

基于Elman神经网络预测计费系统的输出(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 简单循环网络&#xff08;simple recurrent networks&#xff0c;简称SRN&#xff09;又称为Elman network&#xff0c;是由Jeff…

什么是AI文章生成器-AI文章生成器批量生成文章

AI文章生成器有哪些 目前市面上存在一些可以生成文章的 AI 文章生成器&#xff0c;以下是其中几种常见的&#xff1a; OpenAI GPT-3&#xff1a; OpenAI GPT-3 是目前最先进、最著名的 AI 文章生成器之一&#xff0c;它可以生成各种类型的文章&#xff0c;例如新闻报道、科学报…

我的Macbook pro使用体验

刚拿到Mac那一刻&#xff0c;第一眼很惊艳&#xff0c;不经眼前一亮&#xff0c;心想&#xff1a;这是一件艺术品&#xff0c;太好看了吧 而后再体验全新的Macos 系统&#xff0c;身为多年的win用户说实话一时间还是难以接受 1.从未见过的访达&#xff0c;不习惯的右键 2. …

[论文解析] Cones: Concept Neurons in Diffusion Models for Customized Generation

论文连接&#xff1a;https://readpaper.com/pdf-annotate/note?pdfId4731757617890738177&noteId1715361536274443520 源码链接&#xff1a; https://github.com/Johanan528/Cones 文章目录OverviewWhat problem is addressed in the paper?Is it a new problem? If so…

PMP一般要提前多久备考?

PMP很迷&#xff0c;有只备考了一周过的&#xff0c;也有备考几个月过的。保险起见&#xff0c;预留两个月比较靠谱&#xff0c;尤其现在是新考纲&#xff0c;PMP新版大纲加入了 ACP 敏捷管理的内容&#xff0c;而且还不少&#xff0c;敏捷混合题型占到了 50%&#xff0c;前不久…

AcWing3662. 最大上升子序列和(线性DP + 树状数组优化 + 离散化处理)

AcWing3662. 最大上升子序列和&#xff08;线性DP 树状数组优化 离散化处理&#xff09;一、问题二、分析1、DP过程&#xff08;1&#xff09;状态表示&#xff08;2&#xff09;状态转移2、数据结构优化&#xff08;1&#xff09;树状数组维护最值&#xff08;2&#xff09;…

K8s 弃用 Docker!一文介绍 containerd ctr、crictl 使用

containerd 是一个高级容器运行时&#xff0c;又名 容器管理器。简单来说&#xff0c;它是一个守护进程&#xff0c;在单个主机上管理完整的容器生命周期&#xff1a;创建、启动、停止容器、拉取和存储镜像、配置挂载、网络等。 containerd 旨在轻松嵌入到更大的系统中。Docke…

【ASPLOS 2023】图神经网络统一图算子抽象uGrapher,大幅提高计算性能

作者&#xff1a;周杨杰、沈雯婷 开篇 近日&#xff0c;阿里云机器学习平台PAI和上海交通大学冷静文老师团队合作的论文《图神经网络统一图算子抽象uGrapher》被ASPLOS 2023录取。 为了解决当前图神经网络中框架中不同的图算子在不同图数据上静态kernel的性能问题&#xff0…

【前沿技术】文心一言 PK Chat Gpt

目录 写在前面 一、文心一言 二、Chat GPT 三、对比 四、总结 写在前面 随着人工智能技术的不断发展和普及&#xff0c;越来越多的智能应用走入了人们的日常生活&#xff0c;如智能语音助手、智能客服、机器翻译等等。在这些应用中&#xff0c;自然语言生成&#xff08;…
最新文章