shuffle.h 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. #pragma once
  2. #include "fast.h"
  3. #include "entropy.h"
  4. #include <util/generic/utility.h>
  5. #include <util/system/yassert.h>
  6. // some kind of https://en.wikipedia.org/wiki/Fisher–Yates_shuffle#The_modern_algorithm
  7. template <typename TRandIter, typename TRandIterEnd>
  8. inline void Shuffle(TRandIter begin, TRandIterEnd end) {
  9. Y_ASSERT(begin <= end);
  10. static_assert(sizeof(end - begin) <= sizeof(size_t), "fixme");
  11. static_assert(sizeof(TReallyFastRng32::RandMax()) <= sizeof(size_t), "fixme");
  12. if ((size_t)(end - begin) < (size_t)TReallyFastRng32::RandMax()) {
  13. Shuffle(begin, end, TReallyFastRng32(Seed()));
  14. } else {
  15. Shuffle(begin, end, TFastRng64(Seed()));
  16. }
  17. }
  18. template <typename TRandIter, typename TRandIterEnd, typename TRandGen>
  19. inline void Shuffle(TRandIter begin, TRandIterEnd end, TRandGen&& gen) {
  20. Y_ASSERT(begin <= end);
  21. const size_t sz = end - begin;
  22. for (size_t i = 1; i < sz; ++i) {
  23. DoSwap(*(begin + i), *(begin + gen.Uniform(i + 1)));
  24. }
  25. }
  26. // Fills first size elements of array with equiprobably randomly
  27. // chosen elements of array with no replacement
  28. template <typename TRandIter, typename TRandIterEnd>
  29. inline void PartialShuffle(TRandIter begin, TRandIterEnd end, size_t size) {
  30. Y_ASSERT(begin <= end);
  31. static_assert(sizeof(end - begin) <= sizeof(size_t), "fixme");
  32. static_assert(sizeof(TReallyFastRng32::RandMax()) <= sizeof(size_t), "fixme");
  33. if ((size_t)(end - begin) < (size_t)TReallyFastRng32::RandMax()) {
  34. PartialShuffle(begin, end, size, TReallyFastRng32(Seed()));
  35. } else {
  36. PartialShuffle(begin, end, size, TFastRng64(Seed()));
  37. }
  38. }
  39. template <typename TRandIter, typename TRandIterEnd, typename TRandGen>
  40. inline void PartialShuffle(TRandIter begin, TRandIterEnd end, size_t size, TRandGen&& gen) {
  41. Y_ASSERT(begin <= end);
  42. const size_t totalSize = end - begin;
  43. Y_ASSERT(size <= totalSize); // Size of shuffled part should be less than or equal to the size of container
  44. if (totalSize == 0) {
  45. return;
  46. }
  47. size = Min(size, totalSize - 1);
  48. for (size_t i = 0; i < size; ++i) {
  49. DoSwap(*(begin + i), *(begin + gen.Uniform(i, totalSize)));
  50. }
  51. }
  52. template <typename TRange>
  53. inline void ShuffleRange(TRange& range) {
  54. auto b = range.begin();
  55. Shuffle(b, range.end());
  56. }
  57. template <typename TRange, typename TRandGen>
  58. inline void ShuffleRange(TRange& range, TRandGen&& gen) {
  59. auto b = range.begin();
  60. Shuffle(b, range.end(), gen);
  61. }