【问题标题】:How would you shuffle elements in an dynamic 2d array?您将如何对动态二维数组中的元素进行洗牌?
【发布时间】:2021-11-13 06:56:12
【问题描述】:

我一直在网上寻找没有任何运气。

可以随机重新排列/打乱二维数组中的元素吗? 由对象组成的二维数组怎么样?二维数组位于构造函数中。二维数组包含对象元素。这些元素将被“卡片面”对象替换。我已经制作了一类“卡片面”对象,我将其复制并放入二维数组中。每个卡片面在数组中都有一对/匹配。我认为更容易将卡片对象及其副本循环到数组中以替换每个元素,然后再对数组进行洗牌。

所以那个例子...

[[ AH, AH, 2C],
 [ 2C, 3D, 3D],
 [ 4S, 4S, X]]

会变成……

[[ 2C, AH, 2C],
 [ AH, 3D, 4S],
 [ 4S, 3D, X]]

?

【问题讨论】:

  • 我能想到的第一件事是Fisher-Yates shuffle,它将一维数组的内容打乱到位。您必须针对 2D 修改此算法。为此,您可以创建一个索引函数,该函数采用一维索引并找到其二维对应项。例如,在您的示例中,索引 4 将映射到 [2][2] (假设从零开始)。
  • 在 C 中,您可以将二维数组作为一维数组访问。没有理由使用 2D shuffle 来完成您的要求。但这取决于您未指定的数组中的类型 - 乍一看,它看起来像是格式错误的十六进制数字,但在这种情况下,它包含非法字符。变量名不能以数字开头,所以它们也不是变量。
  • @Gowiser 它实际上是一个包含“卡片”面的对象数组。我将更新我的问题以更具体
  • @elo2021 不错。我知道在第一次尝试时很难正确回答您的问题,但如果您不这样做,那么人们会花时间回答问题,这是模棱两可的。其他人会否决建议的答案。
  • 这里你可以看到如何从2d array to 1d array转换,这里你可以看到how to shuffle a 1d array in C

标签: c++ arrays multidimensional-array shuffle dynamic-arrays


【解决方案1】:

如果我们假设我们尝试更改的对象是 std::string 类型,那么我们可以使用下面显示的方法。用于随机化元素顺序的方法是模板,因此它们应该适用于您选择的类型。

#include <iostream>
#include <string>
#include <random>

template <typename T> void swap(T* a, T* b) {
    T temp = *a;
    *a = *b;
    *b = temp;
}

// Shuffle the old fashioned way
template <typename T> void randomize(T arr[], size_t n) {
    if (n == 0)
        return;
    srand((unsigned)time(NULL));
    for (size_t i = n - 1; i > 0; --i) {
        size_t j = rand() % (i + 1);
        swap(arr + i, arr + j);
    }
}

// Shuffle the c++11 way
template <typename T> void randomize_c11(T arr[], size_t n) {
    if (n == 0)
        return;
    std::random_device rd;
    std::mt19937 g(rd());
    std::shuffle(arr, arr + n, g);
}

template <typename T> void print_array(T arr[], size_t rows, size_t cols) {
    std::string indent = "    ";
    std::cout << "[" << std::endl;
    for (size_t row = 0; row < rows; ++row) {
        std::cout << indent << "[";
        for (size_t col = 0; col < cols; ++col) {
            if (col != 0)
                std::cout  << ", ";
            std::cout << *(arr + row*cols + col);
        }
        std::cout << "]" << std::endl;
    }
    std::cout << "]" << std::endl;
}


int main()
{
    std::string array[4][3] = { { "AH", "AH", "2C"},
        {"2C", "3D", "3D"},
        {"AAAA", "BBB", "CC"},
        {"4S", "4S", "X"} };
    // Convert to 1d array (a pointer)
    std::string* array2 = (std::string*)array;
    // Calculate the size of the array
    size_t count = sizeof(array) / sizeof(array[0][0]);
    size_t rows = sizeof(array) / sizeof(array[0]);
    size_t cols = count / rows;
    // Show the 1d-array before sorting
    print_array((std::string*)array, rows, cols);
    // Shuffle the array the old fashioned way
    randomize(array2, count);

    // You can use the variable array directly and avoid using the variable array2:
    //     randomize((std::string *)array, count);

    // You can also do it using the C++11 way:
    //     randomize_c11((std::string *)array, count);

    // Show the array after sorting
    print_array((std::string*)array, rows, cols);
    return 0;
}

这是一个运行程序的例子:

请注意,使用 rand() 进行随机化的老式方法并不是最佳的。见:

Pseudo-random number generation in C++
std::random_device

关于洗牌,另请参阅:

std::random_shuffle, std::shuffle

【讨论】:

  • 支票if (n == 0) return;不够吗?
  • 是的 - 没看到。
  • 您不能通过简单地将 T[][] 转换为 T* 来将 2D 数组视为 1D 数组。 It is undefined behavior.
  • @xskxzr 感谢您的反馈。据我了解,数组是连续存储在内存中的,如果您在数组的大小之外解决 问题,那么您只会得到未定义的行为,这也是您链接到的答案所说的。我还在帖子中讨论了随机的使用。至于 how 没有指定 shuffle,不清楚 OP 想要如何 shuffle。我会澄清 - ty。
【解决方案2】:

只需在脑海中将数组展开为一维数组,然后像其他任何数组一样随机化它:

  1. 在 0 和 num_items-1 之间选择一个随机数 n

  2. 从输出数组的第一个索引复制到索引n

  3. 从 0 到 num_empty_slots -1 范围内选择另一个随机数(因此比以前低 1)

  4. 从数组的开头到结尾计算 empty 个槽,并复制到第 n 个空槽。

  5. 回到 3

您实际上不需要第 1 步和第 2 步,因为 3-5 涵盖了所有情况,但我将它们包括在内以使其更直观。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-07
    • 1970-01-01
    • 2019-08-18
    • 2020-11-22
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 2019-12-29
    相关资源
    最近更新 更多