2007-10-15
■[javascript] 「再帰→ループ」の変換が大変だった件
まず、ループは再帰で表現できる
ループというのはすべて再帰呼び出しで表現できる。
たとえば、コレは
var array = [1, 2, 3]; for (var i = 0; i < array.length; i ++) alert(array[i]);
こんな感じになる
(function f(array, i) { if (i < array.length) { alert(array[i]); return f(array, i+1); } })([1, 2, 3], 0);
もし、 array がこの目的以外に使われないならコッチのがキレイかも
(function f(array) { alert(array.shift()); if (array.length) return f(array); })([1, 2, 3]);
ということは、再帰はループで表現できるはず
ということで、 document ノードから全部の DOM を再帰的に辿っていく例をループで表現してみようと思った
まずは、元のコード
(function f(node) { console.log(node); for (node = node.firstChild; node; node = node.nextSibling) f(node); })(document);
これをループで表現してみる。
(function f(node) { console.log(node); node = node.firstChild; while (node) { f(node); node = node.nextSibling; } })(document);
次に、 function を goto 文とスタックに分解。
var stack = []; var node = document; f: console.log(node); node = node.firstChild; while (node) { stack.push(node); goto f; ret: node = node.nextSibling; } node = stack.pop(); if (stack.length) goto ret;
次に、 f から goto f をループで表現します。 ret: 以下の部分は外に出します。
var stack = []; var node = document; while (true); console.log(node); node = node.firstChild; label0: if (!node) goto label1; stack.push(node); } ret: node = node.nextSibling; goto label0; label1: node = stack.pop(); if (stack.length) goto ret;
だんだんコードがスパゲッティになってきました。。
次に、 ret には goto 文以外で到達するケースがないため、自由に移動できます。
var stack = []; var node = document; while (true) { console.log(node); node = node.firstChild; label0: if (!node) goto label1; stack.push(node); } label1: node = stack.pop(); if (stack.length) goto ret; else goto end; ret: node = node.nextSibling; goto label0; end:
次に goto label1 を break にして、 goto ret を削除します。
var stack = []; var node = document; while (true) { console.log(node); node = node.firstChild; label0: if (!node) break; stack.push(node); } node = stack.pop(); if (stack.length) { node = node.nextSibling; goto label0; }
次に、 label0 を while ループの外に出します。無限ループは巻き紙のようなものなので、一行ずつ上にずらして一番上の行を外に出していけば OK です。
var stack = []; var node = document; console.log(node); node = node.firstChild; label0: while (true) { if (!node) break; stack.push(node); console.log(node); node = node.firstChild; } node = stack.pop(); if (stack.length) { node = node.nextSibling; goto label0; }
次に、 goto label0 をループで表現します。
var stack = []; var node = document; console.log(node); node = node.firstChild; while (true) { while (true) { if (!node) break; stack.push(node); console.log(node); node = node.firstChild; } node = stack.pop(); if (stack.length) { node = node.nextSibling; } else break; }
あとは、少しコードをキレイにして
var stack = []; var node = document; console.log(node); node = node.firstChild; while (true) { while (node) { stack.push(node); console.log(node); node = node.firstChild } node = stack.pop(); if (!stack.length) break; node = node.nextSibling; }
はい!完成!わーわーぱちぱちぱち。
まとめ
トラックバック - http://d.hatena.ne.jp/amachang/20071015/1192435915
リンク元
- 107 http://b.hatena.ne.jp/
- 100 http://d.hatena.ne.jp/
- 90 http://reader.livedoor.com/reader/
- 89 http://b.hatena.ne.jp/entrylist?sort=hot
- 37 http://jyouhouya3.sakura.ne.jp/
- 27 http://www.google.co.jp/ig?hl=ja
- 26 http://himazin.jp/
- 20 http://crocro.com/
- 18 http://jyouhouya3.sakura.ne.jp/index.html
- 18 http://www.pluto.dti.ne.jp/~rinou/
おとなり日記
- 2007-10-15 DenkiYagi 3/13 23%
- 2007-10-14 ブックマクロ開発に 3/23 13%
- 2007-10-14 natu_nの日記 3/27 11%
- 2007-10-14 ケーズメモ 5/53 9%
- 2007-10-15 WEB開発日記 7/211 3%
- 2007-10-15 Webアプリを作ろう 8/351 2%
- 2007-10-14 WEB開発日記 3/149 2%
- 2007-10-15 seesaaの日記 3/160 1%
- 2007-10-15 土下座エージェント日記 東京謝財(6)2001-58-66315 4/778 0%
- 2007-10-15 補天鳥保管庫 4/630 0%