【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ノードの子要素には最上位ノードが入っているので操作しやすくなっています
こんな感じで、必要としていたものは出来ました
自分でほしいと思っていたものができたのでかなり満足です
ここはこう書いたほうが見やすいよ、とか
ここの書き方危ないよ!などありましたら教えてください
おわり


ディスカッション
コメント一覧
まだ、コメントがありません