木を綺麗に描画するアルゴリズム
TRANSCRIPT
![Page 1: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/1.jpg)
木を綺麗に描画するアルゴリズム
![Page 2: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/2.jpg)
どうやって木を描画するか?
• 木はグラフの一部なので描画方法はいろいろ
• どうやったら綺麗に描画できる?
• 以下,とりあえず2分木を対象
![Page 3: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/3.jpg)
描画原則
1. 親は子より上に描画特に2分木なら左の子は親より左,右の子は親より右に描画
2. 辺は交差しない
3. 同じ深さのノードは同じ高さで描画
![Page 4: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/4.jpg)
描画位置の求め方
• y方向はノード自身の深さ
• 問題はx方向の位置
![Page 5: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/5.jpg)
(多分)一番簡単な方法
• 木をpre-orderで探索
• x = 0から初めて探索していったノードから順に左からx方向の値を割り振る
• 一説によるとknuthが考えたらしい (というかknuthが1971年に出した論文のサンプルコードで使われていた手法)
![Page 6: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/6.jpg)
(多分)一番簡単な方法
![Page 7: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/7.jpg)
(多分)一番簡単な方法
![Page 8: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/8.jpg)
(多分)一番簡単な方法の問題• 木がだいたいバランスしている場合はこれでも十分
• でも,木が偏っていると不格好になりがち
• 何がいけないのか?
1. 深さに対するノード数によらずx方向が決定される=> 結果として横にひろがりやすい
2. 2分木なのに親が子の中央に位置していない
![Page 9: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/9.jpg)
描画原則 改1. 親は子より上に描画
特に2分木なら左の子は親より左,右の子は親より右に描画
2. 辺は交差しない
3. 同じ深さのノードは同じ高さで描画
4. なるべく狭く描画する
5. 親は子の中央に位置させる
![Page 10: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/10.jpg)
狭く描画する
• とりあえず狭く描画したい各深さごとに使えるxのインデックスを保持すればOK
• pre-orderで探索して,各ノードの深さで配置可能な場所に左から配置する
![Page 11: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/11.jpg)
狭く描画する
![Page 12: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/12.jpg)
親を子の中央に配置する• pre-orderで探索するとノードを描画するとき右の子の位置が確定していない
• post-orderで探索し,
• 葉にはその深さで配置可能な場所に左詰めで配置
• 親は子ノードの中央に配置このとき,親の位置が親の深さで配置可能な場合より左の場合には,その親をルートとするサブツリー全体をその分だけ右にシフトする
![Page 13: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/13.jpg)
親を子の中央に配置する
![Page 14: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/14.jpg)
この方法の問題点
• これで割とよく描画できる!
• でもさっきの例をよく見ると木の構造が対称なのに対称に描画されていない..
![Page 15: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/15.jpg)
描画原則 改二1. 親は子より上に描画
特に2分木なら左の子は親より左, 右の子は親より右に描画
2. 辺は交差しない
3. 同じ深さのノードは同じ高さで描画
4. なるべく狭く描画する
5. 親は子の中央に位置させる
6. 任意のサブツリーは場所によらず同じように描画する
![Page 16: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/16.jpg)
Tilford-Reingold アルゴリズム• 1980年考案
• post-order で探索し,
• ノードが葉ならそのノードのx位置は0とする
• そうでなければ,右の子を左の子にできるだけ近づける
• 親の位置を子ノードの中央に設定
• 単純そうに見えるが,実際には親の位置を決定するのに少し工夫が必要
• ちなみに,グラフ描画アルゴリズムのFruchterman-ReingoldアルゴリズムのReingoldと同じ人
![Page 17: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/17.jpg)
Tilford-Reingold アルゴリズム
![Page 18: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/18.jpg)
描画アルゴリズムのオーダー
• Tilford-Reingold アルゴリズムは,サブツリーのシフトが再帰的が発生するが,少し計算を工夫することでO(n^2)
• Tilford-Reingold を改良して,木の描画をO(n)で配置するアルゴリズムが考案されているらしい(末尾の文献を参照)
![Page 19: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/19.jpg)
m分木への拡張
• 今までは2分木を対称としていたが,Tilford-Reingoldアルゴリズムをm分木に拡張するのはそれほど難しくない(はず)
• ようするに子の中央に親を配置するのがポイント
![Page 20: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/20.jpg)
ところで,DOT• グラフ記述言語ex)
• Graphvizの内部で使用
• これで書いておけばGraphvizで描画できる(他にも対応しているものはいろいろ)
• いちいちアルゴリズムを実装していられない時に
• DOTはあくまでグラフ描画用だが,Graphvizで木構造のレイアウトとして描画することができるらしい
![Page 21: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/21.jpg)
DOT
![Page 22: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/22.jpg)
(補足)木の描画方法の超簡単な歴史
• 1971年: knuthの論文に描画のソースコードが載るもっと前から何かあったかも
• 1979年: C.WetherellとA.Shannonが木の描画方法に関する論文を発表.これ以降の論文の基礎になる (ちゃんと読んで無いけど多分このスライドの親を中央に配置する方法を発表)
• 1980年: Tilford-Reingold アルゴリズム
• 1990年: Tilford-Reingold アルゴリズムを改良した方法をJ.Q.Walkerが発表.
• 2006年: Walker アルゴリズムがO(n^2)だったものを線形にしたアルゴリズム(?)をC.Bucheimらが考案ちゃんとやるならこれを読めば良さげ
![Page 23: 木を綺麗に描画するアルゴリズム](https://reader033.vdocuments.pub/reader033/viewer/2022052901/556a5fc4d8b42a7a138b5326/html5/thumbnails/23.jpg)
参考文献• Bill Mil, Drawing Presentable Trees, http://billmill.org/pymag-trees/#foot1木の描画方法についてまとまっています.今回の作成にあたり一番参考にしました
• C. Wetherell and A. Shannon. 1979. Tidy Drawings of Trees. IEEE Trans. Softw. Eng. 5, 5 (September 1979), 514-520. DOI=10.1109/TSE.1979.234212
• Reingold, Edward M.; Tilford, J.S., "Tidier Drawings of Trees," Software Engineering, IEEE Transactions on , vol.SE-7, no.2, pp.223,228, March 1981. doi: 10.1109/TSE.1981.234519
• J. Q. Walker, II. 1990. A node-positioning algorithm for general trees. Softw. Pract. Exper. 20, 7 (July 1990), 685-705. DOI=10.1002/spe.4380200705
• Christoph Buchheim, Michael Jünger, and Sebastian Leipert. 2006. Drawing rooted trees in linear time. Softw. Pract. Exper. 36, 6 (May 2006), 651-665. DOI=10.1002/spe.v36:6