优化阶乘算法的探索

优化阶乘算法的探索优化阶乘算法的探索中国地质大学(武汉)  陈海丰 阶乘(factorial)是基斯顿·卡曼(ChristianKramp,1760–1826)于1808年发明的运算符号。阶乘,也是数学里的一种术语,是指从1乘以2乘以3乘以4一直乘到所要求的数。例如所要求的数是4,则阶乘式是1×2×3×4,得到的积是24,24就是4的阶乘。如果所要求的数是n,则阶乘式是1×2×3×……×n,设

大家好,又见面了,我是你们的朋友全栈君。

优化阶乘算法的探索

中国地质大学(武汉)   陈海丰

 

阶乘(factorial)是基斯顿·卡曼(Christian Kramp, 1760 – 1826)于1808年发明的运算符号。阶乘,也是数学里的一种术语,是指从1乘以2乘以3乘以4一直乘到所要求的数。例如所要求的数是4,则阶乘式是1×2×3×4,得到的积是24,24就是4的阶乘。如果所要求的数是n,则阶乘式是1×2×3×……×n,设得到的积是x,x就是n的阶乘。在表示阶乘时,就使用“!”来表示,如n阶乘,就表示为n!。
    根据阶乘的定义,我们不难得到求解阶乘的递推式。

            …………………………………(1)

当n值很小时,在计算机中可以直接用整型数据的运算就可以解决了,可是当n值很大,比如n=10000时计算结果就不能用现有的数据类型来存放了,因为它的位数已远远超过了现有的数据类型(如10000!有35660位)。为了解决所有数据类型都无法存放这样一个庞大的数据,目前大家采用的是将一个大数一位一位的存放到一个字符型数组或整型数组中,然后要运算时对其每一位进行单独运算,这样就解决了庞大数据的存放问题。但具体怎样对两个都比较大的数的作乘法运算呢?这就要利用大整数的高精度运算。如A,B都是位数比较多的大整数,现在要作A*B运算。小学时我们作45*12是先把12中的2与45的个位5相乘,再把2与45的十位4相乘,然后同样再把12中的1与45中的每一位从低到高依次相乘。在这里我们也可以模拟45*12,把A中每一位从低到高与B中的个位相乘,与后再与B中的十位相乘,依次类推,最后把所有的结果对应相加就可以得到所要求的结果了。

具体代码(一):

#include <stdio.h>

#include <string.h>

 

char a[40000], b[10];

int c[40000];

int main()

{    

    int n;

     while(scanf(“%d”, &n) != EOF){

        int la, lb, lc, i, j, k, k1;

        if(n == 0 || n == 1){

              printf(“1/n”);

              continue;

         } //几种特殊情况

        if(n == 2){

              printf(“2/n”);

              continue;

         }

        a[0] = 50;   //初始化使是最先相乘的数从开始

         for(k1 = 3;k1 <= n;k1++){                  

              k = k1;          

              for(j = 0;k;j++){

                   b[j] = k % 10 + 48;

                   k /= 10;

              }          

              la = strlen(a);

              lb = strlen(b);  

              memset(c, 0, sizeof(c));      

              for(i = 0;i < la;i++){

                   for(j = 0;j < lb;j++){          

                       c[i + j] += (a[i] – 48) * (b[j] – 48);

                       //循环相乘,结果存放到另一数组中         

                       c[i + j + 1] += c[i + j] / 10;   //进位         

                       c[i + j] %= 10;

                       lc = i + j + 1;   //当前位     

                   }

              }

              if(c[lc] == 0) lc–;    

              for(i = lc;i >= 0;i–)

                   for(i = lc;i >= 0;i–) a[i] = c[i] + 48;

                   //将结果复制到数组a中,再和b数组相乘

         }

         for(i = lc;i >= 0;i–){   //输出结果时从数组的最后一个开始输出

              printf(“%c”, a[i]);

        }

         printf(“/n”);    

         memset(a, 0, sizeof(a)); //将数组全部初始化

         memset(b, 0, sizeof(b));        

     }

     return 0;

}

上面程序可以计算大数的阶乘,但是效率非常的低,如10000!的阶乘需要2000Ms左右,所以这种算法并不能解决实际问题。考虑到上面的程序是一位一位的把一个大数存放下来,然后相乘时也是一位一位的进行的。然后我想到定义一个整型的数组,每一位不是存放一位而是存放五位,这样相加,相乘的次数就是原来的 ,10000!运算时间是200Ms,是原来的 。

具体代码(二):

 

