C ++ Array Shuffle

时间:2009-05-28 17:44:17

标签: c++ arrays pointers

我对C ++很新,并且不太了解带有指针和引用的函数参数。我有一系列卡片,我想使用Fisher-Yates shuffle进行洗牌。套牌被宣布为

Card *deck[deckSize];

其中deckSize已声明为24.然后初始化该数组。 然后我调用shuffle函数:

void shuffle (Card * deck[]) {
    int deckSize = 24;
    while (deckSize > 1) {
       long int k = lrand48();
       k = k %24;
       deckSize--;
       Card * temp = deck[deckSize];
       deck[deckSize] = deck[k];
       deck[k] = temp;
    }
}

如果我在调用shuffle函数后尝试打印卡的值,则会出现seg错误。有关如何正确执行此操作的任何指示?

10 个答案:

答案 0 :(得分:13)

只需使用std::random_shuffle中的<algorithm>,就像这样:

std::random_shuffle(deck, deck + deckSize);

和你的牌组一起洗牌。

答案 1 :(得分:6)

我的C / C ++生锈但我认为你的声明:

Card *deck[deckSize];

正在向卡片声明一系列指针。你不想要这个吗?

Card deck[deckSize];

然后声明shuffle:

void shuffle (Card deck[]) 

请记住,数组是0索引的。不确定你是否曾经访问过第24个元素,但那将是一个嘘声。

答案 2 :(得分:2)

看起来您的问题不是来自发布的代码,乍一看看起来很好,但是来自它周围的代码。

使用标准容器卡怎么样?你必须填写它,首先打印它,看它是否正常,随机播放,然后重新打印。

#include <vector>
std::vector<Card> deck; // Empty for now. Must be filled with cards.


void shuffle (std::vector<Card> & deck)
{
    int deckSize = 24;
    while (deckSize > 1) 
    {
       long int k = lrand48();
       k = k %24;
       deckSize--;
       Card temp = deck[deckSize];
       deck[deckSize] = deck[k];
       deck[k] = temp;
    }
}

答案 3 :(得分:2)

您也可以使用

std::random_shuffle(deck, deck + deckSize)

为你做Fisher-Yates。

然而,标准随机库中可能没有足够的位来真正从卡的所有可能的随机排列中进行选择。

答案 4 :(得分:1)

您将deck声明为指针数组,但您没有为它分配任何空间。如果在不分配空间的情况下取消引用它,则会出现seg-fault。

答案 5 :(得分:1)

一个直接的挑剔,你应该总是使用随机数的上半部分,因为大多数随机数的实现在下半部分具有较差的随机性。因此,如果long为32位,您可以使用k = (k >> 24) % 24来获得更好的随机性。

其次,问题在于你没有设定温度。您的代码应该有一行:temp = deck[deckSize];

希望这有帮助。

修改

进一步的挑剔,你的随机数发生器也不够大,无论使用高位还是低位,都可以充分改变一副牌。它只有48位长的序列,但是为了洗牌,你需要至少一个226比特长的序列(52!,改变牌组的方式的数量,是一个226比特长的数字)。

答案 6 :(得分:1)

 Card *deck[deckSize];

我想你想要:

Card *deck = new Card[deckSize];

答案 7 :(得分:1)

我认为查看调用代码可能会有所帮助。


class Card{
public:
    Card(int number):number_(number){}
    int getNumber(){return number_;}
 // ...
private:
    int number_;
};

void shuffle (Card * deck[]) {
    int deckSize = 24;
    while (deckSize > 1) {
       long int k = lrand48();
       k = k %24;
       deckSize--;
       Card * temp = deck[deckSize];
       deck[deckSize] = deck[k];
       deck[k] = temp;
    }
}

int main(int argc, char* argv[]){
{

  const int deckSize=24;
  Card* deck[deckSize];
  for(int i = 0 ; i getNumber()

这应该可以正常工作。

答案 8 :(得分:0)

如上所述,无法使用传递给大小的变量定义基本数组。

在那里要小心。

的最后一个要素

typename array[SIZE];

array[SIZE-1],而不是array[SIZE]。这可能是你遇到段错误的地方。

你真的应该尽量使用STL容器。 STL也有洗牌算法(:

答案 9 :(得分:0)

人们抱怨你没有使用容器而没有声明数组的大小。不要担心,这不是问题。有人还说你要超越阵列边界,你不是。没有声明大小的数组是可以的。拥有一系列指向Card的指针也没关系。但我没有得到的是它崩溃的原因。以下是我编写的一些示例代码,基于您的代码:

#include <stdio.h>
#include <stdlib.h>
#define DECK_SIZE 24
void shuffle(int deck[]) {
    int n = DECK_SIZE, t;
    while (n > 1) {
        long k = lrand48() % DECK_SIZE;
        n--;
        t = deck[n];
        deck[n] = deck[k];
        deck[k] = t;
    }
}
int main(int argc, char **argv) {
    int deck[DECK_SIZE], i;
    for (i = 0; i < DECK_SIZE; ++i)
        deck[i] = i + 1;
    shuffle(deck);
    for (i = 0; i < DECK_SIZE; ++i)
        printf("%i\n", deck[i]);
    return 0;
}

运行它,它完全正常。这意味着还有其他事情要发生。在你打电话给shuffle之前尝试打印你牌组中所有牌的价值,看看它是否也存在段错误,我怀疑它会。

但是,您的代码中存在错误。你的功能没有正确洗牌。正确的洗牌方法不是将每张卡与从整个牌组中选择的牌交换,而是将位置N处的每张牌与从0..N范围内选择的牌交换。如果您使用随机卡交换每张卡,您将获得N ^ N个可能的结果,如果您将卡交换回其原始位置,其中一些会重叠。有了3张卡牌,很明显这是错误的,因为你最终将会有27次不同的洗牌,其中一些是相同的,即使有3张卡的3 = 6个排列。问题在于,由于6不是27的因子,因此某些排列比其他排列更可能。为避免这种情况,请尝试这样做:

void shuffle_correctly(int deck[]) {
    int i, t, k;
    for (i = 2; i < DECK_SIZE; ++i) {
        k = lrand48() % i;
        t = deck[i-1];
        deck[i-1] = deck[k];
        deck[k] = t;
    }
}