package com.zhengyuxiao.toolbox.random;
import java.util.*;
/**
* @author xzy
* @date 2020-12-24 11:55
* 說明:隨機工具
*/
public class RandomUtils {
private RandomUtils() {
}
/**
* 帶權重的隨機決策——基於線性掃描
* 注意:
* 1. 時間復雜度O(n),n = prizePool.length
* 2. 將權重大的數據靠前,可以減少列表遍歷的次數
*
* @param prizePool - “獎品池”,即需要決策的數據
* @param weightPool - “獎品權重”,即數據所占的權重(決定數據被選中的概率)
* @param <E> - 數據類型
* @return - 隨機抽中的“獎品”
*/
public static <E> E randomDecisionWithWeight(E[] prizePool, int[] weightPool) {
if (prizePool.length == 0 || prizePool.length != weightPool.length) {
throw new IllegalArgumentException();
}
/*
* 獎品池、獎品權重:
*
* A B C D
* |-----|-------|---------------|-------------------------------|
* 1/15 2/15 4/15 8/15
*
* 生成一個[0,15)區間內的隨機數x,根據x所處的子區間決定抽取到的獎品:
* x
* |----------------------------------|
*/
// 計算總權重,確定隨機數生成范圍
int weightSum = 0;
for (int weight : weightPool) {
if (weight < 0) {
throw new IllegalArgumentException("權重不允許是負數!");
}
weightSum += weight;
}
// 抽取數據
int randomPrizePoint = new Random().nextInt(weightSum);
E randomPrize = null;
for (int i = 0; i < weightPool.length; i++) {
if (randomPrizePoint < weightPool[i]) {
randomPrize = prizePool[i];
break;
} else {
randomPrizePoint -= weightPool[i];
}
}
return randomPrize;
}
public static void main(String[] args) {
String[] prizePool = new String[]{"一等獎", "二等獎", "三等獎", "鼓勵獎"};
int[] prizeWeight = new int[]{1, 2, 4, 8};
Map<String, Integer> count = new HashMap<>(4);
for (int i = 0; i < 1000; i++) {
String randomPrize = randomDecisionWithWeight(prizePool, prizeWeight);
count.put(randomPrize, count.getOrDefault(randomPrize, 0) + 1);
System.out.println(randomPrize);
}
System.out.println("統計:" + count);
}
}
package com.zhengyuxiao.toolbox.random;
import java.nio.charset.Charset;
import java.util.Random;
/**
* 漢字工具
*
* @author xzy
* @date 2021/10/2113:49
*/
public class ChineseUtil {
/**
* 中華姓氏(按照使用人數由多到少排序)
*/
public static final String[] LAST_NAME = new String[]{
"趙", "錢", "孫", "李", "周", "吳", "鄭", "王", "馮", "陳", "褚", "衛", "蔣", "沈", "韓", "楊", "朱", "秦", "尤",
"許", "何", "呂", "施", "張", "孔", "曹", "嚴", "華", "金", "魏", "陶", "姜", "戚", "謝", "鄒", "喻", "柏", "水",
"竇", "章", "雲", "蘇", "潘", "葛", "奚", "范", "彭", "郎", "魯", "韋", "昌", "馬", "苗", "鳳", "花", "方", "俞",
"任", "袁", "柳", "酆", "鮑", "史", "唐", "費", "廉", "岑", "薛", "雷", "賀", "倪", "湯", "滕", "殷", "羅", "畢",
"郝", "鄔", "安", "常", "於", "時", "傅", "皮", "卞", "齊", "康", "伍", "余", "元", "卜", "顧", "孟", "平", "黃",
"和", "穆", "蕭", "尹", "姚", "邵", "湛", "汪", "祁", "毛", "禹", "狄", "米", "貝", "明", "臧", "計", "伏", "成",
"戴", "談", "宋", "茅", "龐", "熊", "紀", "舒", "屈", "項", "祝", "董", "梁", "杜", "阮", "藍", "閔", "席", "季",
"麻", "強", "賈", "路", "婁", "危", "江", "童", "顏", "郭", "梅", "盛", "林", "***", "鍾", "徐", "邱", "駱", "高",
"夏", "蔡", "田", "樊", "胡", "凌", "霍", "虞", "萬", "支", "柯", "昝", "管", "盧", "莫", "經", "房", "裘", "繆",
"干", "解", "應", "宗", "丁", "宣", "賁", "鄧", "郁", "單", "杭", "洪", "包", "諸", "左", "石", "崔", "吉", "鈕",
"龔", "程", "嵇", "邢", "滑", "裴", "陸", "榮", "翁", "荀", "羊", "於", "惠", "甄", "曲", "家", "封", "芮", "羿",
"儲", "靳", "汲", "邴", "糜", "松", "井", "段", "富", "巫", "烏", "焦", "巴", "弓", "牧", "隗", "山", "谷", "車",
"侯", "宓", "蓬", "全", "郗", "班", "仰", "秋", "仲", "伊", "宮", "寧", "仇", "欒", "暴", "甘", "鈄", "厲", "戎",
"祖", "武", "符", "劉", "景", "詹", "束", "龍", "葉", "幸", "司", "韶", "郜", "黎", "薊", "薄", "印", "宿", "白",
"懷", "蒲", "台", "從", "鄂", "索", "咸", "籍", "賴", "卓", "藺", "屠", "蒙", "池", "喬", "陰", "欎", "胥", "能",
"蒼", "雙", "聞", "莘", "黨", "翟", "譚", "貢", "勞", "逄", "姬", "申", "扶", "堵", "冉", "宰", "酈", "雍", "郤",
"璩", "桑", "桂", "濮", "牛", "壽", "通", "邊", "扈", "燕", "冀", "郟", "浦", "尚", "農", "溫", "別", "庄", "晏",
"柴", "瞿", "閻", "充", "慕", "連", "茹", "習", "宦", "艾", "魚", "容", "向", "古", "易", "慎", "戈", "廖", "庾",
"終", "暨", "居", "衡", "步", "都", "耿", "滿", "弘", "匡", "國", "文", "寇", "廣", "祿", "闕", "東", "毆", "殳",
"沃", "利", "蔚", "越", "夔", "隆", "師", "鞏", "厙", "聶", "晁", "勾", "敖", "融", "冷", "訾", "辛", "闞", "那",
"簡", "饒", "空", "曾", "毋", "沙", "乜", "養", "鞠", "須", "豐", "巢", "關", "蒯", "相", "查", "后", "荊", "紅",
"游", "竺", "權", "逯", "蓋", "益", "桓", "公", "萬俟", "司馬", "上官", "歐陽", "夏侯", "諸葛", "聞人", "東方", "赫連",
"皇甫", "尉遲", "公羊", "澹台", "公冶", "宗政", "濮陽", "淳於", "單於", "太叔", "申屠", "公孫", "仲孫", "軒轅", "令狐",
"鍾離", "宇文", "長孫", "慕容", "鮮於", "閭丘", "司徒", "司空", "亓官", "司寇", "仉", "督", "子車", "顓孫", "端木", "巫馬",
"公西", "漆雕", "樂正", "壤駟", "公良", "拓跋", "夾谷", "宰父", "谷梁", "晉", "楚", "閆", "法", "汝", "鄢", "塗", "欽",
"段干", "百里", "東郭", "南", "門", "呼延", "歸海", "羊舌", "微生", "岳", "帥", "緱", "亢", "況", "郈", "有", "琴", "梁丘",
"左丘", "東門", "西門", "商", "牟", "佘", "佴", "伯", "賞", "南宮", "墨", "哈", "譙", "笪", "年", "愛", "陽", "佟", "第五",
"言", "福", "百", "姓"
};
/**
* 各姓氏的權重(數值越大表明使用頻率越高)
* A B C D E F
* |--------------------|---------------|----------|-----|---|-|
*/
public static final int[] LAST_NAME_WEIGHTS = new int[]{
505, 504, 503, 502, 501, 500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 490, 489, 488, 487, 486, 485,
484, 483, 482, 481, 480, 479, 478, 477, 476, 475, 474, 473, 472, 471, 470, 469, 468, 467, 466, 465, 464,
463, 462, 461, 460, 459, 458, 457, 456, 455, 454, 453, 452, 451, 450, 449, 448, 447, 446, 445, 444, 443,
442, 441, 440, 439, 438, 437, 436, 435, 434, 433, 432, 431, 430, 429, 428, 427, 426, 425, 424, 423, 422,
421, 420, 419, 418, 417, 416, 415, 414, 413, 412, 411, 410, 409, 408, 407, 406, 405, 404, 403, 402, 401,
400, 399, 398, 397, 396, 395, 394, 393, 392, 391, 390, 389, 388, 387, 386, 385, 384, 383, 382, 381, 380,
379, 378, 377, 376, 375, 374, 373, 372, 371, 370, 369, 368, 367, 366, 365, 364, 363, 362, 361, 360, 359,
358, 357, 356, 355, 354, 353, 352, 351, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 338,
337, 336, 335, 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, 324, 323, 322, 321, 320, 319, 318, 317,
316, 315, 314, 313, 312, 311, 310, 309, 308, 307, 306, 305, 304, 303, 302, 301, 300, 299, 298, 297, 296,
295, 294, 293, 292, 291, 290, 289, 288, 287, 286, 285, 284, 283, 282, 281, 280, 279, 278, 277, 276, 275,
274, 273, 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260, 259, 258, 257, 256, 255, 254,
253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, 233,
232, 231, 230, 229, 228, 227, 226, 225, 224, 223, 222, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212,
211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, 192, 191,
190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170,
169, 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149,
148, 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 128,
127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107,
106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82,
81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55,
54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28,
27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
};
/**
* 獲取隨機生成的漢字
*
* @return - 隨機生成的漢字
*/
public static String getRandomChineseChar() {
/*
* 漢字以兩個字節存儲,稱為“區位碼”,高位叫區碼,低位叫位碼。假設有一張漢字表,橫豎都是 94列,那么區碼就相當於行,位碼就相當於列,根據行列就可
* 以確定一個漢字了,這有點像二位數組。GB2312大致就是按照這種方式實現的,1-9區存放特殊字符,16-55區存放一級漢字,56-87區存放二級漢字,其余
* 暫時空余。為了區別中文與西文字母,在中文字符首位以1開頭區分以0開頭的ASCII碼,GB2312給每個中文字符加上0xA0。
*
* 因此,漢字的區碼范圍0xB0-0xF7,位碼范圍0xA0-0xFE。
*/
// 隨機生成區碼、位碼
Random random = new Random();
int highPos = (176 + Math.abs(random.nextInt(39)));
int lowPos = (161 + Math.abs(random.nextInt(93)));
// 准備字節碼
byte[] b = new byte[2];
b[0] = (Integer.valueOf(highPos)).byteValue();
b[1] = (Integer.valueOf(lowPos)).byteValue();
// 生成漢字
return new String(b, Charset.forName("GBK"));
}
/**
* 獲取隨機生成的中國姓氏
*
* @param absolutelyFair true:絕對公平 false:使用頻率高的姓氏抽取的概率高
* @return - 隨機生成的中國姓氏
*/
public static String getRandomChineseLastName(boolean absolutelyFair) {
if (absolutelyFair) {
// 完全隨機
return LAST_NAME[new Random().nextInt(LAST_NAME.length - 1)];
} else {
// 基於權重的隨機:使用頻率高的姓氏被抽中的概率高
return RandomUtils.randomDecisionWithWeight(LAST_NAME, LAST_NAME_WEIGHTS);
}
}
/**
* 獲取隨機生成的中文姓名
*
* @return - 隨機生成的中文姓名
*/
public static String getRandomChineseName() {
// 隨機選取姓氏
String lastName = getRandomChineseLastName(false);
// 隨機生成名字(控制8/10的人名字長度為2)
int firstNameLength = new Random().nextInt(10);
String firstName = firstNameLength < 8 ? getRandomChineseChar() + getRandomChineseChar() : getRandomChineseChar();
// 返回姓名:姓氏 + 名字
return lastName + firstName;
}
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
System.out.println(getRandomChineseName());
}
}
}
待優化:沒有根據不同姓氏的實際使用頻率設置權重