Java编程二项分布的递归和非递归实现代码实例
作者:ChuanjieZhu 发布时间:2023-08-07 09:38:04
标签:java,递归,二项分布
本文研究的主要内容是Java编程二项分布的递归和非递归实现,具体如下。
问题来源:
算法第四版 第1.1节 习题27:return (1.0 - p) * binomial(N - 1, k, p) + p * binomial(N - 1, k - 1, p);
计算递归调用次数,这里的递归式是怎么来的?
二项分布:
定义:n个独立的是/非试验中成功次数k的离散概率分布,每次实验成功的概率为p,记作B(n,p,k)。
概率公式:P(ξ=K)= C(n,k) * p^k * (1-p)^(n-k)
其中C(n, k) = (n-k) !/(k! * (n-k)!),记作ξ~B(n,p),期望:Eξ=np,方差:Dξ=npq,其中q=1-p。
概率统计里有一条递归公式:
这个便是题目中递归式的来源。
该递推公式来自:C(n,k)=C(n-1,k)+C(n-1,k-1)。实际场景是从n个人选k个,有多少种组合?将着n个人按1~n的顺序排好,假设第k个人没被选中,则需要从剩下的n-1个人中选k个;第k个选中了,则需要从剩下的n-1个人中选k-1个。
书中二项分布的递归实现:
public static double binomial(int N, int k, double p) {
COUNT++; //记录递归调用次数
if (N == 0 && k == 0) {
return 1.0;
}
if (N < 0 || k < 0) {
return 0.0;
}
return (1.0 - p) * binomial(N - 1, k, p) + p * binomial(N - 1, k - 1, p);
}
实验结果:
n k p 调用次数
10 5 0.25 2467
20 10 0.25 2435538
30 15 0.25 2440764535
由结果可以看出来这个递归方法需要调用的次数呈几何灾难,n到50就算不下去了。
改进的二项分布递归实现:
private static long COUNT = 0;
private static double[][] M;
private static double binomial(int N, int k, double p) {
COUNT++;
if (N == 0 && k == 0) {
return 1.0;
}
if (N < 0 || k < 0) {
return 0.0;
}
if (M[N][k] == -1) { //将计算结果存起来,已经计算过的直接拿过来用,无需再递归计算
M[N][k] = (1.0 - p) * binomial(N - 1, k, p) + p * binomial(N - 1, k - 1, p);
}
return M[N][k];
}
public static double Binomial(int N, int k, double p) {
M = new double[N + 1][k + 1];
for (int i = 0; i <= N; i++) {
for (int j = 0; j <= k; j++) {
M[i][j] = -1;
}
}
return binomial(N, k, p);
}
实验结果:
n k p 调用次数
10 5 0.25 101
20 10 0.25 452
30 15 0.25 1203
50 25 0.25 3204
100 50 0.25 5205
由实验结果可以看出调用次数大幅减小,算法可以使用。
二项分布的非递归实现:
事实上,不利用递归,直接计算组合数和阶乘,反而速度更快。
//计算组合数
public static double combination(double N, double k)
{
double min = k;
double max = N-k;
double t = 0;
double NN=1;
double kk=1;
if(min>max){
t=min;
min = max;
max=t;
}
while(N>max){//分母中较大的那部分阶乘约分不用计算
NN=NN*N;
N--;
}
while(min>0){//计算较小那部分的阶乘
kk=kk*min;
min--;
}
return NN/kk;
}
//计算二项分布值
public static double binomial(int N,int k,double p)
{
double a=1;
double b=1;
double c =combination(N,k);
while((N-k)>0){ //计算(1-p)的(N-k)次方
a=a*(1-p);
N--;
}
while(k>0){ //计算p的k次方
b=b*p;
k--;
}
return c*a*b;
}
实验结果:
n k p 二项分布值
10, 5, 0.25 0.058399200439453125
20, 10, 0.25 0.009922275279677706
50, 25, 0.25 8.44919466990397E-5
与前面的算法比对,计算结果是正确的,而且运行速度是非常之快的。
来源:http://blog.csdn.net/u014485485/article/details/77506844


猜你喜欢
- 前言有时线上问题我们用打日志的方式来观察错误或埋点参数,但由于这些日志如果都打出来会占用大量存储空间而且覆盖了一些有效信息,所以线上级别一般
- Android平台有三种网络接口可以使用,他们分别是:java.net.*(标准Java接口)、Org.apache接口和Android.n
- 前言在Android屏幕的空间中,大部分的区域我们都是可以随意绘制,只有一部分区域是显示的固定内容:状态栏标题栏(ActionBar)页面内
- 前言SpringCloud 是微服务中的翘楚,最佳的落地方案。Spring Cloud Config 是一个解决分布式系统的配置管理方案,它
- 一、介绍在实际的软件项目开发过程中,我可以很负责任的跟大家说,如果你真的实际写代码的时间超过5年,你对增删改查这类简单的功能需求开发,可以说
- 本文实例讲述了Android开发之滑动数值选择器NumberPicker用法。分享给大家供大家参考,具体如下:简介:NumberPicker
- Android 中的危险权限详细整理前言:Android 中有上百种权限,现在将所有的权限归为两类:一类是普通权限一类的危险权限普通权限是指
- 介绍MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。比如执行前、执行后或者对SQL结果集处理、sql入参处理等,这样就可以在
- MybatisPlus特性•无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑•损耗小:启动即会自动注入基本 CURD,性能
- springboot环境切换失效概述最近在使用-Dspring.profiles.active=te 来切换spring-boot的环境时,
- Java 本身就自带 JS 引擎,自从 Java 1.6 开始就支持了,愈来愈好。我对 js 比较熟悉,因此有个大胆的想法,为什么不用自带
- 本文研究的主要是高吞吐、线程安全的LRU缓存的相关内容,具体介绍如下。几年以前,我实现了一个LRU缓存用来为关键字来查找它的id。数据结构非
- 本文实例为大家分享了C#实现银行家算法的具体代码,供大家参考,具体内容如下1.死锁死锁,顾名思义,是一种锁住不可自行解开的死局。在操作系统中
- JDK8中有双冒号的用法,就是把方法当做参数传到stream内部,使stream的每个元素都传入到该方法里面执行一下。代码其实很简单:以前的
- 前言在日常的测试工作过程中,app可能会出现闪退崩溃的情况,这个时候就需要测试同学快速抓取到崩溃日志,来有效的辅助开发定位问题,快速的去解决
- spring mvc url匹配禁用后缀访问在spring mvc中默认 访问url 加任意后缀名都能访问比如:你想访问 /login ,但
- 本文实例为大家分享了java使用集合实现通讯录的具体代码,供大家参考,具体内容如下代码有些繁琐,只适合初学者。项目1java通讯录方法(声明
- 添加标题在 Winfrom 界面中添加一个 ListView 组件,然后点击右上角的箭头,点击编辑列添加下面标题,然后点击确定此时 List
- 本文实例讲述了java两种单例模式用法。分享给大家供大家参考,具体如下:按照加载方式的不同,单例模式有两种实现:private:只能在同一个
- 本文实例讲述了Android开发获取重力加速度和磁场强度的方法。分享给大家供大家参考,具体如下:Android获取重力加速度和磁场强度主要依