长整数加减法JAVA版本

长整数加减法

我在网上看到长整数加减法都是c或者c++版本java版太少,所以上传一个java版本的供大家参考,我会把代码按各个类、粘贴上去,根据各个类去讲解如何实现长整数加减法。

主要思路

将读入的长整数转换为 循环链表,然后选择加减法方式,最后进行加法或者减法

图示

在这里插入图片描述

底层实现

创建双向循环链表

package com.linklist;

import java.util.ArrayList;

public class Cir_Link_List {
    //定义结点类
    public class Node {
        public int e;
        public Node next;
        public Node prev;

        public Node(int e, Node prev, Node next) {
            this.e = e;
            this.prev = prev;
            this.next = next;
        }

        public Node() {
        }
    }


    public Node head;
    public Node end;
    int size;
    public String symbol;

    //初始化
    public void initList() {
        head = new Node(0, null, null);
        end = new Node(0, null, null);
        head.next = end;
        head.prev = end;
        end.prev = head;
        end.next = head;
        size = 0;
    }

    //获取长度
    public int getSize() {
        return size;
    }


    //向头结点后插入结点
    public void insertNodeH(int e) {
        Node next = head.next;
        Node cur = new Node(e, head, next);
        head.next = cur;
        next.prev = cur;
        size++;
    }


    //获取end前一个结点
    public Node getLast() {
        return end.prev;
    }

    /**
     * 从键盘数据,创建循环链表
     */
    public void createList(String str) {
        initList();
        String[] res = str.split(",");//分割为xxxx形式
        //将4位数全部添加进list链表中
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < res.length; i++) {
            list.add(Integer.parseInt(res[i]));
        }
        Node p = new Node(0, head, end);
        head.next = p;
        end.prev = p;
        int number;
        for (int i = 0; i < list.size(); i++) {
            number = list.get(i);
            if (i == 0 && number < 0) {
                number = -number;
                symbol = "-";
            } else if (i == 0 && number >= 0) {
                symbol = "+";
            }
            Node q = new Node(number, p, end);
            p.next = q;
            end.prev = q;
            p = q;
            size++;
        }
        //删除头结点后的第一个无用结点
        Node d = head.next;
        Node dl = d.next;
        head.next = dl;
        dl.prev = head;
    }


    public void show() {
        Node t = end.prev;
        while (t.prev != end) {
            System.out.print(t.e + "->");
            t = t.prev;
        }
        System.out.println();
    }
}

(1) Cir_Link_List类中首先定义类内部类Node类,节点类包含三个属性,e:当前元素的值,next:指向下一个结点的指针,prev:指向前一个结点的指针,在构造方法中,书写了两种构造方法,其中一种是传入e,prev,next进行初始化一个结点,另外一种是不传入任何类属性的构造方法。写好Node类后Cir_Link_List类中,含有四个属性,head:双向循环链表的头结点,end:双向循环链表的尾结点,size:循环链表的长度,symbol:symbol用来记录从用户输入进来数据的正负号。在Cir_Link_List中实现了很多方法,下面一一列举出来并进行说明

首先是getSize()方法,此方法是获取双向循环链表长度,该方法利用size属性,直接return size;即可获取当前双向循环链表长度。在Cir_Link_List中最关键的方法就是insertNodeH(ing e)方法,该方法是向头节点后插入结点,这个方法是在长整数加减法,进行进位时,当头节点下一个结点e的值超过9999,并且还需要进位,此时就需要利用此方法进行,在头节点后插入新的结点,该方法实现通过获取到头节点的下一个结点,head.next,在创建当前结点cur,更改头节点尾部指针指向,更改head.next头部指针指向,当前结点的头指针和尾指针分别指向head和head.next最后不要忘记更新size值,size++;通过上述操作即可实现insertNodeH(int e)方法。

getLast()方法顾名思义,是获取双向循环链表尾结点的前一个结点,由于进行长整数加减法时运算顺序需要从后向前运算,所以需要获取尾结点的前一个结点,从该结点开始4位运算一直向头节点方向运算。

initList()方法,该方法初始化一个双向循环链表,通过创建头节点head,尾结点end,将头结点的头指针指向尾结点,将头节点的尾指针指向尾结点,将尾结点的头指针指向头节点,将尾结点的尾指针指向头节点。

