洗牌算法在笔试面试中出现过几次了,之前想的方法都不太好,而且实现也较复杂。看STL源码剖析才知道STL里提供了一个将容器元素打乱重排的算法random_shuffle(),算法的实现很简单,下面是源代码:
/**
* @brief Shuffle the elements of a sequence using a random number
* generator.
* @ingroup mutating_algorithms
* @param first A forward iterator.
* @param last A forward iterator.
* @param rand The RNG functor or function.
* @return Nothing.
*
* Reorders the elements in the range @p [first,last) using @p rand to
* provide a random distribution. Calling @p rand(N) for a positive
* integer @p N should return a randomly chosen integer from the
* range [0,N).
*/
template<typename _RandomAccessIterator, typename _RandomNumberGenerator>
void
random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
_RandomNumberGenerator& __rand)
{
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_requires_valid_range(__first, __last);
if (__first == __last)
return;
for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i)
std::iter_swap(__i, __first + __rand((__i - __first) + 1));
}
要将向量vector<int> ivec中的元素打乱,调用random_shuffle(ivec.begin(), ivec.end())即可。
参考该算法的实现,可以很简单的写出洗牌算法:
void Show(int *arr)
{
for (int i = 1; i <= 54; i++)
cout << arr[i] << ends;
cout << endl;
}
int main()
{
int arr[55] = {0}; //代表扑克牌的数组
for (int i = 1; i <= 54; i++)
arr[i] = i;
Show(arr);
srand(time(0));
int first = 1;
int last = 55;
for (int i = first + 1; i != last; i++)
{
swap(arr[i], arr[first + rand() % ((i - first) + 1)]);
}
//random_shuffle(arr + 1, arr + 55); //和直接调用STL中的random_shuffle()算法是一样的效果
Show(arr);
return 0;
}