36 选 7 彩票机选程序

编写了一个 “36 选 7 ”彩票机选程序,用了Random类产生随机数,Arrays类对数组进行操作(包括用sort()对数组排序、toString()输出数组),大家可以用这个程序去买彩票了,中奖了要请客哦……

在设计程序过程中,卡壳的地方在怎样避免随机数的重复问题。

百度了下,发现可以用抽牌算法,发现的链接对这种算法解释的很详细:
简单彩票选号

/*************36 选 7 彩票机选程序*************/
/*
一、 购票方法 
    北京市36选7电脑体育彩票采用运动项目型组合式游戏玩法,购买者可从36个运动项目中
任意选取不重复的7个项目,组成一注彩票,进行游戏,每一注有一次中奖机会。也可一次选
择7个以上的项目组成复式票,进行游戏。一张复式票包含多注彩票(每注仍为7个项目,但
每注的7个项目都不同),复式票的选项最多为16项(详见“复式票游戏规则”)。
二、 36种运动图案分别用数字01-36来表示。(如下所示)
	01田径 02游泳 03跳水 04水球 05体操 06举重 
	07射击 08射箭 09击剑 10柔道 11摔跤 12拳击 
	13马术 14足球 15篮球 16排球 17乒乓 18羽毛 
	19网球 20手球 21棒球 22垒球 23滑雪 24冰球 
	25帆船 26帆板 27皮艇 28划艇 29赛艇 30技巧 
	31武术 32滑水 33蹼泳 34围棋 35象棋 36桥牌 
三、 中奖办法
	先后开出8个中奖号码,前7位为正选号(顺序不限),最后一位为特别号.
	特等奖:选中全部7个正选项; 
	一等奖:选中6个正选项加特别项; 
	二等奖:选中6个正选项; 
	三等奖:选中5个正选项加特别项; 
	四等奖:选中5个正选项;或者选中4个正选项加特别项。 
	五等奖:选中4个正选项,或者选中3个正选项加特别项。
*/

import java.util.Random;
import java.util.*;

public class RandomDemo01 {
	public static void main(String []args) {
		Random r = new Random();
		int temp[] = new int[7];

		for (int i = 0; i < 7; i++){	// [1,36]中产生随机数
			temp[i] = (r.nextInt(36) + 1);	// 注意号码不能含0,所以要加1		
		}

		Arrays.sort(temp);	// 为方便查看所选数字,进行排序
		for (int i = 0; i < 7; i++){	// 打印输出结果
			if (i == 6){
				System.out.print(temp[i]);		// 第7个数字后没有“+”,进行格式控制
			}
			else System.out.print(temp[i] + " + ");			
		}
	}
}


程序运行结果:
1 + 3 + 4 + 10 + 11 + 21 + 30

程序2、用“抽牌算法”改进后的程序

import java.util.Random;
import java.util.Arrays;

public class RandomDemo02 {
	public static void main(String []args) {
		Random r = new Random();
		int intArrays[] = new int[36];	// 声明存放牌的数组
		for (int i = 0; i < 36; i++){	// 初始化牌
			intArrays[i] = i + 1;
		}
		int result[] = new int[7];		// 存放所选号码结果

		for (int i = 0; i < 7; i++){		// 选7次
// 1、获取随机数求得的“牌堆”数组里的下标值.eg:第一次可以是从[0,35]			
			int index = r.nextInt(36-i);	
// 2、交换第index个数字(所选号码)和第35-i个数,使这第index个数放到一边 			
			swaps(intArrays, index, (35-i));
// 3、将放到一边后的值存放在结果中
			result[i] = intArrays[intArrays[35-i]];	
		}

		Arrays.sort(result);	// 对结果进行排序,方便查看所选号码

		for (int i = 0; i < 7; i++){	// 以for循环输出数组结果
			if (i == 6){
				System.out.print(result[i]);	// 控制输出格式,最后一个数字后没有 “+” 
			}
			else System.out.print(result[i] + "+");
		}

		// 也可以字符串输出数组
		// System.out.println(Arrays.toString(result));
	}

// 交换数组中下标a 和 下标b的数值
	public static void swaps(int array[],int a, int b){	
		int temp = array[a];
		array[a] = array[b];
		array[b] = temp;
	}
}

程序运行结果:

4+7+13+14+24+33+36
思考问题:

1、能不能再结合Java类集中的集合工具类--Collections类的swap()方法直接交换指定位置的内容。
2、用Math类的random()方法和Random类的random()方法有什么区别?


