Java实现50的阶乘(Java大数阶乘的实现)

2025-10-24 14:36:24

1、我们先来看看如果通过Java提供的数值类型来计算阶乘,最多能计算到多大数字:

1. 使用 int ,其由 4 个字节表示,数值范围为 : -2147483648 至 2147483647, 最多计算到 12 的阶乘

2. 使用 long , 其由 8 个字节表示,数值范围为 -9223372036854775808 至 9223372036854775807, 最多计算到 20 的阶乘

看样,如果通过java原始的数据类型来计算阶乘,最多能计算到20,如果要计算更大数字的阶乘(比如50),那该如何表示呢?

2、使用自定义数字类型,这里使用链表表示法,即对于一个数字,将每一个数值位从低到高放到一个链表中来表示,示例如下 (注意目前我们只处理正数):

数字: 1234 链表表示为:1->2->3->4

数字: 788996 链表表示为:7->8->8->9->9->6

对于其Java代码实现,我们定义一个链表节点类:

// 其以一个静态内部类的形式存在

private static class ListNode {


        
        int val; // 链表节点的值
        ListNode next; // 下一个节点
        
        public ListNode(int val) {
            this.val = val;
        }
        // 重新 toString 方法,方便最后输出整个链表

        @Override


        public String toString() {
            
            StringBuilder b = new StringBuilder();
            b.append(val);
            ListNode nextNode = next;
            while(null != nextNode) {
                b.append(",").append(nextNode.val);
                nextNode = nextNode.next;
            }
            
            return b.toString();
        }
        
    }

Java实现50的阶乘(Java大数阶乘的实现)

3、如何表示一个大数,我们已经有了具体方案,对于阶乘而言,就是不断让这个大数和一个数字相乘,即 ListNode * n , 这里的乘法该如何计算呢?我们先实现最简单的情况,那就是 n<10 这种情况(即你是单位数),代码如下(注意进位的处理):

/**
     * 对于这个方法,num<10
     * @param ln 大数,非空
     * @param num
     * @return
     */


    private ListNode multipleSingleNum(ListNode ln, int num) {
        
        ListNode result = new ListNode(0);
        ListNode currentNode = result;
        int carryBit = 0; // 进位
        while(null != ln) {
            int mVal = ln.val * num + carryBit;
            carryBit = mVal/10;
            mVal = mVal%10;
            ListNode theNode = new ListNode(mVal);
            currentNode.next = theNode;
            currentNode = currentNode.next;
            ln = ln.next;
        }
        // 注意最后要看看是否还有有效的进位没有处理
        if(carryBit > 0) {
            currentNode.next = new ListNode(carryBit);
        }
        
        // 返回结果
        return result.next;
    }

Java实现50的阶乘(Java大数阶乘的实现)

4、那么对于更大数字(n>=10)的相乘该如何进行呢?我们可以把n拆一下,再参与计算,即:

ListNode * n = ListNode * (n1 + n2 + n3...) = ListNode * n1 + ListNode *n2 + ListNode * n3 .... 其中:n 大于等于10, 拆分的 n1 n2 n3 均小于10

我们先实现这个拆分方法:

/**


     * 拆分数字,将一个大于等于10的数字,拆分为多个小于10的数字
     * @param num
     * @return
     */
    private int[] scatterNumber(int num) {
        // 注意要除以9.0, 否则两个整数相除一定返回一个整数

        int resultLength = (int)Math.ceil(num/9.0);


        int[] result = new int[resultLength];
        int index = 0;
        while(num >= 10) {
            result[index] = 9;
            num = num - 9;
            index++;
        }
        if(num > 0) {
            result[index] = num;
        }
        return result;
    }

Java实现50的阶乘(Java大数阶乘的实现)

Java实现50的阶乘(Java大数阶乘的实现)

5、我们利用上述两步构造一个普遍适用的大数相乘的方法,代码如下:

private ListNode multipleNumber(ListNode ln, int num) {


        
        // 将数字进行拆分
        int[] allUsedNums = scatterNumber(num);
        
        ListNode result = new ListNode(0);
        for(int usedNum : allUsedNums) {
            
            // 将每一个小于10的数字和我们的大数相乘
            ListNode mulResult = multipleSingleNum(ln, usedNum);
            // 将相乘的结果进行累加
            result = addTwoNumbers(result, mulResult);
        }
        
        return result;
    }

Java实现50的阶乘(Java大数阶乘的实现)

6、上述步骤中,数字拆分相乘后会返回多个独立的大数 ListNode, 我们调用了 addTwoNumbers 实现结果累加,具体代码如下(整个过程其实就是对齐相加,注意进位的处理):

private ListNode addTwoNumbers(ListNode l1, ListNode l2) {


        
        int firstNodeVal = l1.val + l2.val;
        int carryBit = firstNodeVal/10; // 进位
        firstNodeVal = firstNodeVal%10;
        ListNode result = new ListNode(firstNodeVal); // 最后的计算结果
        ListNode computePoint = result; // 指向当前的计算节点
        l1 = l1.next; // 移到下一个节点
        l2 = l2.next; // 移到下一个节点
        while(null != l1 || null != l2) {
            
            int l1Val = null == l1?0:l1.val;
            int l2Val = null == l2?0:l2.val;
            int sum = l1Val + l2Val + carryBit; // 计算和,要加上进位
            carryBit = sum/10; // 重新计算进位
            sum = sum%10; // 当前位的和
            computePoint.next = new ListNode(sum);
            computePoint = computePoint.next;
            l1 = null == l1?null:l1.next;
            l2 = null == l2?null:l2.next;
        }
        // 如果最后进位有结余,则需要将其设置到新节点中
        if(carryBit > 0) {
            computePoint.next = new ListNode(carryBit);
        }
        return result;
        
    }

Java实现50的阶乘(Java大数阶乘的实现)

7、测试,我们分别计算 10, 20,50 的阶乘,计算结果如图示。

Java实现50的阶乘(Java大数阶乘的实现)

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