阶乘

Python11 递归函数

删除回忆录丶 提交于 2019-11-28 04:14:34
递归函数 理解:一个函数在内部调用自身本身,这个函数就是递归函数。 优点:递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。 递归函数实例: 阶乘 : 代码: ``` # 阶乘 -递归函数实现 : 例3的阶乘: 1 * 1 * 2 * 3 def factorial(x): if not isinstance(x,(int)) or x < 0 : # 校验参数类型必须是正整数或者是0 raise TypeError("参数x类型必须是正整数") elif x == 0: return 1 # 0的阶乘是1 else: return x * factorial(x-1) # 分解 return x * factorial(x-1) # x = 3 时, 结果是 3 * factorial(3-1)(即x=2) # x = 2 时,结果是 2 * factorial(2-1) (即x=1) # x = 1 时,结果是 1 * factorial(1-1) (即x=3) # x = 0 时,结果是 1 # 最后结果 3 * 2 * 1 * 1 print(factorial(3)) ``` 运行结果: 栈溢出:在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回

尾调用优化和尾递归改写

安稳与你 提交于 2019-11-28 01:57:23
1 尾调用 尾调用就是指某个函数的最后一步是调用另一个函数。 # 是尾调用 def f(x): return g(x) # 不是尾调用,因为调用函数后还要执行加法,加法才是最后一步操作 def f(x): return 1+g(x) 2 尾调用优化 函数调用有一个调用栈,栈内保存了这个函数内部的变量信息。函数掉用就是切换不同的调用帧,从而保证每个函数有独立的运行环境。因为尾调用是函数的最后一步操作,所以在进入被尾调用函数之前并不需要保留外层函数的运行时环境,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用记录,取代外层函数的调用记录就可以了。这就叫做"尾调用优化"(Tail call optimization),即只保留内层函数的调用记录。如果所有函数都是尾调用,那么完全可以做到每次执行时,调用记录只有一项,这将大大节省内存。这就是"尾调用优化"的意义。 尾递归 如果尾调用自身,就称为尾递归。递归非常耗费内存,因为需要同时保存成千上百个调用记录,很容易发生"栈溢出"错误(stack overflow)。但对于尾递归来说,由于只存在一个调用记录,所以永远不会发生"栈溢出"错误。 def factorial(n) { if (n == 1) return 1; return n * factorial(n - 1); } factorial(5) // 120

JavaScript函数尾调用与尾递归

安稳与你 提交于 2019-11-28 01:56:33
什么是函数尾调用和尾递归 函数尾调用与尾递归的应用 一、什么是函数的尾调用和尾递归 函数尾调用就是指函数的最后一步是调用另一个函数。 1 //函数尾调用示例一 2 function foo(x){ 3 return g(x); 4 } 5 //函数尾调用示例二 6 function fun(x){ 7 if(x > 0){ 8 return g(x); 9 } 10 return y(x); 11 } 调用最后一步和最后一行代码的区别,最后一步的代码并不一定会在最后一行,比如示例二。还有下面这一种不能叫做函数尾调用: 1 // 下面这种情况不叫做函数尾调用 2 function fu(x){ 3 var y = 10 * x; 4 g(y); 5 } 为什么这种情况不叫作函数的尾调用呢?原因很简单,因为函数执行的最后一步是return指令,这个指令有两个功能,第一个功能是结束当前函数执行,第二个功能是将指令后面的数据传递出去(函数返回值)。而这个return指令不管有没有声明都会执行,没有声明的情况下返回的数据是undefined,所以上面的代码实际上是以下结构: 1 function fu(x){ 2 var y = 10 * x; 3 g(y); 4 return undefined; 5 } return指令是先关闭函数,然后再返回数据。说到这里,就会引发一个问题出来

JavaScript函数尾调用与尾递归