首先,前者是个类,而后者是个方法这就不说了

Random类中实现的随机算法是伪随机,也就是有规则的随机。在进行随机时,随机算法的起源数字称为种子数(seed),在种子数的基础上进行一定的变换,从而产生需要的随机数字。

相同种子数的Random对象,相同次数生成的随机数字是完全相同的。也就是说,两个种子数相同的Random对象,第一次生成的随机数字完全相同,第二次生成的随机数字也完全相同。这点在生成多个随机数字时需要特别注意。

下面介绍一下Random类的使用,以及如何生成指定区间的随机数组以及实现程序中要求的几率。


1、Random对象的生成


         Random类包含两个构造方法,下面依次进行介绍:

         

a、public Random()

该构造方法使用一个当前系统时间对应的相对时间有关的数字作为种子数,然后使用这个种子数构造Random对象。

       

b、public Random(long seed)

该构造方法可以通过制定一个种子数进行创建。

示例代码:

Random r = new Random();

Random r1 = new Random(10);

再次强调:种子数只是随机算法的起源数字,生成的随机数字的区间无关。


2、Random类中的常用方法

Random类中的方法比较简单,每个方法的功能也很容易理解。需要说明的是,Random类中各方法生成的随机数字都是均匀分布的,也就是说区间内部的数字生成的几率是均等的。下面对这些方法做一下基本的介绍:

 

a、public boolean nextBoolean()

方法的作用是生成一个随机的boolean值,生成truefalse的值几率相等,也就是都是50%的几率。

 

b、public double nextDouble()

方法的作用是生成一个随机的double值,数值介于[0,1.0)之间,这里中括号代表包含区间端点,小括号代表不包含区间端点,也就是0到1之间的随机小数,包含0而不包含1.0。

 

c、public int nextInt()

方法的作用是生成一个随机的int值,该值介于int的区间,也就是-231到231-1之间。

如果需要生成指定区间的int值,则需要进行一定的数学变换,具体可以参看下面的使用示例中的代码。

 

d、public int nextInt(int n)

方法的作用是生成一个随机的int值,该值介于[0,n)的区间,也就是0到n之间的随机int值,包含0而不包含n。

如果想生成指定区间的int值,也需要进行一定的数学变换,具体可以参看下面的使用示例中的代码。

 

e、public void setSeed(long seed)

方法的作用是重新设置Random对象中的种子数。设置完种子数以后的Random对象相同种子数使用new关键字创建出的Random对象相同。


3、Random类使用示例

使用Random类,一般是生成指定区间的随机数字,下面就一一介绍如何生成对应区间的随机数字。以下生成随机数的代码均使用以下Random对象r进行生成:

Random r = new Random();

 

a、生成[0,1.0)区间的小数

     double d1 = r.nextDouble();

直接使用nextDouble方法获得。

 

b、生成[0,5.0)区间的小数

double d2 = r.nextDouble() * 5;

因为nextDouble方法生成的数字区间是[0,1.0),将该区间扩大5倍即是要求的区间。

同理,生成[0,d)区间的随机小数,d为任意正的小数,则只需要将nextDouble方法的返回值乘以d即可。

 

c、生成[1,2.5)区间的小数

       double d3 = r.nextDouble() * 1.5 + 1;

生成[1,2.5)区间的随机小数,则只需要首先生成[0,1.5)区间的随机数字,然后将生成的随机数区间加1即可。

同理,生成任意非从0开始的小数区间[d1,d2)范围的随机数字(其中d1不等于0),则只需要首先生成[0,d2-d1)区间的随机数字,然后将生成的随机数字区间加上d1即可。

 

d、生成任意整数

int n1 = r.nextInt();

直接使用nextInt方法即可。

 

e、生成[0,10)区间的整数

int n2 = r.nextInt(10);

n2 = Math.abs(r.nextInt() % 10);

以上两行代码均可生成[0,10)区间的整数。

第一种实现使用Random类中的nextInt(int n)方法直接实现。

第二种实现中,首先调用nextInt()方法生成一个任意的int数字,该数字10取余以后生成的数字区间为(-10,10),因为按照数学上的规定余数的绝对值小于除数,然后再对该区间求绝对值,则得到的区间就是[0,10)了。

同理,生成任意[0,n)区间的随机整数,都可以使用如下代码:

int n2 = r.nextInt(n);

n2 = Math.abs(r.nextInt() % n);

 

f、生成[0,10]区间的整数

int n3 = r.nextInt(11);

n3 = Math.abs(r.nextInt() % 11);

