序
突然腦袋發熱的一個設想,如果是想單純生成不重複隨機數的,請出門左轉有個更好的算法(用數組下標位隨機,隨機到的下標位對應數據扔到最後位置),什麼?你要生成的隨機數範圍很大,浪費空間?來來來,坐下喝茶。
基本思路:
定義一個位長度大於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%左右
該想法的調參還有更多可能性,有興趣或有更好方案的小夥伴歡迎交流~