createList(String str)方法,该方法是Cir_Link_List类中核心方法,通过用户传入的字符串,将其构造出双向循环链表的方法,该方法实现,首先调用initList()方法进行初始化一个链表,紧接着以逗号为分隔符,调用java中split方法将用户的数据以四位数为一组,放入一个String类型的数组中,接下来创建ArrayList链表,将String数组用的元素通过paresInt()方法转换为Int类型,存入ArrayList中接下来就是将ArrayList中的元素插入已经初始化好的双向循环链表中,在插入之前,需要创建一个p结点,p结点位于头节点之后,尾结点之前,每次将新的元素插入到p结点之后尾结点之前,然后p=q,更新p结点位置,以此类推,最后需要删除头节点的下一个结点,因为该结点是p最初所在结点,该结点e没有任何值,属于废结点需要删除。这样就通过用户传入的String类型的数据,构造出双向循环链表!

创建接口Operator

package com.operation;

import com.linklist.Cir_Link_List;

public interface Operator {
    //加法
    public Cir_Link_List add(Cir_Link_List L1, Cir_Link_List L2);
    //减法
    public Cir_Link_List sub(Cir_Link_List L1, Cir_Link_List L2);
    //比较L1,L2的大小
    public int Compare(Cir_Link_List L1, Cir_Link_List L2);
    //定义相加减顺序
    public Cir_Link_List Select(Cir_Link_List L1, Cir_Link_List L2);
    //输入答案
    public  void  ShowAnswer(Cir_Link_List L);
}

operator接口,在此接口中定义了5中方法包括加法add(),减法sub(),比较两个双向循环链表的大小Compare(),定义相加减顺序方法Select(),以及最后的ShowAnser()方法,这些方法需要在Operatoin类中逐一实现。具体方法详解请看Operation类

创建Operation类实现Operator中的方法

package com.operation;

import com.linklist.Cir_Link_List;
import com.linklist.Cir_Link_List.Node;

public class Operation implements Operator {
    @Override
    public Cir_Link_List add(Cir_Link_List L1, Cir_Link_List L2) {
        Cir_Link_List L3 = new Cir_Link_List();//将结果存入L3
        L3.initList();
        Node p = L1.getLast();
        Node q = L2.getLast();
        int e;
        int jinwei = 0;//进位
        //L1和L2长度相等
        while (p.prev != L1.end && q.prev != L2.end) {
            e = p.e + q.e + jinwei;
            if (e >= 10000) {
                jinwei = 1;
                e = e - 10000;
            } else {
                jinwei = 0;
            }
            L3.insertNodeH(e);
            p = p.prev;
            q = q.prev;
        }
        //L1大于L2
        while (p.prev != L1.end) {
            e = p.e + jinwei;
            if (e >= 10000) {
                jinwei = 1;
                e = e - 10000;
            } else {
                jinwei = 0;
            }
            L3.insertNodeH(e);
            p = p.prev;
        }
        //L2大于L1
        while (q.prev != L2.end) {
            e = q.e + jinwei;
            if (e >= 10000) {
                jinwei = 1;
                e = e - 10000;
            } else {
                jinwei = 0;
            }
            L3.insertNodeH(e);
            q = q.prev;
        }
        if (jinwei == 1) L3.insertNodeH(1);
        return L3;
    }

    @Override
    public Cir_Link_List sub(Cir_Link_List L1, Cir_Link_List L2) {
        Cir_Link_List L3 = new Cir_Link_List();
        L3.initList();
        Node p = L1.getLast();
        Node q = L2.getLast();
        int e;
        int jiewei = 0;//借位
        //L1和L2长度相等
        while (p.prev != L1.end && q.prev != L2.end) {
            e = p.e - q.e - jiewei;
            if (p.e < q.e) {
                e = e + 10000;
                jiewei = 1;
            } else {
                jiewei = 0;
            }
            L3.insertNodeH(e);
            p = p.prev;
            q = q.prev;
        }
        //L1比L2长
        while (p.prev != L1.end) {
            e = p.e - jiewei;
            if (e < 0) {
                e = e + 10000;
                jiewei = 1;
            } else {
                jiewei = 0;
            }
            L3.insertNodeH(e);
            p = p.prev;
        }
        //L2比L1长
        while (q.prev != L2.end) {
            e = q.e - jiewei;
            if (e < 0) {
                e = e + 10000;
                jiewei = 1;
            } else {
                jiewei = 0;
            }
        }
        return L3;
    }