#include<stdio.h>

 

int main()  

{    

     int n;

     printf(“请输入一个整数N(0~20000):/n”);    

     while(scanf(“%d”, &n) != EOF){      

         int s[16000] = {0}, j, i, k = 0, t = 0, p = 0;

         long sum = 0;        

         s[0] = 1;  

         for(j = 1;j <= n;j++){  

              for(i = 0;i <= t;i++){  

                   sum = s[i] * j + p;  

                   p = 0;  

                   if(sum > 99999){  

                       s[i] = sum % 100000;   //每一位存放位         

                       p = sum / 100000;          

                       if(t == i){

                            t++;

                            s[t] = 0;

                       }  

                   }  

                   else s[i]=sum;  

              }  

         }  

         printf(“%d!=”, n);

         printf(“%d”, s[t]);  

         for(i = t – 1;i >= 0;i–){    

              printf(“%05d”,s[i]);  

         }  

         printf(“/n/n”);

         printf(“请再输入一个整数N(0~20000):/n”);

     }  

     return 0;  

}

 

当然在程序中可以把存放大数的数组定义成长整型(long)则每一个数组元素可以存放更多位,10000!的运行时间可以缩短到50Ms。在实践中算法的可行性是非常重要的,算法要不断的优化才能有机实际作用,所以要学会优化算法,提高自己的编程能力。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cschf/archive/2008/05/28/2491623.aspx

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/164010.html原文链接:https://javaforall.net

(0)
上一篇 2022年7月24日 上午6:36
下一篇 2022年7月24日 上午6:36


相关推荐

  • ajax出现”parsererror”错误

    ajax出现”parsererror”错误1.后台控制器方法上加了@ResponseBody注解,但AJAX未加dataType:“JSON”2.后台控制器方法的返回值与指定的返回值类型不同

    2022年6月20日
    37
  • 马斯克宣布 Grok 3.5 早期测试版下周发布:首个能回答火箭发动机与电化学问题的 AI

    马斯克宣布 Grok 3.5 早期测试版下周发布:首个能回答火箭发动机与电化学问题的 AI

    2026年3月15日
    3
  • UTF-8和GBK有啥区别?

    UTF-8和GBK有啥区别?粉丝求助 如何解决 把编辑器和浏览器的字符集统一设置成 utf 8 或者 gbk 即可 主要区别 1 GBK 是在 bai 国家标准 GB2312 基础上扩容后兼容 GB2312 的标准 好像还不 du 是国家标准 zhiGBK 编码 dao 专门用来解决中文编码的 是双字节的 不论中英文都是双字节的 2 UTF 8 编码是用以解决国际上字符的一种多字节编码 它对英文使用 8 位 即一个字节 中文使用 24 位 三个字节 来编码 对于英文字符较多的论坛则用 UTF 8 节省空间 另外 如果是外国

    2026年3月17日
    2
  • 查看linux执行的命令记录_shell 调用history

    查看linux执行的命令记录_shell 调用history前言我们每次敲打linux命令的时候,有时候想用之前用过的命令,一般情况下,我们都会按↑↓箭头来寻找历史的命令记录,那如果我想用1天前执行的某条命令,难道还要按↑100次?显示这样是不现实的,我们可

    2022年7月31日
    11
  • WLAN没有有效的IP配置如何一招解决

    WLAN没有有效的IP配置如何一招解决提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档WLAN没有有效的IP配置如何一招解决前言一、电脑连不上网?二、具体步骤1.命令提示符(管理员)输入netshwinsockreset2.重启电脑总结前言自己的笔记本原本好好的突然就连不上网了,该怎么办?别急,博主也遇到过这样的问题,并且找到一种方法,非常有用,认真看哦!一、电脑连不上网?电脑突然就连不上网,诊断以后出现这个你是否在网上看到这样的解决方案?还有这样的博主亲自尝试过,好多种方法都不管用,这里我介绍

    2022年7月11日
    24
  • 三目运算 多条判断

    三目运算 多条判断含义三目运算符格式 关系表达式 表达式 1 表达式 2 当关系表达式的值是 true 的时候 执行表达式 1 当关系表达式值是 false 的时候 执行表达式 2 关系表达式的值要么是 true 要么是 false 实例 1 两种情况的 假设获取的列表 list 的 state 状态有 0 和 1 显示对应的值 list status 0 等待付款 已付款 2 有三种情况的 list status 0 等待付款 list status 1 已支付 已取消 3 假设我们设置操作的按钮

    2026年3月17日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号