【问题标题】:logic for implementing card shuffling实现洗牌的逻辑
【发布时间】:2014-03-27 06:41:27
【问题描述】:

我正在尝试为一副纸牌实现一个类。 “deck”包含的功能之一是随机播放。

void deck::shuffle()
{
    int cardsleft = deck::cards;
    for(int i = 0; i < cardsleft ; i++)
    {
        srand(time(NULL));
        int rdmn = rand() % cardsleft;
        card tempcard = deck::dcards[rdmn];
        deck::dcards[rdmn] = deck::dcards[i];
        deck::dcards[i] = tempcard;
    }

}

为了清楚起见,deck::cards 是一个整数计数。在这个牌组中剩下的牌,deck::dcards 是这个牌组中牌的数组。

我的问题是:这不会产生很好的结果。难道我需要通过指针来做这个,传递引用?如果是这样,它是如何完成的?

或者,它可能只是糟糕的算法吗?也许我只需要一个更好的洗牌逻辑。请说。注意:是的,我知道“algorithm.h”库中有一个 std::shuffle std::random_shuffle 函数,但这些只适用于向量,而不是我在这里使用的数组,不是吗?

更新:nvm,我刚刚意识到我的问题可以在这里回答: http://blog.codinghorror.com/the-danger-of-naivete/

所以这是一个逻辑缺陷,而不是我的实现。

【问题讨论】:

  • std::random_shufflestd::shuffle 适用于任何随机访问范围。数组是一个随机访问范围。

标签: c++ performance algorithm logic shuffle


【解决方案1】:

当你这样做时

srand(time(NULL));

您将种子设置为当前时间。由于此循环将在一秒钟内全部运行(time 函数的正常分辨率),因此种子将在循环中重置为相同的起始值,导致您每次几乎总是获得相同的随机数。

您应该只为随机数生成器播种一次,最好尽早在main 函数中。


您可能还想查看new PRNG functionality in C++11

【讨论】:

    【解决方案2】:

    如果您需要洗牌,您应该考虑std::random_shuffle(或C++11 中的std::shuffle)。它对序列中的元素进行重新排序,以便这些元素的每个可能排列具有相同的出现概率。是的,它可以与数组一起使用,而不仅仅是向量。任何“范围”。

    现在回到您的代码,您遇到了播种问题。生成(伪)随机数的算法采用初始值,即种子。给相同的种子,它们会产生相同的数字序列。这意味着您只需要播种一次生成的随机数(每个线程),否则您将一次又一次地产生相同的数字序列。在你的这个循环中,你会在一段时间内获得相同的数字,直到时间改变,才会使用种子的新值。

    【讨论】:

    • "只需要为随机数生成[或]播种一次(每个线程)"。根据 cppreference.com,srand() 不能保证是线程安全的,它的实现定义了 rand() 本身是否是。如果一个实现使用线程特定的数据,那么你的建议可能是好的;如果它被锁定,那么从多个线程调用srand() 会破坏周期性保证。无论如何 - 重点是需要查阅实施文档。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-10
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多