随机置乱算法

【正解】高纳德置乱算法(Knuth-Fisher-Yates algorithm

准确性:这个算法是无偏的,即每个排列都是等可能的

效率:时间复杂度Θ(n),无需额外空间(基于交换元素)

伪代码:

int a[n]
for i from n-1 to 1
    get a random_integer j (0≤j≤i)
    swap a[i] with a[j]
end

以下是C++实现方法:

①使用STL内置的random_shuffle函数实现;

②手动实现;

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;

int main()
{
	int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };	//原始数列 
	
	//random_shuffle(a, a+10);						//random_shuffle:STL洗牌函数 

	srand(time( NULL ));							//随机数种子 
	for(int i = 9; i > 0; --i)
		swap(a[i], a[rand() % (i + 1)]);			//swap:STL交换函数 

	for(int i = 0; i < 10; ++i)
		cout << a[i] << ' ';						//输出乱序后数列 

	return 0;
}


【错解一】

伪代码:

int a[n]
for i from n-1 to 1
    get a random_integer j (0≤j≤i-1)
    swap a[i] with a[j]

end

分析:将产生一个随机的错位排列,即没有一个元素在原来的位置上


【错解二】Naive algorithm

伪代码:

int a[n]
for i from n-1 to 1
    get a random_integer j (0≤j≤n-1)
    swap a[i] with a[j]

end

这种方法在不仔细思考地情况下极其容易被认为是正确的,但其实是错误的。

分析:此方法将产生n^n中不同的交换方式,每种交换方式是等可能的,而所有排列方式有 n! 种。

显然n^n mod n! ≠ 0(因为 n^n 没有 (n-1) 这个因子而 n! 有),这意味着 n! 种排列方式不使等可能的。

事实上:

①三元素数组乱序时



②四元素乱序时



与正解算法比较,可以看出其正确性有较大问题。


【参考资料】

【C++ STL应用与实现】64: 如何使用shuffle和random_shuffle : 洗牌 (since C++11)

The Danger of Naïveté

费雪耶兹(Fisher–Yates) 也被称作高纳德( Knuth)随机置乱算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值