<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>洗牌算法</title>
</head>
<body>
<script>
/**
* 洗牌算法
*/
function shuffle_pick_1(m) {//洗牌 抽牌法
//生成m张牌
var arr = new Array(m);
for (var i = 0; i < m; i++) {
arr[i] = i;
}
//var arr = Array(m).fill().map((_,i)=>i); 优雅的做法
//每次抽出一张牌,放在另一堆。因为要在数组里抽出元素,
//把后面的所有元素向前拉一位,所以很耗时
var arr2 = new Array()
for (var i = m; i > 0; i--) {
var rnd = Math.floor(Math.random() * i);
arr2.push(arr[rnd]);
arr.splice(rnd, 1);
}
return arr2;
}
function shuffle_pick(m) {//洗牌 //抽牌法优化牌
var arr = new Array(m);
for (var i = 0; i < m; i++) {
arr[i] = i;
}
var arr2 = new Array();
for (var i = m; i > 0;) {
var rnd = Math.floor(Math.random() * i);
arr2.push(arr[rnd]);
arr[rnd] = arr[--i]
}
return arr2;
}
function shuffle_swap(m) {//洗牌 换牌法
var arr = new Array(m);
for (var i = 0; i < m; i++) {
arr[i] = i;
}
//第i张与任意一张牌换位子,换完一轮即可
for (var i = 0; i < m; i++) {
var rnd = Math.floor(Math.random() * (i + 1)),
tmp = arr[rnd];
arr[rnd] = arr[i];
arr[i] = tmp;
}
return arr;
}
function shuffle_insert_1(m) {//洗牌 插牌法
var arr = [0];
////每次生成一张最大的牌,插在随机的某张牌前。因为要在数组里插入元素,把后面的所有元素向后挤一位,所以很耗时。
for (var i = 1; i < m; i++) {
arr.splice(Math.floor(Math.random() * (i + 1)), 0, i);
}
return arr;
}
function shuffle_insert(m) {//洗牌 //插牌法优化版,可以用数学归纳法证明,这种洗牌是均匀的。
var arr = new Array(m);
arr[0] = 0;
for (var i = 1; i < m; i++) {
var rnd = Math.floor(Math.random() * (i + 1));
arr[i] = arr[rnd];
arr[rnd] = i;
}
return arr;
}
function withLog(fn, name) {
return function (args) {
var start = new Date();
var result = fn(args);
var end = new Date();
console.log(name + ' 耗时:', end - start);
return result;
}
}
var fns = [shuffle_pick_1, shuffle_pick, shuffle_swap, shuffle_insert_1, shuffle_insert];
var fnNames = ['抽牌法', '抽牌法优化', '换牌法', '插牌法', '插牌法优化'];
for (var i = 0; i < fns.length; i++) {
var ret = withLog(fns[i], fnNames[i])(10000);
}
</script>
</body>
</html>