c++中如何实现数组的洗牌算法_c++ std::shuffle随机打乱数组【实例】

发布时间 - 2026-01-21 00:00:00    点击率:
std::shuffle必须传UniformRandomBitGenerator引擎(如mt19937)而不能用rand(),因接口不匹配且C++11起弃用;仅支持RandomAccessIterator(如vector、数组),不支持list/map;C++17移除了random_shuffle,迁移需显式提供引擎。

std::shuffle 为什么必须传随机数引擎,不能只用 rand()

因为

std::shuffle 要求一个符合 UniformRandomBitGenerator 概念的随机数引擎(如 std::mt19937),而 rand() 是 C 风格全局函数,不满足接口要求,直接传会编译失败:error: no matching function for call to 'shuffle'。C++11 起已明确弃用 rand() 配合 STL 算法的用法。

实操建议:

  • std::random_device 初始化种子,再构造 std::mt19937 引擎(比 time(0) 更可靠)
  • 避免重复创建引擎——它有状态,应在洗牌前初始化一次,多次调用 shuffle 复用同一个实例
  • 若需可重现结果(如测试),可传固定种子,例如 std::mt19937{42}

std::shuffle 的迭代器范围必须是 RandomAccessIterator

std::shuffle 内部依赖随机访问(比如计算 last - first、用下标交换),所以不能用于 std::liststd::forward_list;对 std::vector、原生数组、std::array 完全适用。

常见错误现象:

  • std::list::begin()end() → 编译报错:no match for ‘operator-’
  • 误用 std::shufflestd::map 键值对洗牌 → 无效(map 迭代器非随机访问,且其顺序由 key 决定,不可“打乱”)

正确写法示例(原生数组):

int arr[] = {1, 2, 3, 4, 5};
std::mt19937 g{std::random_device{}()};
std::shuffle(std::begin(arr), std::end(arr), g);

std::shuffle 与 std::random_shuffle 的区别和迁移要点

std::random_shuffle 在 C++17 中被移除,它曾接受 rand 函数指针或简单随机数生成器,但设计上不安全、不可控、难以测试。迁移到 std::shuffle 时注意:

  • 必须显式提供随机数引擎,不能再省略第三个参数
  • 旧代码 std::random_shuffle(v.begin(), v.end()) 会编译失败,必须补上引擎
  • std::shuffle 是 Fisher–Yates(Knuth)算法的实现,时间复杂度 O(n),无偏 —— 和 random_shuffle 一致,但更可靠

典型迁移写法:

std::vector v = {10, 20, 30, 40, 50};
std::mt19937 gen{std::random_device{}()}; // 替代原来的 rand()
std::shuffle(v.begin(), v.end(), gen);    // 不再支持无引擎调用

洗牌后验证是否真随机?别靠肉眼,用分布统计

新手常以为输出看起来“乱”就对了,但实际可能因种子/引擎误用导致周期性或退化(比如所有运行都得到同一序列)。真正检验需统计位置分布或使用卡方检验。

快速自查建议:

  • 运行 1000 次洗牌,记录每个元素出现在索引 0 的次数 —— 应接近 200(若数组长 5)
  • 避免用 std::random_device 在某些平台(如 MinGW)返回恒定值,可加判空:if (rd.entropy() == 0) /* fallback */
  • 调试时临时用固定种子(如 mt19937{1}),确保行为可复现;上线再换真实种子

容易被忽略的是:洗牌算法本身没问题,但引擎生命周期管理出错(比如在循环里反复构造新引擎并用相同种子),会导致每次洗牌结果完全一样。


# access  # mac  # c++  # 区别  # 键值对  # 为什么  # Array  # if  # for  # Error  # 循环  # 指针  # 接口  # operator  # map  # function  # 算法  # 随机数  # 移除  # 的是  # 迭代  # 出现在  # 而不  # 不支持  # 应在  # 报错  # 第三个 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何用低价快速搭建高质量网站?  Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】  Python数据仓库与ETL构建实战_Airflow调度流程详解  Mybatis 中的insertOrUpdate操作  如何快速重置建站主机并恢复默认配置?  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  智能起名网站制作软件有哪些,制作logo的软件?  宙斯浏览器视频悬浮窗怎么开启 边看视频边操作其他应用教程  如何快速搭建安全的FTP站点?  进行网站优化必须要坚持的四大原则  java中使用zxing批量生成二维码立牌  手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?  如何在腾讯云服务器快速搭建个人网站?  Android仿QQ列表左滑删除操作  iOS正则表达式验证手机号、邮箱、身份证号等  HTML5段落标签p和br怎么选_文本排版常用标签对比【解答】  北京专业网站制作设计师招聘,北京白云观官方网站?  如何在 Go 中优雅地映射具有动态字段的 JSON 对象到结构体  HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】  Python函数文档自动校验_规范解析【教程】  免费视频制作网站,更新又快又好的免费电影网站?  深圳网站制作平台,深圳市做网站好的公司有哪些?  简单实现jsp分页  如何在IIS中新建站点并配置端口与IP地址?  Laravel全局作用域是什么_Laravel Eloquent Global Scopes应用指南  如何在阿里云高效完成企业建站全流程?  laravel怎么在请求结束后执行任务(Terminable Middleware)_laravel Terminable Middleware请求结束任务执行方法  如何挑选优质建站一级代理提升网站排名?  Laravel如何生成URL和重定向?(路由助手函数)  如何在局域网内绑定自建网站域名?  如何用西部建站助手快速创建专业网站?  Laravel如何编写单元测试和功能测试?(PHPUnit示例)  制作企业网站建设方案,怎样建设一个公司网站?  PHP 500报错的快速解决方法  网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?  Laravel storage目录权限问题_Laravel文件写入权限设置  魔毅自助建站系统:模板定制与SEO优化一键生成指南  如何获取PHP WAP自助建站系统源码?  香港服务器网站搭建教程-电商部署、配置优化与安全稳定指南  Laravel Facade的原理是什么_深入理解Laravel门面及其工作机制  LinuxShell函数封装方法_脚本复用设计思路【教程】  微信小程序 闭包写法详细介绍  网站制作价目表怎么做,珍爱网婚介费用多少?  如何在腾讯云免费申请建站?  香港服务器网站推广:SEO优化与外贸独立站搭建策略  Laravel Session怎么存储_Laravel Session驱动配置详解  Midjourney怎么调整光影效果_Midjourney光影调整方法【指南】  uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址  Laravel如何实现数据库事务?(DB Facade示例)  Laravel如何使用Guzzle调用外部接口_Laravel发起HTTP请求与JSON数据解析【详解】