[Java] 用 Swing 生成一个最大公约数计算器(展示计算过程)

2025-12-12 0 427

Swing 生成一个最大公约数计算器(展示计算过程)

背景

在 [Java] 用 Swing 生成一个最大公约数计算器 一文中,我们完成了一个简单的最大公约数计算器。示例效果如下图所示 ⬇️

image.png

它虽然可以计算出两个整数的最大公约数(两个整数不能同时为 00),但是并没有展示计算过程。有的时候,我们也关心计算的过程,例如我们利用欧几里得算法计算 gcd(210,135)gcd(210, 135) 时,计算过程可以这样表示

210=1×135+75135=1×75+6075=1×60+1560=4×15+0210 = 1 times 135 + 75\\ 135 = 1 times 75 + 60\\ 75 = 1 times 60 + 15\\ 60 = 4 times 15 + 0\\

所以

gcd(210,135)=gcd(135,75)=gcd(75,60)=gcd(60,15)=15gcd(210, 135)\\ = gcd(135, 75)\\ = gcd(75, 60)\\ = gcd(60, 15)\\ = 15

如果最大公约数计算器可以把上述过程展示出来,那就方便多了。所以我们的目标是做出下图这样的界面 ⬇️

image.png

正文

需要保存哪些数据

我们先看看如果需要展示完整的计算过程,需要保存哪些数据。以计算 gcd(210,135)gcd(210, 135) 为例,它的计算过程如下 ⬇️

210=1×135+75135=1×75+6075=1×60+1560=4×15+0210 = 1 times 135 + 75\\ 135 = 1 times 75 + 60\\ 75 = 1 times 60 + 15\\ 60 = 4 times 15 + 0\\