    @Override
    public int Compare(Cir_Link_List L1, Cir_Link_List L2) {
        if (L1.getSize() > L2.getSize()) {
            return 1;
        } else if (L1.getSize() < L2.getSize()) {
            return -1;
        } else {
            //链长相等,比较最高4位的值
            Node p = L1.head.next;//拿到最高位
            Node q = L2.head.next;
           while(p.next!=L1.head&&q.next!=L2.head&&p.e==q.e)
           {
               p=p.next;
               q=q.next;
           }
           if(p.e>q.e) return 1;
           else if(p.e<q.e) return -1;
           else return 0;
        }
    }


    @Override
    public Cir_Link_List Select(Cir_Link_List L1, Cir_Link_List L2) {
        String s1 = L1.symbol;
        String s2 = L2.symbol;

        Cir_Link_List L3 = new Cir_Link_List();
        int num = Compare(L1, L2);

        if (s1.equals("+") && s2.equals("+")) {
            //L1+L2
            L3 = add(L1, L2);
            L3.symbol = "+";
        } else if (s1.equals("-") && s2.equals("-")) {
            //-(L1+L2)
            L3 = add(L1, L2);
            L3.symbol = "-";
        } else if (s1.equals("+") && s2.equals("-")) {
            if (num == 1) //L1>L2
            {
                L3 = sub(L1, L2);
                L3.symbol = "+";
            } else if (num == -1) {//L1<L2
                L3 = sub(L2, L1);
                L3.symbol = "-";
            } else {
                L3 = sub(L1, L2); //L1=L2
                L3.symbol = "+";
            }

        } else if (s1.equals("-") && s2.equals("+")) {
            if (num == 1) {
                L3 = sub(L1, L2);
                L3.symbol = "-";
            } else if (num == -1) {
                L3 = sub(L2, L1);
                L3.symbol = "+";
            } else {
                L3 = sub(L1, L2);
                L3.symbol = "+";

            }
        }
        return L3;
    }

    @Override
    public void ShowAnswer(Cir_Link_List L) {
        String str = L.symbol;
        if (str.equals("-")) {
            System.out.print("-");
        }
        Node p = L.head.next;
        while(p.e==0&&p.next!=L.end)p=p.next;//防止0,0,0...这种情况出现
        if (p.next != L.end) {
            //输入第一位
            System.out.print(p.e + ",");
            p = p.next;
        } else {
            System.out.println(p.e + "。");
            return;
        }
        while (true) {
            if (p.e == 0) {
                System.out.print("0000");
            } else if (p.e < 10) {
                System.out.print("000" + p.e);
            } else if (p.e < 100) {
                System.out.print("00" + p.e);
            } else if (p.e < 1000) {
                System.out.print("0" + p.e);
            } else {
                System.out.print(p.e);//正常将4位数输出
            }
            p = p.next;
            if (p.next == L.head) {
                System.out.println("。");
                break;
            } else {
                System.out.print(",");
            }
        }
    }

}

Operation类,该类主要目的是实现两个长整数进行加减法,该类具体实现了Operator接口中add(),sub(),Compare(),Select(),ShowAnser()方法下面我们逐个讲解相关方法。

add(Cir_Link_list L1,Cir_Link_list L2)方法,该方法通过传入两个双向循环链表,然后找到两个双向循环链表的尾结点的前一个结点,可以直接调用getLast()方法找到此结点,分别表示两个结点为p、q,在方法中定义变量e和jinwei,jinwei初始为0,e:用来表示两个对应结点相加后的值,jinwei用来判断e是否大于10000,如果e>=10000则jinwei=1,不然jinwei=0,在两个双向循环链表相加时,两个链表的长度不一定都相等,需要将长度相等的部分进行相加,然后单独处理长度大的那一条链表,在处理长度相等部分时,我们用一个while循环,判断循环结束的条件就是p.prev!=L1.end&&q.prev!=L2.end,这段代码的含义就是,只要p、q没有遍历到头节点就不能结束循环,只有p、q到达头节点时,循环才能结束,在while循环中,首先拿出p、q结点的元素值进行相加,赋值给e,并且e也要加上jinwei的值,然后我们处理e值的大小,如果e>=10000那么e减去10000,jinwei=1,如果e<10000那么jinwei=0,e不变,处理过e后,我们需要处理结果链表,命名为L3,L3调用insertNodeH(e)方法,进行插入结点,最后p=p.prev,q=q.prev即p、q向前遍历。当处理完长度相等部分,需要处理剩余长度比较长的链表,同理需要写两个while循环,分别处理L1>L2,或L2>L1的情况,处理方法与处理相等长度时相同,不在赘述!最后我们不要忘记jinwei,如果最后进位等于1,那么需要新开辟结点并且插入头节点之后,结点的e=1,最后将L3结果链表return即可完成add()方法!

