【Ruby】木構造を定義してみる
こんにちは、しきゆらです
今回は、Rubyで木構造を作ってみたので書いておきます
木構造とは
データ構造の一つで、データの階層構造を表したりデータを探しやすくするために用いられる
詳しくは、Wikipediaを参照 => 木構造 (データ構造)
卒研でデータの階層構造を定義したかったので作ってみました
想定しているデータ
想定していたデータは、「value,parent」というデータがたくさんあるCSV形式のファイルを読み込んで木構造を作るというもので
- 子ノードが複数存在する場合がある
- 最上位ノードが複数存在する場合がある
という感じでした
ファイルの中には、Aというデータの木構造とBという木構造、Cという木構造・・・というように
複数の木構造が1つのファイルの中に入っている状態です
例として以下のようなデータがあった場合は・・・
A,root B,root a1,A b1,B C,root a2,A b2,B c1,C
・A
—-a1
—-a2
・B
—-b1
—-b2
・C
—-c1
こんな感じにして欲しかったんです
上記の「最上位ノード」とは、例で言うところの「・A」のような「・」から始まっているノードのことです
作ったコード
木構造ということで調べてみると、出てくるのは2分木ばかり
ということで作ったものが以下のものです
# coding: utf-8 class Node attr_accessor :parent, :child, :value def initialize(value = 'root', parent = nil) @value = value @child = [] @parent = parent end def ==(node) @value == node.value end # 兄弟要素を返す def brothers unless @parent.nil? then @parent.child else nil end end # 子要素を追加 def add_child!(node) if self == node.parent then @child.push(node) else @child.each do |n| n.add_child!(node) end end end def to_s unless @parent.nil? then 'value: ' + @value else 'root' end end def search(value) # valueが一致するものを探す if @value == value then return self else @child.each do |n| node = n.search(value) if node then return node end end return nil end end end
各ノードには、そのノードがもつ値を表す「value」、親ノードを表す「parent」、子ノードを表す「child」を持っています
childに関しては、配列で管理しています
これは、子ノードに関する操作をeachなどの操作をしたかったから(自分で作ったクラスでもRubyっぽく振る舞って欲しかった)
ノードの持っているデータへのアクセサとして、parent、value、childを作成しました
また、そのノードの兄弟要素を取得したり(brothers)、特定の値を持ったノードを探すメソッド(search)を作りました
ファイルから木構造を作る
また、ファイルからデータを読み込んで木構造を返す関数(?)も作ってみました
def make_tree(file_path) node = Node.new childs = [] File.open(file_path).each_line do |lines| lines = lines.chomp.split(',') value = lines.first next if lines[0] == 'value' if lines.last == 'root' then t = Node.new(value, node) node.add_child!(t) childs.push(t) else childs.each do |n| if n.value == lines.last then tmp = Node.new(value, n) node.add_child!(tmp) childs.push(tmp) break end end end end return node end
この関数にファイルのパスを渡すと、ファイルの内容を取得して木構造をつくって返すようにしました
(各ノードにこの機能を持たせる必要はないので、Nodeクラス内で定義せず関数としてあります)
想定しているデータので書いたように、最上位ノードが複数存在する場合があるので
最上位ノードの親としてrootノードを作り、データを読み込んで木構造を作り、rootノードを返します
つまり、この関数で帰ってきたrootノードの子要素には最上位ノードが入っているので操作しやすくなっています
こんな感じで、必要としていたものは出来ました
自分でほしいと思っていたものができたのでかなり満足です
ここはこう書いたほうが見やすいよ、とか
ここの書き方危ないよ!などありましたら教えてください
おわり
ディスカッション
コメント一覧
まだ、コメントがありません