半世苍凉 提交于 2019-11-27 15:13:48
什么是函数尾调用和尾递归 函数尾调用与尾递归的应用 一、什么是函数的尾调用和尾递归 函数尾调用就是指函数的最后一步是调用另一个函数。 1 //函数尾调用示例一 2 function foo(x){ 3 return g(x); 4 } 5 //函数尾调用示例二 6 function fun(x){ 7 if(x > 0){ 8 return g(x); 9 } 10 return y(x); 11 } 调用最后一步和最后一行代码的区别,最后一步的代码并不一定会在最后一行,比如示例二。还有下面这一种不能叫做函数尾调用: 1 // 下面这种情况不叫做函数尾调用 2 function fu(x){ 3 var y = 10 * x; 4 g(y); 5 } 为什么这种情况不叫作函数的尾调用呢?原因很简单,因为函数执行的最后一步是return指令,这个指令有两个功能,第一个功能是结束当前函数执行,第二个功能是将指令后面的数据传递出去(函数返回值)。而这个return指令不管有没有声明都会执行,没有声明的情况下返回的数据是undefined,所以上面的代码实际上是以下结构: 1 function fu(x){ 2 var y = 10 * x; 3 g(y); 4 return undefined; 5 } return指令是先关闭函数,然后再返回数据。说到这里,就会引发一个问题出来

欧拉定理证明&阶乘的逆元

半世苍凉 提交于 2019-11-27 14:53:30
欧拉定理证明: https://www.cnblogs.com/wangxiaodai/p/9758242.html 阶乘的逆元: 记 f[i] = i! mod p,    g[i] = (i!)−1 mod p 容易发现 g[i] = g[i]+1∗(i +1)      i−1 = f[i]−1∗g[i] 只需要算出 f[n],然后求出 f[n] 的逆元 g[n],然后递推即可。 来源: https://www.cnblogs.com/minun/p/11367417.html

递归与迭代

自闭症网瘾萝莉.ら 提交于 2019-11-27 02:04:57
关于c语言部分函数的一些总结和注意事项: 递归是一种强有力的技巧,但是和其他技巧一样,它也可能被误用。这里就有一个例子。阶乘的定义往往就是以递归的形式描述的。factorial(n)=1,n<=0; factorial(n)=n*factorial(n-1),n>0; 这个定义同时具备了递归所需要的两个特性:1、存在限制条件,当符合这个条件时递归便不再继续;2、每次递归调用之后越来越接近这个限制条件。用这种方式定义阶乘往往引导人们使用递归来实现阶乘函数。程序如下所示: 1 //用递归方法计算n的阶乘 2 3 long factorial(int n) 4 5 { 6 7 if(n<=0) 8 9 return 1;10 11 else12 13 return n*factorial(n-1);14 15 } 但它不是递归的良好用法。为什么呢?因为递归函数调用将涉及一些运行时开销——参数必须压到堆栈中,为局部变量分配内存空间(所有递归均如此,并非特指这个例子),寄存器的值必须保存等。当递归函数的每次调用返回时,上述这些操作必须还原,恢复成原来的样子。所以,基于这些开销,对于这个程序而言,它并没有简化问题的解决方案。下面这个函数是尾部递归的一个例子,由于函数在递归调用返回后不再执行任何任务,所以尾部递归可以很方便的转换成一个简单循环,完成相同的任务 ,程序效率更为有效。 1 /

51Nod-1057 N的阶乘(大数乘法)

时光总嘲笑我的痴心妄想 提交于 2019-11-26 10:15:59
1057 N的阶乘 输入N求N的阶乘的准确值。 输入 输入N(1 <= N <= 10000) 输出 输出N的阶乘 输入样例 5 输出样例 120 分析 这道题如果用常规的模拟乘法可能有一半的测试点超时。我来说一下超时原因: 因为20的阶乘,就已经达到 2432902008176640000 了,但是常规算法中频繁进位操作其实很耗时, 所以将原来的数组一个位置只存一位数改为一个位置存多位数,这样,循环次数就大大减少了,效率就高了。 代码 #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; typedef long long ll; const ll MAX1 = 1e8; ll a[maxn]; ll judge(ll n) { ll carry = 0, sum = 1; for (ll i = n; i >= 2; i--) { for (ll j = 0; j < sum; j++) { ll t = a[j]*i; a[j] = (t + carry)%MAX1; carry = (t + carry)/MAX1; } while(carry){ a[sum++] =