Sub()方法,该方法和add方法类似,都需要传入两个双向循环链表,返回一个结果双向循环链表,首先定义Cir_Link_list 对象L3作为结果链表,然后对L3进行初始化调用initList()方法,在sub()方法中需要变量e,和jiewei(注意不是jinwei),在执行减法操作时,需要借位,然后通过getLast()取得尾结点前一个结点p、q,紧接着处理L1,和L2长度相等部分,首先e=p.e-q.e-jiewei,e是当前两个结点值做差,在减去jiewei值,对e进行处理如果p.e<q.e那么e则小于0,此时需要借位,e=e+10000,jiewei=1,如果p.e>q.e,e值不变,jiewei=0最后L3调用insertNodeH(e),添加结点,p、q进行向前移动,依次类推,接下来是处理L1>L2,或L2>L1的情况,与上述情况相同,不在赘述,最终将结果链表L3return。

Compare()方法,该方法作用是判断L1,L2哪个链表的绝对值大,首先传入L1,L2链表,第一步调用getSize()方法如果L1.getSize()>L2.getSize(),return 1,如果L2长度大于L1 return -1,最后如果L1长度和L2长度都相等,需要从头节点的下一个结点开始遍历,即从p、q开始遍历,如果p.e=q.e则继续向下遍历,直到不相等位置,最后结束的while循环,p、q得到最终位置,比较p、q的值如果p.e>q.e则说明L1>L2,则return 1,如果p.e<q.e则说明L1<L2 return -1,如果p.e=q.e则说明L1=L2,return 0。

Select()该方法主要作用是选择计算方式,并且对结果双向循环链表进行确定符号,首先创建两个String类型变量s1、s2,分别接收L1的symbol,和L2的symbol,创建双向循环链表L3,用于接收结果链表,紧接着调用Compare()方法,传入L1,L2将返回的数值存放到新开辟的int类型变量num中,紧接着需要确定计算方式,首先L1,L2两个长整数都为正数的情况,那么结果一定为正数,直接调用add()方法传入L1,L2确定L3的symbol为正好,如果L1,L2都为负数的情况则L1+L2=-|L1+L2|,可以确定L3的符号为负号,然后调用add()方法即可当L1为正L2为负的情况,这时需要考虑L1,L2绝对值的大小,需要利用num的值,如果num==1即L1>L2,那么L3的符号为正号,调用sub()方法,算出L1-L2就可以求出L3,当num=-1时,说明L1<L2 那么结果一定为负号,即-(|L2|-|L1|),调用sub(L2,L1)即可得到L3,如果L1=L2那么直接调用sub(L1,L2)L3符号为正好即可,最后一种情况是L1为负L2为正,这种情况和上述L1为正,L2为负类似,不在赘述,最终将结果链表L3,return!

ShowAnswer()方法该方法主要是传入结果链表将结果链表打印输出,但是在输出过程中有许多注意的地方,首先如果L3的symbol为负号,那么需要将L3的负号打印输出,接下来需要考虑一种特殊情况,就是L3的前n个结点经过减法后都为0,这时,我们需要通过while循环找到第一个不为0的结点,在while循环中仍然从head的下一个结点p开始遍历,while内的判断条件为p.e==0&&p.next!=L.end 也就是当前结点值e=0并且不是尾结点就向下遍历,当结束循环后需要判断当前结点的下一个结点就是尾结点,如果是直接输出e和句号并且return结束方法,如果不是则输出e和逗号 更新p,p=p.next继续向下执行,接下来进入while循环,将剩下的结点全部打印,但是在打印过程中我们需要进行补0,如果当前e=0,那么需要补4个0,如果e<10,需要补3个0,如果e<100需要补2个0,如果e<1000需要补1个0,如果e为4位数则直接输出e。并且在打印过程中持续输出,号,只有当p.next=L.end遍历到最后时,才输出句号并且跳出循环,结束该ShowAnser方法。

