• C++11标准模板(STL)- 算法(std::random_shuffle, std::shuffle)


    定义于头文件 

    算法库提供大量用途的函数(例如查找、排序、计数、操作),它们在元素范围上操作。注意范围定义为 [first, last) ,其中 last 指代要查询或修改的最后元素的后一个元素。


    随机重排范围中的元素

    1. std::random_shuffle,
    2. std::shuffle

    template< class RandomIt >
    void random_shuffle( RandomIt first, RandomIt last );

    (1)(C++14 中弃用)
    (C++17 中移除)

    template< class RandomIt, class RandomFunc >
    void random_shuffle( RandomIt first, RandomIt last, RandomFunc& r );

    (2)(C++11 前)

    template< class RandomIt, class RandomFunc >
    void random_shuffle( RandomIt first, RandomIt last, RandomFunc&& r );

    (C++11 起)
    (C++14 中弃用)
    (C++17 中移除)

    template< class RandomIt, class URBG >
    void shuffle( RandomIt first, RandomIt last, URBG&& g );

    (3)(C++11 起)

    重排序给定范围 [first, last) 中的元素,使得这些元素的每个排列拥有相等的出现概率。

    1) 随机数生成器是实现定义的,但经常使用函数 std::rand 。

    2) 随机数生成器为函数对象 r

    3) 随机数生成器为函数对象 g

    参数

    first, last-要随机打乱的元素范围
    r-函数对象。若以 r(n) 调用,则返回可转换为 std::iterator_traits::difference_type 的在区间 [0,n) 中随机选取的值
    g-均匀随机位生成器 (UniformRandomBitGenerator) ,其结果类型可隐式转换为 std::iterator_traits::difference_type
    类型要求
    - RandomIt 必须满足值可交换 (ValueSwappable) 和 遗留随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
    - std::remove_reference_t 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

    返回值

    (无)

    复杂度

    firstlast 间的距离成线性。

    注意

    标准未钦定实现,故即使你用准确相同的 RandomFuncURBG ,也可能通过不同的标准库实现得到不同结果。

    可能的实现

    版本一

    1. template< class RandomIt >
    2. void random_shuffle( RandomIt first, RandomIt last )
    3. {
    4. typename std::iterator_traits<RandomIt>::difference_type i, n;
    5. n = last - first;
    6. for (i = n-1; i > 0; --i) {
    7. using std::swap;
    8. swap(first[i], first[std::rand() % (i+1)]);
    9. // rand() % (i+1) 实际上不准确,因为生成的数对于多数 i 值不均匀分布。
    10. // 正确实现将实际上需要重新实现 C++11 std::uniform_distributtion ,
    11. // 这超出了此示例的范畴。
    12. }
    13. }

    版本二

    1. template<class RandomIt, class RandomFunc>
    2. void random_shuffle(RandomIt first, RandomIt last, RandomFunc&& r)
    3. {
    4. typename std::iterator_traits<RandomIt>::difference_type i, n;
    5. n = last - first;
    6. for (i = n-1; i > 0; --i) {
    7. using std::swap;
    8. swap(first[i], first[r(i+1)]);
    9. }
    10. }

    版本三

    1. template<class RandomIt, class URBG>
    2. void shuffle(RandomIt first, RandomIt last, URBG&& g)
    3. {
    4. typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
    5. typedef std::uniform_int_distribution<diff_t> distr_t;
    6. typedef typename distr_t::param_type param_t;
    7. distr_t D;
    8. diff_t n = last - first;
    9. for (diff_t i = n-1; i > 0; --i) {
    10. using std::swap;
    11. swap(first[i], first[D(g, param_t(0, i))]);
    12. }
    13. }

    调用示例

    1. #include <iostream>
    2. #include <algorithm>
    3. #include <functional>
    4. #include <vector>
    5. #include <iterator>
    6. using namespace std;
    7. struct Cell
    8. {
    9. int x;
    10. int y;
    11. Cell &operator +=(const Cell &cell)
    12. {
    13. x += cell.x;
    14. y += cell.y;
    15. return *this;
    16. }
    17. };
    18. std::ostream &operator<<(std::ostream &os, const Cell &cell)
    19. {
    20. os << "{" << cell.x << "," << cell.y << "}";
    21. return os;
    22. }
    23. int main()
    24. {
    25. auto func1 = [](Cell & cell, const Cell & t)
    26. {
    27. cell += t;
    28. return cell;
    29. };
    30. Cell cell{99, 100};
    31. Cell t{2, 3};
    32. auto func2 = std::bind(func1, cell, t);
    33. vector<Cell> cells(8);
    34. std::generate(cells.begin(), cells.end(), func2);
    35. std::cout << "original : ";
    36. std::copy(cells.begin(), cells.end(), std::ostream_iterator<Cell>(std::cout, " "));
    37. std::cout << std::endl;
    38. std::random_shuffle(cells.begin(), cells.end());
    39. std::cout << "random_shuffle : ";
    40. std::copy(cells.begin(), cells.end(), std::ostream_iterator<Cell>(std::cout, " "));
    41. std::cout << std::endl;
    42. std::cout << std::endl;
    43. std::generate(cells.begin(), cells.end(), func2);
    44. std::cout << "original : ";
    45. std::copy(cells.begin(), cells.end(), std::ostream_iterator<Cell>(std::cout, " "));
    46. std::cout << std::endl;
    47. auto func3 = [](int n)
    48. {
    49. return std::rand() % n;
    50. };
    51. std::random_shuffle(cells.begin(), cells.end(), func3);
    52. std::cout << "random_shuffle : ";
    53. std::copy(cells.begin(), cells.end(), std::ostream_iterator<Cell>(std::cout, " "));
    54. std::cout << std::endl;
    55. std::cout << std::endl;
    56. std::generate(cells.begin(), cells.end(), func2);
    57. std::cout << "original : ";
    58. std::copy(cells.begin(), cells.end(), std::ostream_iterator<Cell>(std::cout, " "));
    59. std::cout << std::endl;
    60. std::random_device rd;
    61. std::mt19937 g(rd());
    62. std::shuffle(cells.begin(), cells.end(), g);
    63. std::cout << "shuffle : ";
    64. std::copy(cells.begin(), cells.end(), std::ostream_iterator<Cell>(std::cout, " "));
    65. std::cout << std::endl;
    66. std::cout << std::endl;
    67. return 0;
    68. }

    输出

     

  • 相关阅读:
    java虚拟机 JVM问题记录
    [网络工程师]-网络层协议-IPv6协议
    JAVA:实现BellmanFord贝尔曼-福特求解单源最短路径问题的的算法(附完整源码)
    241. 为运算表达式设计优先级 Python
    Java mysql 双数据源
    测试 SAP 电商云 Spartacus UI 3.4.x 和 4.3.x 的 guest checkout 功能
    flink on yarn任务中文乱码问题解决记录
    conda和Python的虚拟环境如何结合使用,以及二者之间到底有什么区别?
    Docker镜像打包示例
    Normalizer(归一化)和MinMaxScaler(最小-最大标准化)的区别详解
  • 原文地址:https://blog.csdn.net/qq_40788199/article/details/127714970