![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?5a7ff87)
要素数が5つなら5!で120通り、nであればn!通りの配列をすべて得たい、といった具合です。
自分で組んでみたところ、再帰呼び出しを多用しているせいか要素を8つにした時点でFirefoxだと「このページのスクリプトは処理に時間がかかっているか応答しなくなっています。…」、IEでも似たような警告文が表示されてしまいます。
コードは以下に示すとおりです。
そこでお聞きしたいのは、
1.「処理に時間が~云々」などの表示をさせずに処理を
続けさせるにはどのように書いたらいいか
2.もっと短くスマートなコードで全走査できないか
の2つです。
1.についてはユーザサイドでなく開発者サイドで、かつalertを使う以外の方法で、警告文を出させないで処理を続けさせるためにはコードをどのようにしたらよいでしょうか。
2.に関しては、私が書いたコードは正直わかりにくいと思いますので、もっとシンプルに全走査できるアルゴリズムがあったら教えてほしいです。
どうかよろしくお願いします。
<html>
<body>
<script type="text/javascript">
<!--
//Arrayオブジェクトに自身をコピーした配列を返すclone()メソッド追加
Array.prototype.clone = function(){
// 自分自身が配列かをチェック
if(this[0].constructor == Array ){
var ar, n;
//新しい配列を用意する
ar = new Array(this.length);
for(var n=0;n<ar.length;n++){
//再起呼び出しで配列の中身をコピー
ar[n] = this[n].clone();
}
//作成した配列を返す
return ar;
}
return Array.apply(null,this);
}
//★要素を並べ替える前の配列の宣言
var ar = new Array("1","2","3","4","5","6","7","8");
//並べ替え後の配列を格納する配列宣言
var arranged_ar = new Array();
function arArrange(){
//引数は(呼び出した節の、並び替える前の配列内での順番,すでに取り出した節の配列,兄弟の配列)
function createBranch(parentCounter,parentNodes,sameDepthBranches){
var branches = new Array(); //呼び出した節の子ノード格納用の配列宣言
branches = sameDepthBranches.clone(); //呼び出した節の兄弟をコピー
branches.splice(parentCounter,1) //呼び出した節を除いて子ノードの配列作成完了
var pushed_ar = new Array(); //この節以前に登場した節を格納する(最終的に並べ替え終わった配列になる)配列宣言
pushed_ar = parentNodes.clone(); //呼び出し元のpushed_arをコピー
for(var i=0;i<branches.length;i++){
pushed_ar.push(branches[i]); //pushed_arに子ノードを1つ追加
//走査が葉ノードに達したときの処理
if(pushed_ar.length == ar.length){
var length = arranged_ar.length;
arranged_ar[length] = new Array();
for(var j=0;j<pushed_ar.length;j++){
arranged_ar[length].push(pushed_ar[j]); //arranged_arに並び替え後の配列を格納
}
//走査がまだ葉ノードに達していない場合の処理
}else{
createBranch(i,pushed_ar,branches); //自身を再帰呼び出しすることで葉ノードに達するまでループ
}
//子ノード以下の走査が終わった場合の処理
pushed_ar.splice(pushed_ar.length-1,1); //追加した子ノードを削除して次の子ノード追加へ
}
return;
}
//↑で宣言したcreateBranch関数の呼び出し
for(i=0;i<ar.length;i++){
var tempAr = new Array();
tempAr.push(ar[i]);
createBranch(i,tempAr,ar);
}
//結果をresultに格納
var result = "";
for(var i=0;i<arranged_ar.length;i++){
result += i+1 + ": ";
for(var j=0;j<arranged_ar[i].length;j++){
result += arranged_ar[i][j] + ",";
}
result += "<br>";
}
//結果を画面に表示
document.getElementById("result").innerHTML = result;
return;
}
-->
</script>
<input type="button" value="全並べ替えパターン走査" onclick="arArrange();">
<p id="result">ここに結果表示</p>
</body>
</html>
A 回答 (3件)
- 最新から表示
- 回答順に表示
No.3
- 回答日時:
解説の前に補足。
「辞書式」は一般的な辞書式ではなく、配列tに定義された順を「辞書式」とする。
といった文言を書き忘れていました。(わかっていただけた気もしますが)
さて、解説。
全体の方針としては、
「n個の異なる文字を重複することなく1列に並べる場合の数を求めよ」
といったよくありがちな問題の解法、高校数学Aの「階乗」の概念を使っています。
1文字目はn通り、2文字目は(n-1)通り、・・・
例としてn=4を使い
(1)動作の最終目的
(2)各々の文字が何番目かを表す数字で表現
(3)左から並べる過程の中で、その文字が残った文字の中で(0から数え)何番目か(ここがミソ)
を“右から”(表示崩れの都合上)図にしてみると、
(3) (2) (1)
0000 0123 abcd ここで、図(3)を縦に見てみると、規則性に気づくはずです。
0010 0132 abdc 左からi個目(1≦i≦n)の数字は
0100 0213 acbd (n-i)! 個ずつ、0から(n-i)までの数字を繰り返しています。
0110 0231 acdb
0200 0312 adbc 辞書式k番目(0≦k<n)のi文字目は、(変数_に代入される)
0210 0321 adcb A K=k%( (n-i+1)! ) kを(n-(i-1))!で割った余りKを利用して
1000 1023 bacd (Kは(i-1)文字目までが同じとなる集団の中で何番目かを表す)
1010 1032 badc B K÷((n-i)!) を切捨てた数として表現されます
1100 1203 bcad
1110 1230 bcda (3)→(2)の復元の為、何文字目が使われたかを表す配列Aを使う。
1200 1302 bdac A[j] : j番目の文字が使用されているか
1210 1320 bdca A=[1,0,1,0],_=1の場合、Aの中で(_+1=)2回目に0が現れる場所が
2000 2013 cabd _に代入され(2)の数字を表す。
2010 2031 cadb (2)→(1)の復元は、t[_]
略
function a(k){n=_n;N=_N/n;//n,Nは処理内で書き換えられるので、バックアップを代入。
//Nは本当は(n-1)!から必要なので、nで割っておく
for(i=0;i<n;i++)A[i]=0;//フラグ用配列初期化
var r=t[_=k/N>>0];A[_]=1;//一文字目。k<Nなので、式A不要。>>0の0ビットシフトで正の数切捨て。
//_番目を使用したのでA[_]をtrueにしておく
for(i=1;i<_n;i++){//二文字目以降
k=k%N;//式A kそのものを上書きし、後のコードを簡潔化
N/=--n;//N:n! → N:(n-1)! に変更。 次回のループのためにnを小さくしておく
_=k/N>>0;//式B
for(j=0;j<=_;j++)_+=A[j];//(3)→(2)の復元処理
r+=t[_];A[_]=1;//(2)→(1)の復元をし、rに連結。Aに_番目使用済みと記録
}
return r;}
自分でも読んでて これで分かるのか? な感じです。
わからないところ聞いてください。
No.2
- 回答日時:
>1.「処理に時間が~云々」などの表示をさせずに処理を
> 続けさせるにはどのように書いたらいいか
処理を複数の関数に区切り、setTimeout等である程度ブランクを入れる。といいはず。
ループ回数が多いのは区切りにくいので通用しないかも?
それと、動作が速い表記を使う
new Array()→[]
なんかはすごくよく使う
>2.もっと短くスマートなコードで全走査できないか
配列には、しないほうがよさそうです。
データの量がnの増加に伴って莫大に増えていく割りに、使われるデータはごく一部です。
きっとメモリも悲鳴を上げています。
私が考えたのは、arranged_ar[k]の形式で呼び出す代わりに、
arranged_ar(k)と表記し、関数によりその場でデータを生成する形です。
因に私の癖でショートコーディング風味になってしまったので、
変数名変わってます&解説不能です(笑)
アルゴリズムも、これを説明するのか・・・? って思うぐらいな物ですが、必要とあらば、たぶん、、します。。。できるかなぁ・・・
変数名・関数名は自由に変えてください
設定:n(整数。n<=35ではサクサクの動作を確認)、t(並べ替える文字たち。一文字ずつじゃなくてもOK)
呼び出し:a(k) で辞書式でk番目のデータ
<script><!--
var i,j,_,_n=n=35,_N=N=1,A=[];
var t=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r',
's','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','J','K','略...'];
while(n)N*=n--;//n!をNに格納
_N=N;n=_n;//バックアップ
function a(k){n=_n;N=_N/n;
for(i=0;i<n;i++)A[i]=0;//フラグ用配列初期化
var r=t[_=k/N>>0];A[_]=1;//一文字目
for(i=1;i<_n;i++){//二文字目以降
k=k%N;
N/=--n;
_=k/N>>0;
for(j=0;j<=_;j++)_+=A[j];
r+=t[_];A[_]=1;
}
return r;}
alert(a(10000))//辞書式で並べた結果の10000番目の文字列を計算。
//辞書式であることが確認されうるでしょう
//alert(a(0)+"\n"+a(1)+"\n"+a(2)+"\n\n"+a(50000)+"\n"+a(50001)+"\n"+a(50002))
//どうしても、というなら配列化。n>8ノンストップは無理。
//var ar=[];
//for(k=0;k<_N;k++)ar[k]=a(k)
//--></script>
回答ありがとうございます。
大変参考になったのですが、お手数ですがコードの説明をしていただけますか?初心者でコードが理解できないので。。。
面倒であれば
var r=t[_=k/N>>0];A[_]=1;//一文字目
の行だけでもかまいません。
どうかよろしくお願いします。
No.1
- 回答日時:
こんばんは。
面白そうなのでやってみました。
最初に考えたのは、クローンを作ったりしているとメモリを食いそうなので、定義された配列を順に並び替えるだけで、結果を求められないかということ。
御質問文のコードはほとんど見てないので、考え方は多分違うでしょう。
clac部分は配列a[]の後ろからk個の全ての並び替えを出力するルーチンで、個数k-1で自分自身をcallしています。
init部は配列を初期定義しているだけなので、
var a = new Array("1","2","3","4","5","6","7");
みたいな1行でもすみます。 ので、若干コンパクトになっているかも。
(変数名を短くしたりしているのもあるので、ちゃんと比較はしていません)
さて、IE6で実験したところ、同様にn=8でアラートがでてしまいました。
resultを文字列で蓄えていると、大変長いものになる(n=8で40320行)ので、直接document.writeで表記すればよいかと試してみました(時間はこの方がかかると思う)が、結果は変わりませんでした。
それではと、出力をやめて、計算のみを行わせてみるとn=8はクリアできましたが、n=9で、やはりアラートが出てしまいました。
残念ながら、私の能力ではこのあたりまでで、あまりお役に立ちそうも無いですが、何かの参考にでもなれば…
<html>
<head>
<script type="text/javascript">
<!--
var a=[], al, result, count;
function init(){
al = parseInt(document.getElementById('val').value);
result = '想定範囲外'; count = 1;
if (al>0 && al<9) {
for (var i=0; i<al; i++) a[i] = i+1;
result = '計算対象配列:' + a.toString() + '<p>';
}
//document.write(result); //←直接出力
calc(al);
document.getElementById('result').innerHTML = result;
alert("calc end");
}
function calc(k){
if (k == 1) {
var s='000000' + (count++);
result += s.substr(s.length-7) + ': ' + a.toString() + '<br />';
//document.write(s.substr(s.length-7) + ': ' + a.toString() + '<br />'); //←直接出力
} else {
for (var n=0; n<k; n++){
calc(k-1);
var tmp = a[al-k];
for (var i=al-k; i<al-1; i++) a[i] = a[i+1];
a[al-1] = tmp;
}}
}
-->
</script>
</head>
<body>
<input type="text" id="val">
<input type="button" value="走査" onclick="init();">
<p />
<div id="result">ここに結果表示</div>
</body>
</html>
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) ファイル全てを .xlsm に変更したところ、プログラムが途中で落ちてしまっています 17 2022/12/07 12:03
- JavaScript 1日1回引けるJavaScriptおみくじについて 1 2022/12/12 22:28
- 英語 SPECS の所の LENGTH というのは、BARREL LENGTH なのか?全体の長さなのか? 1 2022/04/27 20:05
- JavaScript javascript作成してます。ラジオボタンで判定するコードを書いてます。 1 2023/07/18 11:03
- JavaScript EasyUIのSubGrid(jquery)におけるObjectに入れた連想配列について 1 2022/05/02 11:21
- C言語・C++・C# C#テキストボックスの文字を配列にいれてその後表示する 4 2022/07/17 04:47
- JavaScript 画像の表示位置 3 2022/12/23 08:25
- JavaScript javascriptのちょっとした動作不良(原因は突き止めたのですが) 1 2023/06/15 19:58
- Excel(エクセル) エクセル 自動計算 1 2023/01/30 13:28
- Perl perl このテキストファイルを簡単に配列に入れるには? 2 2022/04/27 20:24
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C#テキストボックスの文字を配...
-
jspからjavascriptの変数引継ぎ
-
HTMLで誕生石と星座をアラート...
-
【Google Apps Script】コード...
-
フォーム入力値の重複チェック
-
javascriptで行を抽出したいです。
-
Ajax Updaterでドラッグアンド...
-
同じIDで定義した要素の配列を...
-
javascriptで2つのArrayの...
-
どうすればresponseText結果を...
-
配列について、その要素を並べ...
-
[JS] setAttributeで保存される...
-
多次元配列とfor文について
-
React hooksが値を返して配列変...
-
JavaScriptの配列変数検索
-
javascriptからphpに配列データ...
-
javascript 変数名の連結をしたい
-
Javascriptで文字を順番に表示...
-
js 配列?
-
関数でy=g(x)のgとは何の略です...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
同じIDで定義した要素の配列を...
-
C#テキストボックスの文字を配...
-
jspからjavascriptの変数引継ぎ
-
javascript 変数名の連結をしたい
-
二次元配列を使って順位をだす...
-
React hooksが値を返して配列変...
-
undefinedを表示させない方法は...
-
フォーム入力値の重複チェック
-
javascriptで行を抽出したいです。
-
JavaScriptでの動的な多次元配...
-
多次元配列から最大値を1行また...
-
HTMLで誕生石と星座をアラート...
-
JSONデータを50音順でソートしたい
-
重複しないようにランダムで表...
-
1から20までの整数から、重複な...
-
JavaScriptにおける[] とか :...
-
gas 配列
-
【JavaScript】オブジェクト型...
-
WSH(Jscript)でファイル一覧
-
JavaScriptで簡単なクイズを作...
おすすめ情報