Java用n种方法编写实现双色球随机摇号案例


之前我用JavaScript编写过一个实现双色球随机摇号的案例, 点击此处查看,今天我再用Java语言来实现这一效果。

规则

那么首先我们要搞清楚规则是什么:

双色球投注区分为红球号码区和蓝球号码区
红球号码范围为01~33,蓝球号码范围为01~16
双色球每期从33个红球中开出6个号码,从16个蓝球中开出1个号码作为中奖号码
双色球玩法即是竞猜开奖号码的6个红球号码和1个蓝球号码,顺序不限

简单来说,就是通过随机,红球就是在1~33中随机出来6个互不相同的数字,蓝球则是产生一个1 ~16之间的数字。那么难点当然在于红球,如何确保不重复呢?

实现方式一

当然是用集合了,因为集合的性质就在于,里面的元素互不重复。接下来我们就用集合来实现:

package day_11_25;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

/**
 * 双色球
 * 红球1~33  篮球1~16
 *
 * @author soberw
 */
public class DoubleBall2 {
    public static void main(String[] args) {
        Random random = new Random();
        Set<Integer> red = new HashSet<Integer>();
        do {
            red.add(random.nextInt(33) + 1);
        } while (red.size() != 6);
        System.out.print("{ ");
        red.forEach((value) -> {
            System.out.printf("[%02d] ", value);
        });
        System.out.print("}");
        System.out.printf("{ [%02d] }", random.nextInt(16) + 1);
    }
}

运行结果:
在这里插入图片描述

实现方式二

那么如果不用集合而用数组呢?我们都知道Java的数组比较死板,就是一旦定义,就不能再更改长度,而且在声明的时候一定要指定长度或者初始化值。那么如果想用数组实现呢,代码如下:

package day_11_25;

import java.util.Random;

/**
 * 双色球
 * 红球1~33  篮球1~16
 *
 * @author soberw
 */
public class DoubleBall3 {
    public static void main(String[] args) {
        Random random = new Random();
        //放红球
        int[] red = new int[6];
        for (int i = 0; i < red.length; i++) {
            boolean flag = true;
            int redRAn = random.nextInt(33) + 1;
            while (flag) {
                for (int j = 0; j < red.length; j++) {
                    if (red[j] == redRAn) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    red[i] = redRAn;
                    break;
                }
            }
        }
        System.out.print("{ ");
        for (int i : red) {
            System.out.printf("[%02d] ", i);
        }
        System.out.print("}");
        System.out.printf("{ [%02d] }", random.nextInt(16) + 1);
    }
}

运行结果:
在这里插入图片描述

实现方式三

其实用数组的实现方式有很多,上面这种采用了三重循环嵌套,如果逻辑性不强,很难理解为什么这样子写,下面分享另一种写法,相比于上一种写法,这种的思路是创建一个基数数组base存放1~33所有的号码球,每次随机抽取出一个,然后将base 中对应号码球的赋值为0,每次抽取的时候都会先判断是不是为0,如果是0就说明已经被抽走了,那么就继续随机,直到不再重复为止。确保不会重复:

package day_11_25;

import java.util.Random;

/**
 * 双色球
 * 红球1~33  篮球1~16
 *
 * @author soberw
 */
public class DoubleBall {
    public static void main(String[] args) {
        Random ran = new Random();
        //基数组,从这里抽数放入red
        int[] base = new int[33];
        //存放红球
        int[] red = new int[6];
        int ranIndex;
        //给base元素依次赋值1~33
        for (int i = 1; i <= base.length; i++) {
            base[i - 1] = i;
        }

        for (int i = 0; i < red.length; i++) {
            while (true) {
                //随机base的下标
                ranIndex = ran.nextInt(33);
                //判断是不是被抽走了,被抽走了就继续随机,没有的话就放入red,并将base中对应的赋值为0
                if (0 != base[ranIndex]) {
                    red[i] = base[ranIndex];
                    base[ranIndex] = 0;
                    break;
                }
            }
        },
        System.out.print("{ ");
        for (int i : red) {
            System.out.printf("[%02d] ", i);
        }
        System.out.print("}");
        System.out.printf("{ [%02d] }", ran.nextInt(16) + 1);

    }
}

运行结果:
在这里插入图片描述

实现方式四

当然我们也可以借助数组工具类Arrays中的二分查找方法 binarySearch()来判断是否已经存在,但是前提是必须在查找前先排序,因为二分查找的前提就是要确保数组是有序的:

package day_11_25;

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

/**
 * 双色球
 * 红球1~33  篮球1~16
 *
 * @author soberw
 */
public class DoubleBall4 {
    public static void main(String[] args) {
        Random random = new Random();
        //放红球
        int[] red = new int[6];
        Arrays.fill(red,33);
        //存放号码球
        int ranRed;
        for (int i = 0; i < red.length; i++) {
            boolean flag = true;
            //确保数组有序
            Arrays.sort(red);
            while (flag) {
                ranRed = random.nextInt(33) + 1;
                //判断数组中是否存在此元素
                if (Arrays.binarySearch(red, ranRed) < 0) {
                    flag = false;
                    red[i] = ranRed;
                }
            }
        }
        System.out.print("{ ");
        for (int i : red) {
            System.out.printf("[%02d] ", i);
        }
        System.out.print("}");
        System.out.printf("{ [%02d] }", random.nextInt(16) + 1);
    }
}

运行结果:
在这里插入图片描述

这里需要注意一点,Arrays.binarySearch()方法如果找不到元素,返回的不是-1,而是一个小于0的数,这个数是多少呢,查看API手册得知:
在这里插入图片描述
我在使用的时候就栽过坑,让其等-1,结果陷入死循环。。。

实现方法五

那么上一个方法存在的问题就是,每次判断之前我还要对数组进行排序,虽然这是内置的算法不用我们自己在写了,但是总感觉还是有待优化一下。于是,就有了第五种方法:)
使用Vector类完成,它的优势在于,它是动态的,可以动态添加数据,最主要的是,它内置了超级多的方法,相比于原始数组的死板,实在是强大许多:

package day_11_25;

import java.util.Random;
import java.util.Vector;

/**
 * 双色球
 * 红球1~33  篮球1~16
 *
 * @author soberw
 */
public class DoubleBall5 {
    public static void main(String[] args) {
        Random random = new Random();
        //声明一个空数组用于存放红球
        Vector<Integer> red = new Vector<Integer>();
        //超出六个退出
        while (red.size() < 6) {
            int ranRed = random.nextInt(33) + 1;
            //如果不存在则添加
            if (!red.contains(ranRed)) {
                red.add(ranRed);
            }
        }
        System.out.print("{ ");
        for (int i : red) {
            System.out.printf("[%02d] ", i);
        }
        System.out.print("}");
        System.out.printf("{ [%02d] }", random.nextInt(16) + 1);
    }
}

运行结果:
在这里插入图片描述
这是我目前想到的五种方式,那么你觉得那种好用呢?
或者你有更好的方法,欢迎评论区补充,大家一起探讨一起学习!

posted @ 2022-02-09 19:45  soberw-  阅读(1130)  评论(0编辑  收藏  举报