创建Main类实现操作页面从文件读入数据

package com.main;

import com.linklist.*;
import com.operation.*;
import com.linklist.Cir_Link_List.Node;
import java.awt.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;


public class Main {
    public static void  menu() {
        System.out.println("*************************************************");
        System.out.println("              任意长整数加减法              ");
        System.out.println("     操作要求");
        System.out.println("     1.整型变量范围:-(2^15 -1)~(2^15 -1)");
        System.out.println("     2.输入形式每四个整数为一组,整数在[0~9]范围内,组间用逗号分割开,分号表示输入结束");
    }

    public static void main(String[] args) {
        menu();
        Cir_Link_List L1 = new Cir_Link_List();
        Cir_Link_List L2 = new Cir_Link_List();
        Cir_Link_List L3 =new Cir_Link_List();
        try {
            FileReader fr = new FileReader("Score.txt");
            BufferedReader br = new BufferedReader(fr);
            String temp=null;
            String[]str=new String[3];
            String s1,s2;
            while((temp=br.readLine())!=null) {
                System.out.print(temp);
                str=temp.split(";");//以;分割
                s1 = str[0];
                s2 = str[1];
                L1.createList(s1);//传入仅有xxxx,xxxx的形式
                L2.createList(s2);
                Operation op = new Operation();
                L3 = op.Select(L1, L2);
                System.out.print("应输出:");
                op.ShowAnswer(L3);
                System.out.println();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

文件中的数据 文件名字为Score.txt

0;0;
-2345,6789;-7654,3211;
-9999,9999;1,0000,0000,0000;
1,0001,0001;-1,0001,0001;
1,0001,0001;-1,0001,0000;
-9999,9999,9999;-9999,9999,9999;
1,0000,9999,9999;1;

小结

整体实现不是很难,需要注意的地方我都写在了方法详解里,数据的来源是从文件中读入,如果需要从键盘只需要在Main类进行修改运用Scanner读入数据即可!

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java双循环链表整数运算是一种利用双向循环链表来实现对整数的存储和运算的方法。每个节点只存储四位十进制数字,即不超过9999的非负整数。双向链表有头指针,它的data值存储整数的符号,1为正,-1为负,0代表整数为0;它的over值存储除头节点外节点的个数。在实现整数加减法时,需要将两个整数分别存储在两个双向循环链表中,然后按照加减法的规则进行运算,最后将结果存储在一个新的双向循环链表中。具体实现过程中,需要注意进位和借位的处理,以及对于结果中前导0的处理。 下面是一个简单的Java双循环链表整数加法的实现代码: ``` public class LongIntAddition { public static void main(String[] args) { String s1 = "123456789"; String s2 = "987654321"; Node head1 = createList(s1); Node head2 = createList(s2); Node result = add(head1, head2); printList(result); } public static Node createList(String s) { Node head = new Node(0, 0); Node tail = head; int len = s.length(); int sign = 1; if (s.charAt(0) == '-') { sign = -1; len--; } int count = 0; for (int i = s.length() - 1; i >= 0; i--) { char c = s.charAt(i); if (c == '-') { break; } int digit = c - '0'; tail.next = new Node(digit * sign, count++); tail.next.prev = tail; tail = tail.next; } head.over = count; return head; } public static Node add(Node head1, Node head2) { Node p = head1.next; Node q = head2.next; Node result = new Node(0, 0); Node tail = result; int carry = 0; while (p != null || q != null) { int x = (p != null) ? p.data : 0; int y = (q != null) ? q.data : 0; int sum = x + y + carry; carry = sum / 10000; sum = sum % 10000; tail.next = new Node(sum, tail.over++); tail.next.prev = tail; tail = tail.next; if (p != null) { p = p.next; } if (q != null) { q = q.next; } } if (carry > 0) { tail.next = new Node(carry, tail.over++); tail.next.prev = tail; } result.over = tail.over; return result; } public static void printList(Node head) { if (head.next == null) { System.out.println("0"); return; } if (head.next.data < 0) { System.out.print("-"); } Node p = head.next; while (p != null) { int digit = Math.abs(p.data); if (p.over == 0) { System.out.print(digit); } else { System.out.printf("%04d", digit); } if (p.next != null) { System.out.print(","); } p = p.next; } System.out.println(); } } class Node { int data; int over; Node prev; Node next; public Node(int data, int over) { this.data = data; this.over = over; } } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值