写点什么

随机数环设想

发布于: 2021 年 03 月 31 日

突然脑袋发热的一个设想,如果是想单纯生成不重复随机数的,请出门左转有个更好的算法(用数组下标位随机,随机到的下标位对应数据扔到最后位置),什么?你要生成的随机数范围很大,浪费空间?来来来,坐下喝茶。基本思路:定义一个位长度大于 bitNum 的数组位环(使用位运算)每次取的随机数要先去数组对应下标位中判断下标位的数是否为 0,若为 0 则直接返回 并把这个位置置 1,如果是 1,则寻找 1 前面的那个位,如果找了一定的数量 destoryLen 都是 1 那么将该随机数返回,环终结个数+1,数组元素全部置 0,将新数组该随机下标位 置 1。


代码实现:


import java.util.concurrent.ThreadLocalRandom;
/** * Created by Kowalski on 2017/1/22. * */public class RandomIdWorker {
/**位运算数组*/ private static final int[] arr_32 = { 0x80000000,0x40000000,0x20000000,0x10000000, 0x08000000,0x04000000,0x02000000,0x01000000, 0x00800000,0x00400000,0x00200000,0x00100000, 0x00080000,0x00040000,0x00020000,0x00010000, 0x00008000,0x00004000,0x00002000,0x00001000, 0x00000800,0x00000400,0x00000200,0x00000100, 0x00000080,0x00000040,0x00000020,0x00000010, 0x00000008,0x00000004,0x00000002,0x00000001, }; /**随机数最大值*/ private static int bitNum; /**随机数长度*/ private static int circleLenNum; /**当前圈数*/ private static int circleNum; /**圈最大值*/ private static int maxCircleNum; /**摧毁圈长度*/ private static int destoryLen; /**环数组*/ private static int[] arr; /**随机数*/ private static ThreadLocalRandom random = ThreadLocalRandom.current();
public static void init(int bitNum, int maxCircleNum, int destoryLen) {
if(destoryLen > bitNum) { throw new IllegalArgumentException("destoryLen can not big than bitNum"); } else { /**初始化数组*/ arr = new int[bitNum / 32 + 1]; /**初始化参数*/ RandomIdWorker.bitNum = bitNum; RandomIdWorker.maxCircleNum = maxCircleNum; RandomIdWorker.destoryLen = destoryLen;
for(circleLenNum = 10; bitNum / 10 != 0; bitNum /= 10) { circleLenNum *= 10; }
} }
public static void main(String... args){
init(9999, 9999, 100);
int res = 0; long time = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { res = generate(); } System.out.println(System.currentTimeMillis() - time); System.out.println(res); System.out.println("圈数:" + circleNum); }
public static synchronized int generate(){
/**取随机数*/ int ran = random.nextInt(bitNum); /**核心代码*/ int i; for(i = 0; i < destoryLen; ++i) { if ((arr[ran / 32] & arr_32[ran % 32]) == 0) {
arr[ran / 32] |= arr_32[ran % 32];
return circleLenNum*circleNum + ran; } /**数已存在就取下一个*/ ran = (ran + 1) % bitNum; } /**到达最大圈数 从头开始*/ if(circleNum == maxCircleNum){ circleNum = 0;
}else { ++circleNum; } /**清空数组*/ for (i = 0; i < bitNum / 32 + 1; ++i) { arr[i] = 0; } /**将新数组中ran位设成1*/ arr[ran / 32] |= arr_32[ran % 32];
return circleLenNum*circleNum + ran; }
}
复制代码


备注:1.代码中 main 方法跑的是随机数最大 9999,最大圈数 9999,连续 100 个 1 出现则环终结的示例 2.该示例在本人电脑中跑,生成 10000000 个最大值为 99999999 的不重复随机数大概需要 1s 左右的时间,期中共消耗了约 1272 个环,环的平均利用率在 80%左右


该想法的调参还有更多可能性,有兴趣或有更好方案的小伙伴欢迎交流~

发布于: 2021 年 03 月 31 日阅读数: 10
用户头像

还未添加个人签名 2020.03.30 加入

还未添加个人简介

评论

发布
暂无评论
随机数环设想