码迷,mamicode.com
首页 > 编程语言 > 详细

C++之用链表实现大数的加减乘除

时间:2018-02-25 19:19:41      阅读:249      评论:0      收藏:0      [点我收藏+]

标签:遇到   前言   接下来   拷贝   字符串   拷贝构造函数   返回结果   依次   逆向   

1.前言

实现大数的加减乘除是今年寒假C++的大作业,原本我是用字符串写的,但是后来看作业要求要用链表实现,于是我不情不愿的用链表的实现了一遍

2.Num类

2.1Node类

首先是内部的一个Node类用于建立单向链表,size用于计算大小方便Num对象之间做比较

    class Node
    {
    public:
        int val;
        Node*next;
        Node(int v, Node*n)
        {
            val = v;
            next = n;
        }
    };
    Node*head;
    int size;

2.2构造函数,赋值函数以及析构函数

首先是默认构造函数,其实可能不会使用到,但为了方便,还是写了

    Num()
    {
        head = NULL;
        size = 0;
        D = false;
    }

然后是主要的一个构造函数,当遇到‘.‘的时候,我们用-100来作为标记

该链表为逆向构造的一个数,方便进行加减操作

    Num(const string&s)
    {
        D = false;
        head = NULL;
        size = 0;
        for (int i = 0; i < s.size(); i++)
        {
            if (s[i] == ','||s[i]=='-')
                continue;
            size++;
            if (s[i] == '.')
                head = new Node(-100, head);
            else
                head = new Node(s[i] - '0', head);
        }
    }

接下来是拷贝构造函数以及赋值函数,两者基本是一样的

值得注意的是,赋值函数要首先确认赋值对象是否为本身,若为本身,则返回

    Num(const Num& num)
    {
        D = num.D;
        size = num.size;
        head = NULL;
        Node*cur = num.head, *temp=head;
        while (cur)
        {
            if (!head)
            {
                head = new Node(cur->val, NULL);
                temp = head;
            }
            else
            {
                temp->next = new Node(cur->val, NULL);
                temp = temp->next;
            }
            cur = cur->next;
        }
    }
    Num& operator=(const Num&num)
    {
        if (this == &num)
            return *this;
        free();
        size = num.size;
        head = NULL;
        D = num.D;
        Node*cur = num.head, *temp=head;
        while (cur)
        {
            if (!head)
            {
                head = new Node(cur->val, NULL);
                temp = head;
            }
            else
            {
                temp->next = new Node(cur->val, NULL);
                temp = temp->next;
            }
            cur = cur->next;
        }
        return *this;
    }

最后是析构函数,我们析构函数只需要回收掉链表的内存即可

为了方便函数内部回收链表内存,将回收操作写为free函数

    ~Num()
    {
        free();
    }
    void free()
    {
        size = 0;
        while (head)
        {
            Node*temp = head->next;
            delete head;
            head = temp;
        }
        head = NULL;
    }

上述即为Num类的基本组成函数

2.3加法操作与减法操作

为方便操作,加减时大数在前,小数在后,直接对本身对象进行操作,所以使用+=,-=以及返回对象本身引用

加减操作没什么好说的,从最低位开始依次相加

在进位或借位时进行了一个判断是否为小数点的操作,以防操作错误

    Num& operator+=(const Num&num)
    {
        Node*pa = head, *pb = num.head;
        while (pa||pb)
        {
            int b = 0;
            if (pb)
            {
                b = pb->val;
                pb = pb->next;
            }
            if (pa->val != -100)
            {
                pa->val += b;
                if (pa->val > 9)
                {
                    if (pa->next)
                    {
                        if (pa->next->val == -100)
                            pa->next->next->val++;
                        else
                            pa->next->val++;
                    }
                    else
                    {
                        pa->next = new Node(1, NULL);
                        size++;
                    }
                    pa->val -= 10;
                }
            }
            pa = pa->next;
        }
        return *this;
    }
    Num& operator-=(const Num&num)
    {
        Node*pa = head, *pb = num.head;
        while (pa || pb)
        {
            int b = 0;
            if (pb)
            {
                b = pb->val;
                pb = pb->next;
            }
            if (pa->val != -100)
            {
                pa->val -= b;
                if (pa->val < 0)
                {
                    if (pa->next->val == -100)
                        pa->next->next->val--;
                    else
                        pa->next->val--;
                    pa->val += 10;
                }
            }
            pa = pa->next;
        }
        return *this;
    }

2.4乘法操作

乘法操作其实和列式计算一样,涉及到进位,但很容易理解

    Num operator*(const Num&num)
    {
        Num res(string(size + num.size, '0'));
        Node *pr = res.head, *temp;
        for (Node*pa = head; pa != NULL; pa = pa->next)
        {
            int carry = 0;
            temp = pr;
            for (Node*pb = num.head; pb != NULL; pb = pb->next,pr=pr->next)
            {
                int temp = pa->val*pb->val + carry + pr->val;
                pr->val = temp % 10;
                carry = temp / 10;
            }
            pr->val += carry;
            pr = temp->next;
        }
        return res;
    }

2.5除法操作

除法操作我们使用被除数减去除数乘以若个干10进行

比如58除以5 首先用58-50=8 然后商加10 然后用8-5=3 商加1 由于3比5小,就不进行操作了 最终结果为11

但是题目要求除法操作要保留十位小数四舍五入,我们只需要事先对被除数乘以10^11即可,最终再加上小数点进行四舍五入操作

我们首先实现了两个与10有关的函数

    void Mul10(const int& x)
    {
        for (int i = 0; i < x; ++i)
        {
            head = new Node(0, head);
            size++;
        }
    }
    void Div10(const int&x)
    {
        for (int i = 0; i < x; ++i)
        {
            Node*temp = head->next;
            delete head;
            head = temp;
            size--;
        }
    }

然后是除法操作,res用于返回结果,p用于与res相加

d用于与被除数相减

    Num operator/(const Num&num)
    {
        Num res(string(1, '0')), p(string(1, '1'));
        res.D = true;
        p.D = true;
        Num d = num;
        while (num<=*this)
        {
            int len = size - num.size;
            d.Mul10(len);
            p.Mul10(len);
            int z = 0;
            if (*this < d)
            {
                d.Div10(1);
                p.Div10(1);
                z = -1;
            }
            if (res.head->val == 0&&res.size==1)
                res = p;
            else
                res += p;
            *this -= d;
            balance();
            d.Div10(len + z);
            p.Div10(len + z);
        }
        return res;
    }

我们注意到了除法操作中有比较<的操作,接下来便是重载<函数

C++之用链表实现大数的加减乘除

标签:遇到   前言   接下来   拷贝   字符串   拷贝构造函数   返回结果   依次   逆向   

原文地址:https://www.cnblogs.com/vhyz/p/8469905.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!