2026/1/1 14:41:54
网站建设
项目流程
dede网站不能运行php文件,wordpress函数调用函数,php做的大型网站,seo关键词排名优化怎么样在《数据结构与算法 II》课程设计中#xff0c;我以 “抽奖机随机号码序列生成” 为主题#xff0c;实现了 3 种经典随机抽样算法#xff0c;并完成了随机性验证。这篇文章会详细分享算法逻辑、代码实现、测试过程及课设收获#xff0c;文末附完整可运行代码。一、需求与算…在《数据结构与算法 II》课程设计中我以 “抽奖机随机号码序列生成” 为主题实现了 3 种经典随机抽样算法并完成了随机性验证。这篇文章会详细分享算法逻辑、代码实现、测试过程及课设收获文末附完整可运行代码。一、需求与算法选型本次课设目标是实现 “从 1~n 中抽取 m 个不重复随机整数”针对不同场景选择了 3 种算法算法适用场景核心优势暴力随机法m 远小于 n如 1~30 抽 5实现最简单洗牌抽样法m 接近 n如 1~10 抽 3无重复生成开销费雪耶茨抽样法n 极大、m 较小如 1~100 抽 5空间复杂度优化至 O (m)二、算法实现与代码解析1. 暴力随机法核心逻辑循环生成随机数遍历已生成号码查重重复则重新生成。cpp运行// 暴力随机法1~maxNum抽winNum个不重复号码 vectorint bruteForceRandom(int minNum, int maxNum, int winNum) { vectorint winNums; if (minNum maxNum || winNum 0 || winNum (maxNum - minNum 1)) { cerr 暴力随机法参数错误 endl; return winNums; } srand((unsigned int)time(NULL)); while (winNums.size() static_castsize_t(winNum)) { int num rand() % (maxNum - minNum 1) minNum; bool isRepeat false; // 暴力查重 for (int n : winNums) { if (n num) { isRepeat true; break; } } if (!isRepeat) winNums.push_back(num); } return winNums; }2. 洗牌抽样法核心逻辑生成完整号码序列→费雪耶茨洗牌→取前 m 个元素。cpp运行// 洗牌函数 void shuffleNumbers(vectorint nums) { srand(time(nullptr)); for (size_t i nums.size() - 1; i 0; i--) { int j rand() % (static_castint(i) 1); swap(nums[i], nums[j]); } } // 洗牌抽样法 vectorint shuffleSampling(int minNum, int maxNum, int winNum) { vectorint nums, result; if (minNum maxNum || winNum 0 || winNum (maxNum - minNum 1)) { cerr 洗牌抽样法参数错误 endl; return result; } // 创建号码池 for (int i minNum; i maxNum; i) nums.push_back(i); shuffleNumbers(nums); // 抽取前winNum个 size_t winNumUnsigned static_castsize_t(winNum); for (size_t i 0; i winNumUnsigned i nums.size(); i) { result.push_back(nums[i]); } return result; }3. 费雪耶茨抽样法核心逻辑初始化 1~m 序列→从 m1 到 n 随机替换前 m 个位置元素。cpp运行// 简单随机数生成 int getRand(int min, int max) { static random_device rd; return min (rd() % (max - min 1)); } // 费雪耶茨抽样法 vectorint fisherYatesSampling(int maxNum, int winNum) { vectorint res; if (winNum 0 || winNum maxNum) { cerr 费雪耶茨抽样法参数错误 endl; return res; } res.resize(static_castsize_t(winNum)); // 初始化1~winNum for (size_t i 0; i static_castsize_t(winNum); i) { res[i] static_castint(i 1); } // 从winNum1到maxNum随机替换 for (int i winNum 1; i maxNum; i) { int j getRand(1, i); if (static_castsize_t(j) static_castsize_t(winNum)) { res[static_castsize_t(j) - 1] i; } } return res; }三、测试类验证算法随机性为了验证算法的公平性设计了LotteryTest测试类支持单轮结果打印和批量随机性统计cpp运行class LotteryTest { private: int testTimes; // 测试轮数 int minNum; // 号码最小值 int maxNum; // 号码最大值 int winNum; // 抽取数量 // 打印单轮结果 void printSingleResult(const vectorint res, const string algoName) { cout 【 algoName 】抽奖结果; if (res.empty()) { cout 无有效结果; } else { for (size_t i 0; i res.size(); i) { cout res[i]; if (i ! res.size() - 1) cout | ; } } cout endl; } // 统计随机性 void statRandomness(vectorint (*algo)(int, int, int), const string algoName) { unordered_mapint, int countMap; int validTest 0; cout \n algoName 随机性测试 testTimes 轮 endl; for (int i minNum; i maxNum; i) countMap[i] 0; for (int t 0; t testTimes; t) { vectorint res algo(minNum, maxNum, winNum); if (res.empty()) continue; validTest; for (int num : res) countMap[num]; } double idealFreq static_castdouble(winNum) / (maxNum - minNum 1); cout 理想频率 fixed setprecision(4) idealFreq 次/轮 endl; cout 实际频率号码次数/轮 | 偏差 endl; for (int i minNum; i maxNum; i) { double actualFreq static_castdouble(countMap[i]) / validTest; cout setw(3) i : fixed setprecision(4) actualFreq | 偏差 abs(actualFreq - idealFreq) endl; } } // 适配费雪耶茨抽样法的统计 void statFisherYates() { unordered_mapint, int countMap; int validTest 0; cout \n 费雪耶茨抽样法 随机性测试 testTimes 轮 endl; for (int i 1; i maxNum; i) countMap[i] 0; for (int t 0; t testTimes; t) { vectorint res fisherYatesSampling(maxNum, winNum); if (res.empty()) continue; validTest; for (int num : res) countMap[num]; } double idealFreq static_castdouble(winNum) / maxNum; cout 理想频率 fixed setprecision(4) idealFreq 次/轮 endl; cout 实际频率号码次数/轮 | 偏差 endl; for (int i 1; i maxNum; i) { double actualFreq static_castdouble(countMap[i]) / validTest; cout setw(3) i : fixed setprecision(4) actualFreq | 偏差 abs(actualFreq - idealFreq) endl; } } public: LotteryTest(int tTimes, int minN, int maxN, int winN) : testTimes(tTimes), minNum(minN), maxNum(maxN), winNum(winN) {} // 单轮测试 void singleTest() { cout endl; cout 单轮抽奖测试结果 endl; cout endl; vectorint res1 bruteForceRandom(minNum, maxNum, winNum); printSingleResult(res1, 暴力随机法); vectorint res2 shuffleSampling(minNum, maxNum, winNum); printSingleResult(res2, 洗牌抽样法); vectorint res3 fisherYatesSampling(maxNum, winNum); printSingleResult(res3, 费雪耶茨抽样法); } // 批量随机性测试 void batchRandomTest() { cout \n endl; cout 随机性测试结果 endl; cout endl; statRandomness(bruteForceRandom, 暴力随机法); statRandomness(shuffleSampling, 洗牌抽样法); statFisherYates(); } };四、运行结果与分析1. 单轮测试结果plaintext 单轮抽奖测试结果 【暴力随机法】抽奖结果8 | 3 | 9 【洗牌抽样法】抽奖结果7 | 3 | 9 【费雪耶茨抽样法】抽奖结果6 | 2 | 82. 批量随机性测试10000 轮以暴力随机法为例各号码实际频率与理想频率0.3偏差均小于 0.002说明算法随机性均匀plaintext 暴力随机法 随机性测试10000轮 理想频率0.3000次/轮 实际频率号码次数/轮 | 偏差 1: 0.2987 | 偏差0.0013 2: 0.3012 | 偏差0.0012 ...