每一行都可以看成是 ⬇️ (qiq_i 表示第 ii 行的 rir_i 表示第 ii 行的 余数

ai=qi×bi+ria_i = q_i times b_i + r_i

看来我们只需要将所有的 ai,qi,bi,ria_i, q_i, b_i, r_i 都保存下来(计算结束的条件是出现某个 ri=0r_i=0),就可以将完整的计算过程展示出来。

输入的标准化

只使用非负数

对非负整数 aa 而言,不难验证 gcd(a,b)=gcd(a,b)gcd(a, b) = gcd(-a, b),所以如果用户输入了 负整数,我们总是可以将其先转化为 非负整数,然后再进行计算。也就是说我们只要计算 gcd(a,b)gcd(|a|, |b|),就可以得到 gcd(a,b)gcd(a, b) 的值。

参数顺序的调整

由于 gcd(a,b)=gcd(b,a)gcd(a, b) = gcd(b, a),所以可以调整参数 a,ba, b 的顺序。我们可以通过计算 gcd(max(a,b),min(a,b))gcd(max(a,b), min(a, b)) 从而得到 gcd(a,b)gcd(a, b)

代码

计算最大公约数的代码

基于上文的讨论,可以写出保存了计算过程中所有数据的 GCDCalculator 类 ⬇️

class GCDCalculator {

    record CalculationDetails(
            BigInteger a,
            BigInteger b,
            BigInteger gcd,
            java.util.List equationHolders
    ) {
        /**
         * A holder class for equation a = q * b + r
         */
        record Equation(
                BigInteger a,
                BigInteger q,
                BigInteger b,
                BigInteger r
        ) {
            @Override
            public String toString() {
                return String.format(\"%s = %s × %s + %s\", a, q, b, r);
            }
        }
    }

    private BigInteger toBigInteger(String num) {
        return new BigInteger(num.trim());
    }

    public CalculationDetails calculateGCD(String a, String b) {
        return calculateGCD(toBigInteger(a), toBigInteger(b));
    }

    public CalculationDetails calculateGCD(BigInteger a, BigInteger b) {
        a = a.abs();
        b = b.abs();

        BigInteger biggerOne;
        BigInteger smallerOne;
        if (a.compareTo(b) >= 0) {
            biggerOne = a;
            smallerOne = b;
        } else {
            biggerOne = b;
            smallerOne = a;
        }

        if (biggerOne.equals(BigInteger.ZERO)) {
            throw new IllegalArgumentException(\"两个整数不能都是0!\");
        }
        var equations = doCalculateGCD(biggerOne, smallerOne);
        BigInteger gcd = smallerOne.equals(BigInteger.ZERO) ? biggerOne : equations.getFirst().b;
        return new CalculationDetails(biggerOne, smallerOne, gcd, equations);
    }

    private java.util.List doCalculateGCD(BigInteger a, BigInteger b) {
        if (b.equals(BigInteger.ZERO)) {
            return new ArrayList();
        }

        var result = doCalculateGCD(b, a.mod(b));
        result.add(new CalculationDetails.Equation(a, a.divide(b), b, a.mod(b)));
        return result;
    }

    public static void main(String[] args) {
        GCDCalculator gcdCalculator = new GCDCalculator();
        System.out.println(gcdCalculator.calculateGCD(\"0\", \"1\").gcd); // should be 1
        System.out.println(gcdCalculator.calculateGCD(\"1\", \"0\").gcd); // should be 1
        System.out.println(gcdCalculator.calculateGCD(\"100\", \"20\").gcd); // should be 20
        System.out.println(gcdCalculator.calculateGCD(\"10\", \"12\").gcd); // should be 2
        System.out.println(gcdCalculator.calculateGCD(\"233\", \"144\").gcd); // should be 1
        System.out.println(gcdCalculator.calculateGCD(\"12345\", \"67890\").gcd); // should be 15
        System.out.println(gcdCalculator.calculateGCD(\"54321\", \"9876\").gcd); // should be 3
        System.out.println(gcdCalculator.calculateGCD(\"1160718174\", \"316258250\").gcd); // should be 1078
    }
}

它的 main 函数里做了一些测试,最大公约数的计算结果结果符合预期。

完整的代码

既然我们的代码已经可以保存在计算最大公约数的过程中用到的所有数据,那么再添加一些和 Swing 相关的代码就可以将计算过程展示出来了。由于 Swing 的知识体系比较复杂,而它的知识点也比较零散,我自己也只是学了点皮毛,和 Swing 相关的代码就不展开说了。完整的代码如下 ⬇️

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;

public class DetailedGCDCalculator {
    public static void main(String[] args) {
        EventQueue.invokeLater(() -> new CalcGreatestCommonDivisor().show());
    }
}

class CalcGreatestCommonDivisor {

    public void show() {
        SimpleFrame frame = new SimpleFrame(\"最大公约数计算器\");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

        JPanel northPanel = new JPanel();
        northPanel.setLayout(new GridLayout(2, 2));
        JTextField textField1 = new JTextField();
        northPanel.add(new JLabel(\"请输入第一个整数:\", SwingConstants.RIGHT));
        northPanel.add(textField1);
        northPanel.add(new JLabel(\"请输入第二个整数:\", SwingConstants.RIGHT));
        JTextField textField2 = new JTextField();
        northPanel.add(textField2);

        JTextArea textArea = new JTextArea(8, 20);
        textArea.setText(\"这里用于展示最大公约数的计算过程\");
        textArea.setEditable(false);
        textArea.setLineWrap(true);
        JScrollPane scrollPane = new JScrollPane(textArea);
        frame.add(scrollPane, BorderLayout.CENTER);

        frame.add(northPanel, BorderLayout.NORTH);
        JButton button = new JButton(\"计算最大公约数\");
        button.addActionListener(new ActionListener() {
            private final GCDCalculator calculator = new GCDCalculator();

            @Override
            public void actionPerformed(ActionEvent e) {
                String rawA = textField1.getText();
                String rawB = textField2.getText();
                try {
                    var calculationDetails = calculator.calculateGCD(rawA, rawB);
                    String text = buildText(calculationDetails);
                    textArea.setText(text);
                } catch (NumberFormatException exception) {
                    textArea.setText(\"Exception found \" + exception.getMessage());
                } catch (IllegalArgumentException exception) {
                    textArea.setText(exception.getMessage());
                }
            }
        });
        frame.add(button, BorderLayout.SOUTH);
    }

    private String buildText(GCDCalculator.CalculationDetails calculationDetails) {
        BigInteger a = calculationDetails.a();
        BigInteger b = calculationDetails.b();
        BigInteger gcd = calculationDetails.gcd();
        List equations = calculationDetails.equationHolders();

        StringJoiner joiner = new StringJoiner(System.lineSeparator());
        if (equations.isEmpty()) { // then b is 0 (so gcd(a, b) = a)
            joiner.add(String.format(\"%s = 0 × %s\", b, a));
            joiner.add(String.format(\"%s = 1 × %s\", a, a));
            joiner.add(String.format(\"所以 gcd(%s, %s) = %s\", a, b, gcd));
        } else {
            String firstLine = String.format(\"通过使用欧几里得算法,可以计算出 gcd(%s, %s) = %s\", a, b, gcd.toString());
            joiner.add(firstLine);
            joiner.add(\"具体过程如下\");
            joiner.add(\"\");
            for (var equation : equations.reversed()) {
                joiner.add(equation.toString());
            }
            joiner.add(\"\");
            joiner.add(\"所以\");
            boolean isFirstLine = true;
            for (var equation : equations.reversed()) {
                if (isFirstLine) {
                    joiner.add(String.format(\"gcd(%s, %s)\", equation.a(), equation.b()));
                    isFirstLine = false;
                } else {
                    joiner.add(String.format(\"= gcd(%s, %s)\", equation.a(), equation.b()));
                }
            }
            joiner.add(\"= \" + gcd);
        }
        return joiner.toString();
    }
}


class SimpleFrame extends JFrame {
    public SimpleFrame(String title) {
        setTitle(title);
        setSize(600, 400);
    }
}


class GCDCalculator {

    record CalculationDetails(
            BigInteger a,
            BigInteger b,
            BigInteger gcd,
            java.util.List equationHolders
    ) {
        /**
         * A holder class for equation a = q * b + r
         */
        record Equation(
                BigInteger a,
                BigInteger q,
                BigInteger b,
                BigInteger r
        ) {
            @Override
            public String toString() {
                return String.format(\"%s = %s × %s + %s\", a, q, b, r);
            }
        }
    }

    private BigInteger toBigInteger(String num) {
        return new BigInteger(num.trim());
    }

    public CalculationDetails calculateGCD(String a, String b) {
        return calculateGCD(toBigInteger(a), toBigInteger(b));
    }

    public CalculationDetails calculateGCD(BigInteger a, BigInteger b) {
        a = a.abs();
        b = b.abs();

        BigInteger biggerOne;
        BigInteger smallerOne;
        if (a.compareTo(b) >= 0) {
            biggerOne = a;
            smallerOne = b;
        } else {
            biggerOne = b;
            smallerOne = a;
        }

        if (biggerOne.equals(BigInteger.ZERO)) {
            throw new IllegalArgumentException(\"两个整数不能都是0!\");
        }
        var equations = doCalculateGCD(biggerOne, smallerOne);
        BigInteger gcd = smallerOne.equals(BigInteger.ZERO) ? biggerOne : equations.getFirst().b;
        return new CalculationDetails(biggerOne, smallerOne, gcd, equations);
    }

    private java.util.List doCalculateGCD(BigInteger a, BigInteger b) {
        if (b.equals(BigInteger.ZERO)) {
            return new ArrayList();
        }

        var result = doCalculateGCD(b, a.mod(b));
        result.add(new CalculationDetails.Equation(a, a.divide(b), b, a.mod(b)));
        return result;
    }

    public static void main(String[] args) {
        GCDCalculator gcdCalculator = new GCDCalculator();
        System.out.println(gcdCalculator.calculateGCD(\"0\", \"1\").gcd); // should be 1
        System.out.println(gcdCalculator.calculateGCD(\"1\", \"0\").gcd); // should be 1
        System.out.println(gcdCalculator.calculateGCD(\"100\", \"20\").gcd); // should be 20
        System.out.println(gcdCalculator.calculateGCD(\"10\", \"12\").gcd); // should be 2
        System.out.println(gcdCalculator.calculateGCD(\"233\", \"144\").gcd); // should be 1
        System.out.println(gcdCalculator.calculateGCD(\"12345\", \"67890\").gcd); // should be 15
        System.out.println(gcdCalculator.calculateGCD(\"54321\", \"9876\").gcd); // should be 3
        System.out.println(gcdCalculator.calculateGCD(\"1160718174\", \"316258250\").gcd); // should be 1078
    }
}

请将以上代码保存为 DetailedGCDCalculator.java
用下方的命令可以编译 DetailedGCDCalculator.java 并运行其中的 main 函数。

javac DetailedGCDCalculator.java
java DetailedGCDCalculator

运行示例

刚启动时

刚启动时,还没有任何输入
image.png

测试用例 1: 计算 gcd(1,0)gcd(1, 0)

image.png

测试用例 2: 计算 gcd(31415,92653)gcd(31415, 92653)

完整的计算步骤比较长,我将窗口放大后,截图如下 ⬇️

image.png

测试用例 3: 计算 gcd(2584,1597)gcd(2584, 1597)1597159725842584Fibonacci 数列中相邻的两项,而 Fibonacci 数列中相邻两项的最大公约数总是 11

完整的计算步骤比较长,我将窗口放大后,截图如下 ⬇️

image.png

测试用例 4: 计算 gcd(210,135)gcd(210, 135)

image.png

参考资料

  • [Java] 用 Swing 生成一个最大公约数计算器

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 编程相关 [Java] 用 Swing 生成一个最大公约数计算器(展示计算过程) https://www.zuozi.net/35953.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务