<!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>