Java編程二項分布的遞歸和非遞歸實現(xiàn)代碼實例
本文研究的主要內(nèi)容是Java編程二項分布的遞歸和非遞歸實現(xiàn),具體如下。
問題來源:
算法第四版 第1.1節(jié) 習(xí)題27:return (1.0 - p) * binomial(N - 1, k, p) + p * binomial(N - 1, k - 1, p);
計算遞歸調(diào)用次數(shù),這里的遞歸式是怎么來的?
二項分布:
定義:n個獨立的是/非試驗中成功次數(shù)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。
概率統(tǒng)計里有一條遞歸公式:

這個便是題目中遞歸式的來源。
該遞推公式來自:C(n,k)=C(n-1,k)+C(n-1,k-1)。實際場景是從n個人選k個,有多少種組合?將著n個人按1~n的順序排好,假設(shè)第k個人沒被選中,則需要從剩下的n-1個人中選k個;第k個選中了,則需要從剩下的n-1個人中選k-1個。
書中二項分布的遞歸實現(xiàn):
public static double binomial(int N, int k, double p) {
COUNT++; //記錄遞歸調(diào)用次數(shù)
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);
}
實驗結(jié)果:
n k p 調(diào)用次數(shù) 10 5 0.25 2467 20 10 0.25 2435538 30 15 0.25 2440764535
由結(jié)果可以看出來這個遞歸方法需要調(diào)用的次數(shù)呈幾何災(zāi)難,n到50就算不下去了。
改進(jìn)的二項分布遞歸實現(xiàn):
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) { //將計算結(jié)果存起來,已經(jīng)計算過的直接拿過來用,無需再遞歸計算
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);
}
實驗結(jié)果:
n k p 調(diào)用次數(shù) 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
由實驗結(jié)果可以看出調(diào)用次數(shù)大幅減小,算法可以使用。
二項分布的非遞歸實現(xiàn):
事實上,不利用遞歸,直接計算組合數(shù)和階乘,反而速度更快。
//計算組合數(shù)
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;
}
實驗結(jié)果:
n k p 二項分布值 10, 5, 0.25 0.058399200439453125 20, 10, 0.25 0.009922275279677706 50, 25, 0.25 8.44919466990397E-5
與前面的算法比對,計算結(jié)果是正確的,而且運行速度是非常之快的。
總結(jié)
以上就是本文關(guān)于Java編程二項分布的遞歸和非遞歸實現(xiàn)代碼實例的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
- Java實現(xiàn)的二叉樹常用操作【前序建樹,前中后遞歸非遞歸遍歷及層序遍歷】
- JAVA實現(xiàn)遍歷文件夾下的所有文件(遞歸調(diào)用和非遞歸調(diào)用)
- java遞歸與非遞歸實現(xiàn)掃描文件夾下所有文件
- JAVA遞歸與非遞歸實現(xiàn)斐波那契數(shù)列
- Java基于棧方式解決漢諾塔問題實例【遞歸與非遞歸算法】
- Java編程獲取文件列表及子文件目錄的方法(非遞歸)
- Java編程用棧來求解漢諾塔問題的代碼實例(非遞歸)
- java數(shù)學(xué)歸納法非遞歸求斐波那契數(shù)列的方法
- java 漢諾塔Hanoi遞歸、非遞歸(仿系統(tǒng)遞歸)和非遞歸規(guī)律 實現(xiàn)代碼
- Java語言實現(xiàn)非遞歸實現(xiàn)樹的前中后序遍歷總結(jié)
相關(guān)文章
自定義的Troop<T>泛型類( c++, java和c#)的實現(xiàn)代碼
這篇文章主要介紹了自定義的Troop<T>泛型類( c++, java和c#)的實現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-05-05
SpringBoot集成JPA持久層框架,簡化數(shù)據(jù)庫操作
JPA(Java Persistence API)意即Java持久化API,是Sun官方在JDK5.0后提出的Java持久化規(guī)范。主要是為了簡化持久層開發(fā)以及整合ORM技術(shù),結(jié)束Hibernate、TopLink、JDO等ORM框架各自為營的局面。JPA是在吸收現(xiàn)有ORM框架的基礎(chǔ)上發(fā)展而來,易于使用,伸縮性強(qiáng)。2021-06-06

