C ++ Array Shuffle - PullRequest
       27

C ++ Array Shuffle

1 голос
/ 28 мая 2009

Я довольно новичок в C ++ и не совсем понимаю параметры функций с указателями и ссылками. У меня есть набор карт, которые я хочу перемешать, используя перемешивание Фишера-Йейтса. Колода объявлена ​​как

Card *deck[deckSize];

где deckSize был объявлен как 24. Затем массив инициализируется. Затем я вызываю функцию перемешивания:

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

Если я пытаюсь напечатать значение карты после вызова функции случайного воспроизведения, я получаю ошибку сегмента. Любые указатели о том, как сделать это правильно?

Ответы [ 10 ]

13 голосов
/ 28 мая 2009

Просто используйте std::random_shuffle, найденный в <algorithm>, например:

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

и ваша колода будет перетасована.

6 голосов
/ 28 мая 2009

Мой C / C ++ ржавый, но я думаю, что ваша декларация:

Card *deck[deckSize];

объявляет массив указателей на карты. Разве ты не хочешь этого?

Card deck[deckSize];

и затем объявляем случайное перемешивание:

void shuffle (Card deck[]) 

Имейте в виду, что массивы 0-индексированы. Не уверен, что ты когда-нибудь получишь доступ к 24-му элементу, но это будет бу-бу.

2 голосов
/ 27 июля 2009

Вы также можете использовать

std::random_shuffle(deck, deck + deckSize)

, что делает Фишер-Йейтс для вас.

Однако в стандартных случайных библиотеках, вероятно, недостаточно битов, чтобы действительно выбирать из всех возможных случайных комбинаций карточек.

2 голосов
/ 28 мая 2009

Похоже, что ваша проблема не в размещенном коде, который на первый взгляд выглядит хорошо, а в коде вокруг него.

А как насчет использования стандартного контейнера карт? Вы должны заполнить его, сначала распечатать, чтобы убедиться, что все в порядке, перемешать, а затем распечатать снова.

#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;
    }
}
1 голос
/ 28 мая 2009

Я думаю, что это может помочь увидеть код вызова.


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

Это должно работать просто отлично.

1 голос
/ 28 мая 2009
 Card *deck[deckSize];

Я думаю, что вы хотите:

Card *deck = new Card[deckSize];
1 голос
/ 28 мая 2009

Один немедленный задира, вы всегда должны использовать верхнюю половину случайного числа, потому что большинство реализаций случайных чисел имеют меньшую случайность в нижней половине. Поэтому, если long 32-битные, вы можете использовать: k = (k >> 24) % 24, чтобы получить лучшую случайность.

Во-вторых, проблема в том, что вы не устанавливаете темп. Ваш код должен иметь строку: temp = deck[deckSize];.

Надеюсь, это поможет.

Редактировать

Кроме того, ваш генератор случайных чисел также недостаточно велик, чтобы перетасовать колоду карт в достаточной степени, независимо от того, используется ли старший или младший бит. Он имеет только последовательность длиной 48 бит, но для перетасовки колоды вам потребуется последовательность длиной не менее 226 бит (52! Число способов перетасовать колоду - это число длиной 226 бит).

1 голос
/ 28 мая 2009

Вы объявили колоду как массив указателей, но не выделили для нее места. Если вы отмените ссылку, не выделив место, вы получите ошибку сегмента.

0 голосов
/ 28 мая 2009

Люди жалуются, что вы не используете контейнеры и не объявляете размер вашего массива. Не беспокойся об этом, это не проблема. Кто-то также сказал, что вы пересекаете границы массива, а это не так. Можно иметь массивы с размером, который не объявлен. Также хорошо иметь массив указателей на карту. Но я не понимаю, почему он падает. Вот пример кода, который я написал на основе вашего кода:

#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 возможных результатов, некоторые из которых пересекаются, если вы меняете карту обратно на ее первоначальное место. С колодой из трех карт очевидно, что это неправильно, потому что в итоге вы получите 27 различных перемешиваний, некоторые из которых одинаковы, даже если есть 3! = 6 комбинаций из 3 карт. Проблема в том, что, поскольку 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;
    }
}
0 голосов
/ 28 мая 2009

Базовые массивы не могут быть определены с переменной, переданной как размер, как упомянуто выше.

И будь осторожен там. Последний элемент

typename array[SIZE];

- это array[SIZE-1], а не array[SIZE]. Это, вероятно, где вы получаете segfault.

Вы действительно должны хотя бы попытаться использовать контейнеры STL. STL также имеет алгоритмы случайного выбора (:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...