シャッフルアルゴリズムは、ゲームをプレイしてランダムにソートするときに遭遇する一般的なランダム問題です。このように抽象化することができます。M。
Baiduで「再シャッフルアルゴリズム」を検索すると、最初の結果は「Baidu Library -Reshuffle Algorithm」でした。コンテンツをスキャンした後、コンテンツの多くは、リンクリストを使用して最終的に配列を置き換えるなど、他の人を誤解させることができます。
この記事の最初の方法は、次のように簡単に説明できます。カードをランダムに描画し、別のグループに入れます。もう一度描画し、空のカードを描くときに繰り返し描画します。
「もう一度描いた後、カードを描く」とは、後でカードを描く可能性が高くなります。これは明らかに不合理です。
1つのステップを最適化できます。カードが描画された後、元のカードが少なくなります。 (空のカードを残すのではなく)
コードは次のとおりです。
コードコピーは次のとおりです。
関数shuffle_pick_1(m)// shush //カード描画方法
{
// Mカードを生成します
var arr = new Array(m);
for(var i = 0; i <m; i ++){
arr [i] = i;
}
//一度に1枚のカードを描画し、別のパイルに置きます。アレイから要素を抽出し、その後のすべての要素を1つずつ前方に引く必要があるため、時間がかかります。
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);
}
ARR2を返します。
}
アレイが大きい場合、中央の特定の要素を削除すると、キューが一歩前進するため、これは明らかに問題があります。これは非常に時間のかかるアクションです。
「なぜその要素を削除するのか」という目的を思い出してください。空のカードを避けることです。
その要素を削除することに加えて、空のカードを削除する他の方法はありますか?
----はい、最後のUndrownカードを描画位置に配置する必要があります。
したがって、このアイデアを次のように最適化できます。
コードコピーは次のとおりです。
function shuffle_pick(m)// shut //カードを最適化するためのカード描画方法
{
// Mカードを生成します
var arr = new Array(m);
for(var i = 0; i <m; i ++){
arr [i] = i;
}
//一度に1枚のカードを描画し、別のパイルに置きます。最後のUndrownカードを開いた座席に置きます。
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];
}
ARR2を返します。
}
カードを描くというアイデアに加えて、カードを変更するというアイデアも使用できます。
「Baidu Wenku-Shut Algorithm」は、カードの変更のアイデアに言及しています。「2つの位置をランダムに切り替え、合計でn nを交換します。nが大きいほど、ランダムに近づきます。」
このアプローチは間違っています。 nが非常に大きい場合(たとえば、10枚のカード、10枚のスイッチなど)、「一部のカードはポジションをまったく変更しない」可能性が高いです。
このアイデアに従って、少し調整します。カードを任意のカードで変更し、1ラウンドで変更するだけです。
コードは次のとおりです。
コードコピーは次のとおりです。
関数shuffle_swap(m)// shush //カード変更方法
{
// Mカードを生成します
var arr = new Array(m);
for(var i = 0; i <m; i ++){
arr [i] = i;
}
// i番目のカードは座席を変更するために使用され、1ラウンドで変更できます
for(var i = 0; i <m; i ++){
var rnd = math.floor(math.random()*(i+1))、
temp = arr [rnd];
arr [rnd] = arr [i];
arr [i] = temp;
}
arrを返します。
}
カードの描画と交換のアイデアに加えて、カードを挿入するというアイデアも使用できます。1枚のカードが1つあります。2番目のカードにはランダムに挿入される2つのポジション(最初のカードの前または後ろ)があり、3番目のカードにはランダムに挿入される3つのポジションがあります(最初の位置に配置するか、2番目のポジションに挿入されます)。
コードは次のとおりです。
コードコピーは次のとおりです。
関数shuffle_insert_1(m)// shunt //カード挿入方法
{
//毎回、最大のカードが生成され、ランダムカードの前に挿入されます。要素を配列に挿入し、その後のすべての要素を1つずつ絞る必要があるため、時間がかかります。
var arr = [0];
for(var i = 1; i <m; i ++){
arr.splice(math.floor(math.random()*(i+1))、0、i);
}
arrを返します。
}
上記のコードにもいくつかの問題があります。カードの数が増えると、カードを挿入すると、カードを挿入すると、一歩後退するカードの多くにつながるためです。
もちろん、適切に最適化することもできます。最初にN-1カードがあり、n-thカードが端に配置され、次に任意のカードと位置を交換します。
コードは次のとおりです。
コードコピーは次のとおりです。
関数shuffle_insert(m)// shush //カード挿入方法の最適化されたバージョンは、このシャッフルが均一であるという数学的誘導によって証明できます。
{
//毎回最大のカードを生成し、ランダムカードでポジションを交換します
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;
}
arrを返します。
}
OK、すべてのコードは次のとおりです。興味のある学生は、それぞれの実行効率かどうか、最終結果が理論的にランダムかどうかを確認するために、自分のマシンで試してみることができます。
コードコピーは次のとおりです。
<html>
<head>
<meta http-equiv = "content-type" content = "text/html; charset = gb2312">
<title> jk:javascriptシャッフルアルゴリズム</title>
</head>
<body>
<script type = "text/javascript">
関数shuffle_pick_1(m)// shush //カード描画方法
{
// Mカードを生成します
var arr = new Array(m);
for(var i = 0; i <m; i ++){
arr [i] = i;
}
//一度に1枚のカードを描画し、別のパイルに置きます。アレイから要素を抽出し、その後のすべての要素を1つずつ前方に引く必要があるため、時間がかかります。
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);
}
ARR2を返します。
}
function shuffle_pick(m)// shut //カードを最適化するためのカード描画方法
{
// Mカードを生成します
var arr = new Array(m);
for(var i = 0; i <m; i ++){
arr [i] = i;
}
//一度に1枚のカードを描画し、別のパイルに置きます。最後のUndrownカードを開いた座席に置きます。
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];
}
ARR2を返します。
}
関数shuffle_swap(m)// shush //カード変更方法
{
// Mカードを生成します
var arr = new Array(m);
for(var i = 0; i <m; i ++){
arr [i] = i;
}
// i番目のカードは座席を変更するために使用され、1ラウンドで変更できます
for(var i = 0; i <m; i ++){
var rnd = math.floor(math.random()*(i+1))、
temp = arr [rnd];
arr [rnd] = arr [i];
arr [i] = temp;
}
arrを返します。
}
関数shuffle_insert_1(m)// shunt //カード挿入方法
{
//毎回、最大のカードが生成され、ランダムカードの前に挿入されます。要素を配列に挿入し、その後のすべての要素を1つずつ絞る必要があるため、時間がかかります。
var arr = [0];
for(var i = 1; i <m; i ++){
arr.splice(math.floor(math.random()*(i+1))、0、i);
}
arrを返します。
}
関数shuffle_insert(m)// shush //カード挿入方法の最適化されたバージョンは、このシャッフルが均一であるという数学的誘導によって証明できます。
{
//毎回最大のカードを生成し、ランダムカードでポジションを交換します
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;
}
arrを返します。
}
// alert(shuffle_pick(10))
var funcs = [shuffle_pick_1、shuffle_pick、shuffle_swap、shuffle_insert_1、shuffle_insert]、
funcnames = ["Draw Card"、 "Draw Card Optimization"、 "Card Change"、 "Card Insert"、 "Card Insert Optimization"]]]
m = 10000、
Times = [];
for(var i = 0; i <funcs.length; i ++){
var d0 = new date();
funcs [i](m);
funcnames [i] =(new date() - d0) + '/t' + funcnames [i];
}
alert(funcnames.join( '/n'));
</script>
</body>
</html>