本人已经多次接触到关于洗牌算法的讨论,在之前面试时也有人曾问我过,据我所看,大多的实现都不太理想,今晚来了兴致也就捣鼓了一下,放上来以供大家交流交流,从代码中可以看出来,本屌丝的洗牌算法还是挺优的,并且做到了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");
}
}
}