一种较优的洗牌算法

来源:互联网 发布:mathlab软件下载 编辑:程序博客网 时间:2024/05/11 12:55

本人已经多次接触到关于洗牌算法的讨论,在之前面试时也有人曾问我过,据我所看,大多的实现都不太理想,今晚来了兴致也就捣鼓了一下,放上来以供大家交流交流,从代码中可以看出来,本屌丝的洗牌算法还是挺优的,并且做到了52张牌,张张都是随机抽取到的,如果还有什么不足之处还请大神指点指点

main.cpp

#include "Cards.h"#include <iostream>#include <time.h>int main(int argc, const char * argv[]){    // 以系统时间为随机种子    srand((unsigned)time(0));    Cards cards;    cards.init();    cards.shuffle();    for (int i=0; i<5; ++i)    {        Cards::Card* card = cards.getCardByIndex(i);        printf("%3d", card->_index);    }    return 0;}

Cards.h

#ifndef __Shuffle__Cards__#define __Shuffle__Cards__#include <iostream>class Cards{public:    // 单张纸牌,这里是为了面向对象,里面的成员你也根据自己的需求来修改    struct Card    {    public:        Card(){cleanUp();}        virtual ~Card(){}                // 索引号        char _index;                void cleanUp()        {            _index = 0;        }    };        Cards();    virtual ~Cards();        // 初始化    void init();    // 洗牌    void shuffle();    // 取牌    Card* getCardByIndex(int index);    // 展示纸牌的索引    void showIndexes();private:    // 牌的总数量    int _count;    // 纸牌的索引,因为纸牌最多为52张,所以这里用char就足够了    char* _card_indexes;    // 所有纸牌    Card* _cards;};#endif /* defined(__Shuffle__Cards__) */


Cards.cpp

#include "Cards.h"Cards::Cards(){    // 纸牌总数为52张    _count = 52;    // 申请内存加初始化    _card_indexes = new char[_count];    memset(_card_indexes, 0, sizeof(char) * _count);    _cards = new Card[_count];    /* _cards不在这初始化是因为每个元素已经在Card的构造函数里初始化了,     * 这里不能用malloc来申请内存,如果用malloc那就得进行强转,就不会走Card的构造函数和析构函数     */}Cards::~Cards(){    // 释放内存    delete []_card_indexes;    delete []_cards;}void Cards::init(){    for (int i=0; i<_count; ++i)    {        // 将纸牌的索引号放入_card_indexes数组        _card_indexes[i] = i;        // 填上每张纸牌的索引号,        _cards[i]._index = i;    }}void Cards::shuffle(){    // rand_max为随机上限,初始值为纸牌总数量    int rand_max = _count;    // 随机抽取,直到次数为纸牌的总数量为止    for (int i=0; i<_count; ++i)    {        // 取到随机数,该随机数为_card_indexes的索引        int index_of_indexes = rand() % rand_max;        // 如果抽到的索引号不为随机上限,则进行移动        if (index_of_indexes != rand_max - 1)        {            // 取出即将被覆盖的内存的数据            char card_index = _card_indexes[index_of_indexes];            // 拷贝目标            char* dest = _card_indexes + index_of_indexes;            // 拷贝源            char* src = dest + 1;            // 拷贝的元素个数            int n = _count - index_of_indexes - i - 1;            // 拷贝            memcpy(dest, src, sizeof(char) * n);            // 将之前取出的数据放入移动了的数据之后            _card_indexes[rand_max - 1] = card_index;        }        // 打印出每抽取一次的结果        printf("%d--->%d\n", i, index_of_indexes);        showIndexes();        // 每抽完一次,随机上限就少一次,        --rand_max;    }}Cards::Card* Cards::getCardByIndex(int index){    // 先取到纸牌的索引    int card_index = _card_indexes[index];    // 再去取纸牌    return _cards + card_index;}void Cards::showIndexes(){    for (int i=0; i<_count; ++i)    {        int card_index = _card_indexes[i];        printf("%2d,", card_index);        // 每打印13个元素换行        if (!((i + 1) % 13))        {            printf("\n");        }    }}


0 0