简体   繁体   English

C ++数组随机播放

[英]C++ Array Shuffle

I'm fairly new to C++ and don't quite understand function parameters with pointers and references. 我对C ++相当陌生,并且不太了解带有指针和引用的函数参数。 I have an array of Cards that I want to shuffle using the Fisher-Yates shuffle. 我有一系列要使用Fisher-Yates洗牌进行洗牌的卡片。 The deck is declared as 甲板被宣布为

Card *deck[deckSize];

where deckSize has been declared as 24. The array is then initialized. 其中deckSize已声明为24。然后初始化该数组。 I then call the shuffle function: 然后,我调用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;
    }
}

If I try to print the value of a card after calling the shuffle function I get a seg fault. 如果在调用随机播放功能后尝试打印卡的值,则会出现段错误。 Any pointers on how to do this properly? 关于如何正确执行操作的任何指示?

Just use std::random_shuffle found in <algorithm> , like this: 只需使用<algorithm> std::random_shuffle ,如下所示:

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

and your deck with be shuffled. 和你的甲板被洗牌。

My C/C++ is rusty but I think your declaration: 我的C / C ++生锈了,但我认为您的声明是:

Card *deck[deckSize];

is declaring an array of POINTERS to Cards. 正在向卡片声明一个POINTERS数组。 Don't you want this? 你不想要这个吗

Card deck[deckSize];

and then declare shuffle: 然后声明洗牌:

void shuffle (Card deck[]) 

keep in mind arrays are 0-indexed. 请记住,数组是0索引的。 Not sure if you'd ever access the 24th element but that would be a boo-boo. 不知道您是否曾经访问过第24个元素,但这将是一个boo-boo。

You could also use 您也可以使用

std::random_shuffle(deck, deck + deckSize)

which does Fisher-Yates for you. 费舍尔·耶茨(Fisher-Yates)为您服务。

However, there probably aren't enough bits in the standard random libraries to genuinely choose from all possible random permutations of cards. 但是,标准随机库中可能没有足够的位来真正地从卡的所有可能的随机排列中进行选择。

It looks that your problem does not come from the code posted, which looks fine at a first glance, but from the code around it. 看来您的问题不是出在发布的代码上,乍看之下看起来不错,但出在周围的代码上。

What about using a standard container of cards ? 使用标准的卡容器怎么办? You must fill it, print it first to see if it's ok, shuffle, and then print it again. 您必须先将其填充,然后先打印以确认是否正常,然后随机播放,然后再次打印。

#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;
    }
}

You declared deck as an array of pointers but you didn't allocate any space for it. 您将deck声明为指针数组,但没有为其分配任何空间。 If you de-reference it without allocating space you will get a seg-fault. 如果取消引用它而不分配空间,则会出现段错误。

One immediate nitpick, you should always use the top-half of a random number because most implementations of random numbers have poorer randomness on the bottom half. 一个直接的提要,您应该始终使用随机数的上半部分,因为大多数随机数实现在下半部分的随机性都较差。 So if long's are 32 bit you could use: k = (k >> 24) % 24 to get better randomness. 因此,如果long为32位,则可以使用: k = (k >> 24) % 24以获得更好的随机性。

Second, the problem here is you are not setting temp. 其次,这里的问题是您没有设置温度。 Your code should have a line: temp = deck[deckSize]; 您的代码应该有一行: temp = deck[deckSize]; .

Hope this helps. 希望这可以帮助。

Edit : 编辑

Further nitpick, your random number generator is also not big enough to sufficiently shuffle a deck of cards regardless of using the high bit or low bit. 更进一步,无论您使用高位还是低位,您的随机数生成器都还不足以充分打乱一副纸牌。 It only has 48bit long sequence, but to shuffle a deck you'd need at least a 226bit long sequence (52!, the number of ways to shuffle a deck, is a 226bit long number). 它只有48位长的序列,但是混洗一个牌组,您至少需要一个226位长的序列(52 !,牌组的混洗方式的数量,是226位长)。

 Card *deck[deckSize];

我想你要:

Card *deck = new Card[deckSize];

I think it might help to see the calling code. 我认为查看调用代码可能会有所帮助。

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()

That should work just fine. 那应该很好。

Basic arrays can't be defined with variable passed as size, as mentioned above. 如上所述,基本数组无法使用作为大小传递的变量来定义。

And be careful there. 并在那里小心。 Last element of 的最后一个元素

typename array[SIZE];

is array[SIZE-1] , not array[SIZE] . array[SIZE-1] ,不是array[SIZE] It's probably where you getting a segfault. 这可能是您遇到段错误的地方。

You really should at lest try to use STL containers. 您确实应该至少尝试使用STL容器。 STL has shuffle algorithms too (: STL也有洗牌算法(:

People are complaining that you're not using containers and not declaring the size of your array. 人们抱怨您没有使用容器,也没有声明数组的大小。 Don't worry about that, that's not the problem. 不必担心,这不是问题。 Someone also said you're going past array boundaries, which you aren't. 有人还说您要越过数组边界,但事实并非如此。 It's okay to have arrays with size not declared. 没有声明大小的数组也可以。 It's also okay to have an array of pointers to Card. 拥有指向Card的指针数组也是可以的。 But the thing I don't get is why it crashes. 但是我不明白的是为什么它崩溃了。 Here's some sample code I wrote, based on your code: 这是我根据您的代码编写的一些示例代码:

#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;
}

Run it, it works perfectly fine. 运行它,它工作得很好。 That means there is something else going on. 这意味着还有其他事情发生。 Try printing the value of all the cards in your deck before you call shuffle to see if it segfaults there too, I suspect it would. 我猜这会在您调用shuffle之前尝试打印出卡座中所有卡的值,以查看是否也存在段错误。

However, there IS an error in your code. 但是,您的代码中有错误。 Your function does not shuffle correctly. 您的功能无法正确随机播放。 The correct way to shuffle is not to swap each card with a card selected from the entire deck, but to swap each card at position N with an card selected from the range 0..N. 正确的洗牌方式不是将每张卡与从整个牌组中选择的一张卡交换,而是将位置N处的每张卡与从0..N范围中选择的卡交换。 If you swapped each card with a random card you get N^N possible outcomes, some of which overlap if you swap a card back to its original place. 如果用随机卡交换每张卡,则会得到N ^ N个可能的结果,如果将卡交换回其原始位置,则某些结果会重叠。 With a 3 card deck it's apparent that this is wrong because you will end up with 27 different shuffles, some of which are the same, even though there are 3!=6 permutations of 3 cards. 如果使用3张牌,这显然是错误的,因为您最终将得到27个不同的混洗,即使3张纸有3!= 6个排列,它们中的一些也是相同的。 The problem is that since 6 is not a factor of 27, some permutations are more likely than others. 问题在于,由于6不是27的因数,因此某些排列比其他排列更有可能。 To avoid this, try doing it this way: 为了避免这种情况,请尝试通过以下方式进行操作:

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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM