递归与分支策略:
1.例子一:阶乘
说到递归,不得不提下数学归纳法。数学归纳法是一种通过自身的语汇定义某事物自己的方法。
用自身定义某事物自身的方法看起来像是在绕圈子,但是事实上他是完全正确的(假设有一个基值的情况)
阶乘在概念上和三角数字式类似的,只是用*取代了+而已。
请看下面的式子:
三角数字:f(n)=f(n-)+n;
阶乘:n!=(n-1)!*n;<==>f(n)=f(n-1)*n;
A.阶乘的编程实现:
public long factorial(int n){//关于返回值的类型,小的话用int,long
if(n==0)
return 1;
else
return factorial(n-1)*n;
}
B.补充:求超大数n的阶乘,使用math包下的BigInteger
先介绍下BigInteger和BigDecimal包装类型(没有基本类型),是java.math包下的类,不是java.lang.Math:
Java提供了两个用于高精度计算的类:BigInteger和BigDecimal。虽然它们大体上属于“包装器类”的范畴,但两者都没有对应的基本类型。不过,这两个类包含的方法,提供的操作与对基本类型所能执行的操作相似。也就是说,能作用于int或float的操作,也同样能作用于BigInteger或BigDecimal。只不过必须以方法调用方式取代运算符方式来实现。由于这么做复杂了许多,所以运算速度会比较慢,相比而言,int和float是以速度取代了精度。
BigInteger支持任意精度的整数。也就是说,在运算中,可以准确地表示任何大小的整数值,而不会丢失任何信息。
常用方法:
abs() //返回其值是此BigInteger的绝对值的BigInteger。
add(BigInteger val) //返回其值为(this+val)的BigInteger。
subtract(BigInteger val) //返回其值为(this-val)的BigInteger。
multiply(BigInteger val) // 返回其值为(this*val)的BigInteger。
divide(BigInteger val) //返回其值为(this/val)的BigInteger。
remainder(BigInteger val) //返回其值为(this%val)的BigInteger。
compareTo(BigInteger val) //将此BigInteger与指定的BigInteger进行比较。返回值1、0、-1分别表示大于、等于、小于
pow(int exponent) //返回当前大数的exponent次幂。
toString() //返回此BigInteger的十进制字符串表示形式。
toString(int radix) //返回此BigInteger的给定基数(radix进制)的字符串表示形式。
BigDecimal支持任何精度的定点数,例如,可以用它进行精确的货币运算。
它可以用来表示任意精度的有符号十进制数。BigDecimal 由任意精度的整数非标度值 和 32 位的小数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。BigDecimal 类提供以下操作:算术、标度操作、舍入、比较、哈希算法和格式转换。toString() 方法提供 BigDecimal 的规范表示形式。 BigDecimal 类使用户能完全控制舍入行为
使用例子:
BigDecimal bigDecimal = new BigDecimal(Math.PI);
bigDecimal = bigDecimal.setScale(2,BigDecimal.ROUND_DOWN);//接近零的舍入模式取PI值小数点后面二位
->3.14
使用BigInteger实现10000!的算法:
package DataStructures_Algorithm;
import java.math.BigInteger;
public class FactorialBigIntegerTest {
public static void main(String[] args) {
System.out.println(factorial(10000));
}
private static final BigInteger factorial(int n){
BigInteger bigInteger=new BigInteger(""+n);
if(n==0)
return BigInteger.ONE;
else
return factorial(n-1).multiply(bigInteger);
}
}
扩展有这样一组数字序列0,1,1,2,3,5,8……..,求第100个数是多少!
很明显:第n项的值
n=1,f(1)=0;
n=2,f(2)=1;
n=3,f(3)=f(1)+f(2)=0+1=1;
n=4,f(4)=f(2)+f(3)=1+1=2;
n=5,f(5)=f(3)+f(4)=1+1=1+2=3;
n=6,f(6)=f(4)+f(5)=2+3=5;
……………………..
n=n,f(n)=f(n-2)+f(n-1);
编程实现f(100):这里用数组实现,用递归没效率
private static final BigInteger distributePoker(int n) {
// BigInteger数组
BigInteger[] resultBigInteger = new BigInteger[n];
for (int i = 0; i < n; i++) {
if (i == 0)
resultBigInteger[i] = BigInteger.ZERO;
if (i == 1)
resultBigInteger[i] = BigInteger.ONE;
if(i>=2)
resultBigInteger[i] = resultBigInteger[i - 2]
.add(resultBigInteger[i - 1]);
}
return resultBigInteger[n - 1];
}
C.不使用BigInteger,计算超大数阶乘算法——>用整型数组保存每位数的结果,最后返回字符串,效率最高
private static final String ArrayStringFactorial(int n) {
int a[] = new int[200];// 确保保存最终运算结果的数组位数足够大,200位的数已经够大了
int carry = 0;// 进位标志位
int digit = 1;// 位数
a[0] = 1;// 将结果先初始化为1
int temp;// 阶乘的任一元素与临时结果的某位的乘积结果
StringBuffer resultStr = new StringBuffer();
for (int i = 2; i <= n; ++i)// 开始阶乘,阶乘元素从2开始依次“登场”
{
// 按最基本的乘法运算思想来考虑,将临时结果的每位与阶乘元素相乘
for (int j = 1; j <= digit; ++j) {
temp = a[j - 1] * i + carry;// 相应阶乘中的一项与当前所得临时结果的某位相乘(加上进位)
a[j - 1] = temp % 10;// 更新临时结果的位上信息
carry = temp / 10; // 看是否有进位
}
while (carry!=0?true:false)// 如果有进位
{
a[(++digit) - 1] = carry % 10;// 新加一位,添加信息。位数增1
carry /= 10; // 看还能不能进位
}
}
for (int i = digit; i >= 1; --i) {
resultStr.append(a[i - 1]);
}
return resultStr.toString();
}
分治策略 请继续关注下文。。。。。。。。。。