ここでは非ジェネリックなコレクション型System.Collections.Stackクラスについて解説します。 Stackクラスを使用するよりも、Stackに相当するジェネリックなコレクション型System.Collections.Generic.Stack<T>クラスを使用することを強く推奨します。
Stack
System.Collections.Stackクラスは、後入れ先出し(LIFO: Last-In, First-Out)のデータ構造を持つスタックを提供するコレクションクラスです。 Stackクラスでは、ArrayListクラスやHashtableクラスとは異なり、コレクションにどのようなオブジェクトが格納されているかということより、どのような順番で格納されたかと言うことの方が重要視されます。
基本的な操作
.NET FrameworkにおけるStackクラスの概要を見ていきます。 Stackに要素を追加するプッシュの操作はPushメソッド、Stackから要素を取り出すポップの操作はPopメソッドで行います。 Stackから要素をポップすると、取り出した要素はStackから削除されます。 本を一冊ずつ積み上げる作業がプッシュ、積まれた本を一冊ずつ上から取っていく作業がポップに相当するとイメージするとよいと思います。
また、Peekメソッドを使うと、Stackの内容はそのままで(削除されずに)先頭にある要素を取得できます。 Stackの内容が空の場合に、PopメソッドやPeekメソッドを呼び出すとInvalidOperationExceptionがスローされます。 Stackの内容を空にするには、Clearメソッドを使います。 Stackに指定した内容の要素が含まれているか調べるには、Containsメソッドを使います。
Stackに現在いくつの要素が含まれているかを知るにはCountプロパティを参照します。 ArrayListなどと同様、Stackには任意の数の要素をプッシュできます。 Stack内部の容量はプッシュの際に自動的に拡充されます。 ポップの際に要素数が減っても、Stack内部で確保されている容量は減ることはありません。
using System;
using System.Collections;
class Sample {
static void Main()
{
Stack s = new Stack();
// Stackに要素をPush
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
s.Push("Dave");
s.Push("Eve");
Console.WriteLine("Count: {0}", s.Count);
// Stackの先頭にある要素をPeek
Console.WriteLine("Peek: {0}", s.Peek());
Console.WriteLine("Count: {0}", s.Count);
// Stackの先頭にある要素をPop
Console.WriteLine("Pop: {0}", s.Pop());
Console.WriteLine("Pop: {0}", s.Pop());
Console.WriteLine("Count: {0}", s.Count);
// Stackに"Alice", "Eve"が含まれるか調べる
Console.WriteLine(s.Contains("Alice"));
Console.WriteLine(s.Contains("Eve"));
// Stackに"Fran", "Gordon"をPush
s.Push("Fran");
s.Push("Gordon");
Console.WriteLine();
// Stackが空になるまで内容をPop
while (0 < s.Count) {
Console.WriteLine(s.Pop());
}
}
}
Imports System
Imports System.Collections
Class Sample
Shared Sub Main()
Dim s As New Stack()
' Stackに要素をPush
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
s.Push("Dave")
s.Push("Eve")
Console.WriteLine("Count: {0}", s.Count)
' Stackの先頭にある要素をPeek
Console.WriteLine("Peek: {0}", s.Peek())
Console.WriteLine("Count: {0}", s.Count)
' Stackの先頭にある要素をPop
Console.WriteLine("Pop: {0}", s.Pop())
Console.WriteLine("Pop: {0}", s.Pop())
Console.WriteLine("Count: {0}", s.Count)
' Stackに"Alice", "Eve"が含まれるか調べる
Console.WriteLine(s.Contains("Alice"))
Console.WriteLine(s.Contains("Eve"))
' Stackに"Fran", "Gordon"をPush
s.Push("Fran")
s.Push("Gordon")
Console.WriteLine()
' Stackが空になるまで内容をPop
While 0 < s.Count
Console.WriteLine(s.Pop())
End While
End Sub
End Class
Count: 5 Peek: Eve Count: 5 Pop: Eve Pop: Dave Count: 3 True False Gordon Fran Charlie Bob Alice
一番最後にStackに入れた要素は一番始めに取り出されるという特性上、要素を入れた順番とは逆の順番で表示されている点に注目してください。
列挙操作
Stackでも、foreach文による列挙ができるようになっていますが、インデクサはサポートされないのでfor文による列挙は出来ません。 foreach文による列挙を行う場合は、Popしたときと同じ順で列挙されますが、当然要素の削除は行われません。
using System;
using System.Collections;
class Sample {
static void Main()
{
Stack s = new Stack();
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
s.Push("Dave");
s.Push("Eve");
foreach (object e in s) {
Console.WriteLine(e);
}
Console.WriteLine("Count: {0}", s.Count);
Console.WriteLine();
while (0 < s.Count) {
Console.WriteLine(s.Pop());
}
Console.WriteLine("Count: {0}", s.Count);
}
}
Imports System
Imports System.Collections
Class Sample
Shared Sub Main()
Dim s As New Stack()
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
s.Push("Dave")
s.Push("Eve")
For Each e As Object In s
Console.WriteLine(e)
Next
Console.WriteLine("Count: {0}", s.Count)
Console.WriteLine()
While 0 < s.Count
Console.WriteLine(s.Pop())
End While
Console.WriteLine("Count: {0}", s.Count)
End Sub
End Class
Eve Dave Charlie Bob Alice Count: 5 Eve Dave Charlie Bob Alice Count: 0
配列からの変換
配列からStackに変換するには、コンストラクタが使えます。 コンストラクタに配列を指定した場合、Stackの内容は配列の要素を先頭から一つずつPushした場合と同じ内容になります。
using System;
using System.Collections;
class Sample {
static void Main()
{
string[] arr = new string[] {"Alice", "Bob", "Charlie", "Dave", "Eve"};
Stack s = new Stack(arr); // 配列からStackを作成
while (0 < s.Count) {
Console.WriteLine(s.Pop());
}
}
}
Imports System
Imports System.Collections
Class Sample
Shared Sub Main()
Dim arr() As String = New String() {"Alice", "Bob", "Charlie", "Dave", "Eve"}
Dim s As New Stack(arr) ' 配列からStackを作成
While 0 < s.Count
Console.WriteLine(s.Pop())
End While
End Sub
End Class
Eve Dave Charlie Bob Alice
配列への変換・コピー
Stackから配列へ変換する場合にはToArrayメソッドやCopyToメソッドが使えますが、ArrayListから配列の変換の場合とは異なり、object型の配列への変換しかサポートされていません。 変換・コピーした後の配列の内容は、Stackの内容を一つずつPopした場合と同じ内容になります。 また、変換・コピーの前後でStackの内容は変化しません。
using System;
using System.Collections;
class Sample {
static void Main()
{
Stack s = new Stack();
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
s.Push("Dave");
s.Push("Eve");
// 配列に変換
object[] arr1 = s.ToArray();
for (int i = 0; i < arr1.Length; i++) {
Console.WriteLine("arr1[{0}]: {1}", i, arr1[i]);
}
Console.WriteLine("Count: {0}", s.Count);
// 配列にコピー
object[] arr2 = new object[s.Count];
s.CopyTo(arr2, 0);
for (int i = 0; i < arr2.Length; i++) {
Console.WriteLine("arr2[{0}]: {1}", i, arr2[i]);
}
Console.WriteLine("Count: {0}", s.Count);
}
}
Imports System
Imports System.Collections
Class Sample
Shared Sub Main()
Dim s As New Stack()
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
s.Push("Dave")
s.Push("Eve")
' 配列に変換
Dim arr1() As Object = s.ToArray()
For i As Integer = 0 To arr1.Length - 1
Console.WriteLine("arr1[{0}]: {1}", i, arr1(i))
Next
Console.WriteLine("Count: {0}", s.Count)
' 配列にコピー
Dim arr2(s.Count) As Object
s.CopyTo(arr2, 0)
For i As Integer = 0 To arr2.Length - 1
Console.WriteLine("arr2[{0}]: {1}", i, arr2(i))
Next
Console.WriteLine("Count: {0}", s.Count)
End Sub
End Class
arr1[0]: Eve arr1[1]: Dave arr1[2]: Charlie arr1[3]: Bob arr1[4]: Alice Count: 5 arr2[0]: Eve arr2[1]: Dave arr2[2]: Charlie arr2[3]: Bob arr2[4]: Alice Count: 5