相对于整数区间,[0,10]区间[0,11)区间等价,所以即生成[0,11)区间的整数。

 

g、生成[-3,15)区间的整数

int n4 = r.nextInt(18) - 3;

n4 = Math.abs(r.nextInt() % 18) - 3;

生成非从0开始区间的随机整数,可以参看上面非从0开始的小数区间实现原理的说明。

 

h、几率实现

按照一定的几率实现程序逻辑也是随机处理可以解决的一个问题。下面以一个简单的示例演示如何使用随机数字实现几率的逻辑。

在前面的方法介绍中,nextInt(int n)方法中生成的数字是均匀的,也就是说该区间内部的每个数字生成的几率是相同的。那么如果生成一个[0,100)区间的随机整数,则每个数字生成的几率应该是相同的,而且由于该区间中总计有100个整数,所以每个数字的几率都是1%。按照这个理论,可以实现程序中的几率问题。

示例:随机生成一个整数,该整数以55%的几率生成1,以40%的几率生成2,以5%的几率生成3。实现的代码如下:

int n5 = r.nextInt(100);

int m; //结果数字

if(n5 < 55){ //55个数字的区间,55%的几率

m = 1;

}else if(n5 < 95){//[55,95),40个数字的区间,40%的几率

m = 2;

}else{

m = 3;

}

因为每个数字的几率都是1%,则任意55个数字的区间的几率就是55%,为了代码方便书写,这里使用[0,55)区间的所有整数,后续的原理一样。

当然,这里的代码可以简化,因为几率都是5%的倍数,所以只要以5%为基础来控制几率即可,下面是简化的代码实现:

         int n6 =r.nextInt(20);

         int m1;

         if(n6 < 11){

                     m1 = 1;

             }else if(n6 < 19){

                     m1= 2;

              }else{

                       m1 = 3;

            }

    在程序内部,几率的逻辑就可以按照上面的说明进行实现。


4、其它问题

 

a、相同种子数Random对象问题

前面介绍过,相同种子数的Random对象,相同次数生成的随机数字是完全相同的,下面是测试的代码:

                           Random r1 = new Random(10);

                           Random r2 = new Random(10);

                            for(int i = 0;i < 2;i++){

                                     System.out.println(r1.nextInt());

                                     System.out.println(r2.nextInt());

                            }

在该代码中,对象r1r2使用的种子数都是10,则这两个对象相同次数生成的随机数是完全相同的。

如果想避免出现随机数字相同的情况,则需要注意,无论项目中需要生成多少个随机数字,都只使用一个Random对象即可。

 

b、关于Math类中的random方法

其实在Math类中也有一个random方法,该random方法的工作是生成一个[0,1.0)区间的随机小数。

通过阅读Math类的源代码可以发现,Math类中的random方法就是直接调用Random类中的nextDouble方法实现的。

只是random方法的调用比较简单,所以很多程序员都习惯使用Math类的random方法来生成随机数字。





  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VB6.0实现彩票367程序,功能:生成14个过滤条件值保存DB,查询指定期的前X期开出的个数,七期随机选号法,统计每个号码出球规律,"随机选下注数据,从定号码中遍历组合,在中号码列表中继续筛等。   程序主窗口中的TAB标签项卡实属不错,你可把它用在你的应用程序中。   注:统一起见,下标全部从1用起,0下标不用命名中的Sum这里统一为 个数 的意思,Total一般的数值变量,尽量统一使用Long型,因为Long型的取值范围大,而且速度快一些,只是内存多一点。   1000个数   Quick最快,循环只有500多次   Bucket第二,循环只有999次   过滤操作具体执行过程   一个条件一个条件的全部过滤所有   一次一注号码轮流进行一个条件一个条件的过滤,一次一个条件过滤全部,保留下来的进行下一轮过滤,那容错就几乎无法实现了,如果要实现容错机制的话,应该是一注号码要通过全部过滤条件,然后可利用容错,符合条件和容错就保留下来,鉴于保存所有号码的数组是二维的,那么就直接对保存的二维数组进行各个条件过滤,不可能每次用一个一维数组保存,再用这个一维来过滤。用一个一维数组来记录容错情况,也就是符合多少个条件,比如14个条件,设定了容错率为6,那么只要有8个或以上过滤条件符合,就保留下来。放到一个新的二维数组中奇号个数,0-7   参数:二维数组(),存放一注号码,7个   返回值:奇号的个数,一个Variant数组,里面分别是每注的奇数的个数   UBound(Num, 1) 第一维是注数

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值