配列もCollectionも使わないデータ構造(Stack)
配列もCollectionも使わないデータ構造
久しぶりに
『VBA Developer's Handbook』を読んだ。
「Chapter 6」の「Creating Dynamic Data Structures Using Class Modules」のところに、実に面白いことが書いてあったので、やってみた。
Stackを二つのクラスモジュールで実現する
データの集合を取り扱う、となると、素人考えでは、配列を使う方法か、Collection
を使う方法しか思いつかない。
しかし、全然違うアプローチが説明されていたので、つい夢中で読んでしまった。英語苦手なくせに。
とりあえず、String
型のデータを出し入れするStackを二つのクラスモジュールで実現する。
まず、クラスモジュールを二つ用意し、一方にはStringStack
、もう一方にStackString
と名前をつける。
StringStack
がStack全体、StackString
がStackに積まれている一つ一つの要素を表す。
クラスモジュール StringStack
Option Explicit Private topItem As StackString Public Property Get Top() As String If ItemExists Then Top = topItem.Value Else Top = "" End If End Property Public Property Get ItemExists() As Boolean ItemExists = Not (topItem Is Nothing) End Property Public Sub Push(ByVal argValue As String) Dim newTopItem As New StackString newTopItem.Value = argValue Set newTopItem.NextItem = topItem Set topItem = newTopItem End Sub Public Function Pop() As String Dim ret As Variant If Me.ItemExists Then ret = topItem.Value Set topItem = topItem.NextItem End If Pop = ret End Function
まず、こちらはStack全体を表すStringStack
クラス。
プロパティが二つ。
Top
プロパティは、Stackのてっぺんに積んであるアイテムの値。今回はString
型に限定している。
ItemExists
プロパティは、Stackにアイテムがあるかどうかを表す。
で、メソッドが二つ。
Push
メソッドは、新しいアイテムをStackのてっぺんに積む。
Pop
メソッドは、てっぺんにあるアイテムを除去するとともに、その値を取得する。
クラスモジュール StackString
Option Explicit Private value_ As String Private nextItem_ As StackString Public Property Let Value(ByVal argValue As String) value_ = argValue End Property Public Property Get Value() As String Value = value_ End Property Public Property Set NextItem(ByVal argItem As StackString) Set nextItem_ = argItem End Property Public Property Get NextItem() As StackString Set NextItem = nextItem_ End Property
こちらは、Stackに積まれているそれぞれのアイテムを表現するクラス。
Read/Writeのプロパティが二つ。
Value
プロパティは、アイテムの値。今回はString
型に限定している。
NextItem
プロパティは、自分自身の一つ下に積まれているアイテムを表す。
使ってみる
標準モジュールに次のようなコードを書いて、StringStack
クラスを使ってみる。
リスト1 標準モジュール
Private Sub testStringStack() Dim strStack As New StringStack '……(1)' With strStack Call .Push("1番サード岩鬼") '……(2)' Debug.Print .Top '……(3)' Call .Push("2番セカンド殿馬") Debug.Print .Top Call .Push("3番レフト微笑") Debug.Print .Top Call .Push("4番キャッチャー山田") Debug.Print .Top Debug.Print "====================" '……(4)' Do While .ItemExists '……(5)' Debug.Print .Pop Loop End With End Sub
まず、(1)の
Dim strStack As New StringStack
で、StringStack
クラスのインスタンスを用意する。
その後、(2)の
With strStack Call .Push("1番サード岩鬼") End With
で、Push
メソッドを用いて、「1番サード岩鬼
」というデータ(笑)を持ったアイテム(StackString
オブジェクト)がStackに積まれる。
そうしておいて、(3)の
With strStack Debug.Print .Top End With
で、Top
プロパティの値を出力する。この時点でStackのてっぺんにあるアイテムの値は先ほどの「1番サード岩鬼
」のはず。
同様に、二つ目、三つ目、四つ目のアイテムを追加していく。
ここで、一旦(4)の
Debug.Print "===================="
で、イミディエイト ウインドウに区切り線を入れる。
後は、(5)の
With strStack Do While .ItemExists Debug.Print .Pop Loop End With
で、ItemExists
プロパティがFalse
になるまで、すなわちStackに積まれたアイテムが無くなるまで、〈てっぺんのアイテムの値を出力=てっぺんのアイテムを除去〉を繰り返す。
リスト1を実行すると、
Stackの場合、上へ上へと積み重ねたものを、上から順番に取り出すことになるので、こうなる。
おわりに
詳しい仕組みの説明は今のところ省略しますが、配列もCollection
も使わずに、データの集合を表現するって、何かスゴくないですか?
私はちょっと感動しています。
StackString
オブジェクトの内部にStackString
オブジェクトを持たせることによって、マトリョーシカ人形のような要領で複数のデータを数珠つなぎのように持たせる、ということなんですが、非常に面白いアイディアだと思います。
この調子で、Queueとか、OrderedLinkedListなんかも作っていくと、クラスモジュールの練習に良さそうです。