如何生成隨機不重複的11位數字

hatch發表於2018-09-06

要求

  • 不重複
  • 隨機
  • 11位數字
  • 不佔儲存

我們都知道11位數字(random)對應有最大值max和最小值min99999999999和10000000000.很簡單的從最小值開始按順序分發到最大值,就滿足了不重複,不佔儲存,11位數字的特性。那麼接下來就要考慮如何生成隨機數字這個特性?

如何隨機

可以考慮將上面分發的11位id數字進行二進位制打亂,就可以生成隨機數字啦。但是呢打亂後的數字長度可能低於11位或者高於11位,那麼如何有心機的進行二進位制打亂才能保證固定11位呢。

11位數字(random) 不小於min

很自然的可以想到id從0到max-min分發再打亂再加上min肯定不會小於min,但是可能會大於max。

id數字特性

random:是要生成的隨機數字 id:是順序分發的數字

min=<random<=max   

min=<min+id<=max  0=<id<=max-min
複製程式碼

11位數字(random) 不大於max

可以先觀察一下max-min對應的二進位制

1010011110100011010110000001111111111

如何進位制順序打亂不超過max-min,對於上面二進位制除高位之外的第一個為1的位之後取最大值,即上述二進位制變為(max_diff):

1001111111111111111111111111111111111

這樣打亂順序前三位保持不變,後面打亂就可以不超過max-min.我這裡是低8位和除去前三位的高八位交換的。

使用率

變化後的二進位制的使用率有:

max_diff/(max-min)=85899345919/89999999999=95.4%

The code

public class ShortChainUtils {

	private static final long MIN = 10000000000L;

	private static final long SUFFIX_ID = ((1L << 34) - 1);

	private static final long PRE_ID = (7L << 34);

	private static final long MAX_ID = 85899345919L;

	public static long next(long id) {

		if (id < 0 || id > MAX_ID) {
			throw new IllegalArgumentException("Illegal id: " + id);
		}

		// 非線性
		id = swap(id, 7, 0);
		id = swap(id, 6, 1);

		// Id後34位
		long value = id & SUFFIX_ID;

		// Id後34位的最低八位和高1-9位交換
		value = (((value >> 8) | ((value & 255) << 26)));

		// Id前3位|Id後34位
		id = (id & PRE_ID) | value;

		// 加上最小值, 保證生成的11位
		id += MIN;

		return id;
	}

	/**
	 * xxxx xxxx xxxx x0xx xxxx xx0x xxxx xxxx|0000 0000 0000 0b00 0000 00a0
	 * 0000 0000
	 */
	private static long swap(long value, int x, int y) {

		return (value & (~(1 << x)) & (~(1 << y))) | (((value >> x) & 1) << y) | (((value >> y) & 1) << x);
	}

	private ShortChainUtils() {
	};

	public static void main(String[] args){
		Set set = new HashSet();
		for(int i=0;; i++) {
			long id = ShortChainUtils.next(i);
			System.out.println(id +"---"+i);
			if(set.contains(id)){
				System.out.println("duplicated");
				break;
			}
			set.add(id);
		}
	}

複製程式碼

不重複id

對於不重複id的分發可以參考:

自增ID的實現

總結

該隨機數字演算法生成簡單,效率高,容易擴充套件(比如你想生成8位,9位可以用類似方法),不用記錄已生成數字去重。

另外還要注意一點的是,要想隨機數字不重複,重點是ID分發不重複。

相關文章