- ジェネリックコレクション ページ一覧
Stack
データ構造としてのスタック(stack)には、二つの操作プッシュ(push)とポップ(pop)が定義されます。 プッシュはスタックの先頭に要素を追加する操作で、ポップはスタックの先頭から要素を取り出す操作です。 この二つの操作により後入れ先出し(LIFO: Last-In, First-Out)のデータ構造が実現されます。
例を挙げると、本を一冊ずつ上に積んでいく作業がプッシュ、積まれた本を一冊ずつ上から取っていく作業がポップに相当します。
.NETにおいて、スタックのデータ構造を持つコレクションクラスがSystem.Collections.Generic.Stackクラスです。
Stackクラスに要素を追加するプッシュの操作はPushメソッド、Stackから要素を取り出すポップの操作はPopメソッドで行います(§.プッシュ操作とポップ操作 (Push/Pop))。 Stackから要素をポップすると、取り出した要素はStackから削除されます。 Stackから要素を取り出さずに参照だけ行う場合はPeekメソッドを使います。 Stackに現在いくつの要素が含まれているかを知るにはCountプロパティを参照します。
ListクラスやDictionaryクラスとは異なり、Stackクラスでは要素が格納された順序が大きな意味を持ちます。 最初(または最後)に格納された要素のみに着目するため、インデックスを指定した要素へのアクセス(ランダムアクセス)はできません(§.インデックス付きの列挙操作)。 また、Stackに格納される要素は格納された順に並べられ、格納された後はその順序を並べ替えることはできません。
Listなどと同様、Stackは可変長のコレクションであるため任意の数の要素をプッシュできます。 プッシュの際、Stack内部の容量は必要に応じて自動的に拡充されます。 ポップの際に要素数が減っても、明示的に指示しない限りはStack内部で確保されている容量が減ることはありません。
JavaScriptなど他のスクリプト言語では、配列をスタックやキューのように扱うための操作が用意されているものもありますが、Stackクラスではスタックとしての操作しか提供されません。 つまり、Stackクラスに対してunshift/shift操作を行うようなメソッドは用意されていません。 そういった操作を行いたい場合はQueueクラスを使用します。
プッシュ操作とポップ操作 (Push/Pop)
Stackクラスでは、PushメソッドでStackに対して要素の追加(プッシュ操作)、PopメソッドでStackからの要素の取り出し(ポップ操作)を行います。
次の例では、3つの要素をStackにプッシュし、その後Stackが空になるまでポップしています。 スタックでは一番最後に入れた要素は一番始めに取り出される(Last-In, First-Out)という特性上、要素を入れた順番とは逆の順番で表示されている点に注目してください。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
var s = new Stack<string>();
// Stackに要素をPush
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
// Stackが空になるまで内容をPop
while (0 < s.Count) {
Console.WriteLine(s.Pop());
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
' Stackに要素をPush
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
' Stackが空になるまで内容をPop
While 0 < s.Count
Console.WriteLine(s.Pop())
End While
End Sub
End Class
Charlie Bob Alice
Stackでもforeachによる列挙操作を行うことができます。 Stackの内容をforeachで列挙すると、Pushしたのと逆順、つまりPopする場合と同様の順序で要素が列挙されます。
空のStackに対するPop
Stackが空のときにPopメソッドを呼び出すと、null
/Nothing
が返されるのではなく、例外InvalidOperationExceptionがスローされます。 このため、Popメソッドの戻り値からStackが空だったかどうかを判断することはできません。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
var s = new Stack<string>();
Console.WriteLine($"Count = {s.Count}"); // 0
// Stackが空の状態でPop操作を行うとInvalidOperationExceptionがスローされる
Console.WriteLine(s.Pop());
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
Console.WriteLine($"Count = {s.Count}") ' 0
' Stackが空の状態でPop操作を行うとInvalidOperationExceptionがスローされる
Console.WriteLine(s.Pop())
End Sub
End Class
Count = 0 Unhandled exception. System.InvalidOperationException: Stack empty. at System.Collections.Generic.Stack`1.ThrowForEmptyStack() at System.Collections.Generic.Stack`1.Pop() at Sample.Main() in /home/smdn/samplecodes/dotnet/cs/test.cs:line 12
Stackが空かどうかに関わらず、例外をスローせずにポップ操作を試行するメソッドとしてTryPopメソッドが用意されています。
このほか、PopメソッドでInvalidOperationExceptionを避けるには、Popメソッドを呼び出す前にCountプロパティを参照して、要素が1つ以上格納されているかチェックするようにします。
ポップ操作の試行 (TryPop)
Stackが空のときにPopメソッドを呼び出すと、例外InvalidOperationExceptionがスローされます。 一方、TryPopメソッドを使うと、Stackが空の場合でも例外をスローさせずにポップ操作を試行することができます。 TryPopメソッドは.NET Standard 2.1/.NET Core 2.0以降で使用できます。
TryPopメソッドは、成功した場合はポップした要素をoutパラメータで出力し、戻り値true
を返します。 失敗した場合、つまりStackが空だった場合は単に戻り値false
を返します。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
var s = new Stack<string>();
// Stackに要素をPush
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
// Stackが空になるまで内容をPop
// (Stackが空の場合、TryPopメソッドはfalseを返す)
while (s.TryPop(out var e)) {
Console.WriteLine(e);
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
' Stackに要素をPush
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
' Stackが空になるまで内容をPop
' (Stackが空の場合、TryPopメソッドはFalseを返す)
Dim e As String = Nothing
While s.TryPop(e)
Console.WriteLine(e)
End While
End Sub
End Class
Charlie Bob Alice
ピーク操作 (Peek)
PopメソッドはStackの先頭にある要素を取り出して取得しますが、Peekメソッドを使うとStackの内容を変更せず(Stackから削除せず)に先頭にある要素を参照できます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
var s = new Stack<string>();
// Stackに要素をPush
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
// Stackの内容を変更せずに先頭にある要素を参照する
Console.WriteLine(s.Peek());
// PeekメソッドはStackから要素を取り出さずに参照するので、要素数は変わらない
Console.WriteLine($"Count = {s.Count}"); // 3
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
' Stackに要素をPush
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
' Stackの内容を変更せずに先頭にある要素を参照する
Console.WriteLine(s.Peek())
' PeekメソッドはStackから要素を取り出さずに参照するので、要素数は変わらない
Console.WriteLine($"Count = {s.Count}")
End Sub
End Class
Charlie Count = 3
foreachなどによる列挙操作では、Stackの状態を変更せずにStackに格納されているすべての内容を参照することができます。
Popメソッドと同様に、Stackの内容が空の場合にPeekメソッドを呼び出すと、例外InvalidOperationExceptionがスローされます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
var s = new Stack<string>();
Console.WriteLine($"Count = {s.Count}"); // 0
// Stackが空の状態でPeek操作を行うとInvalidOperationExceptionがスローされる
Console.WriteLine(s.Peek());
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
Console.WriteLine($"Count = {s.Count}") ' 0
' Stackが空の状態でPeek操作を行うとInvalidOperationExceptionがスローされる
Console.WriteLine(s.Peek())
End Sub
End Class
Count = 0 Unhandled exception. System.InvalidOperationException: Stack empty. at System.Collections.Generic.Stack`1.ThrowForEmptyStack() at System.Collections.Generic.Stack`1.Peek() at Sample.Main() in /home/smdn/samplecodes/dotnet/cs/test.cs:line 12
したがって、Peekメソッドの戻り値を見てStackが空かどうかを判断することはできません。 Stackが空であるかどうかを判断するにはPeekメソッドではなくCountプロパティを参照します。
ピーク操作の試行 (TryPeek)
TryPopメソッドと同様に、TryPeekメソッドを使うと、Stackが空の場合でも例外をスローさせずにピーク操作を試行することができます。 TryPeekメソッドは.NET Standard 2.1/.NET Core 2.0以降で使用できます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
var s = new Stack<string>();
// Stackに要素を追加する
s.Push("Alice");
// Stackに要素がある状態で先頭の要素を参照する
if (s.TryPeek(out var e1))
Console.WriteLine(e1);
else
Console.WriteLine("(empty)");
// Stackから要素を取り出す
s.Pop();
// Stackが空の状態で先頭の要素を参照する
if (s.TryPeek(out var e2))
Console.WriteLine(e2);
else
Console.WriteLine("(empty)");
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
' Stackに要素を追加する
s.Push("Alice")
' Stackに要素がある状態で先頭の要素を参照する
Dim e1 As String = Nothing
If s.TryPeek(e1) Then
Console.WriteLine(e1)
Else
Console.WriteLine("(empty)")
End If
' Stackから要素を取り出す
s.Pop()
' Stackが空の状態で先頭の要素を参照する
Dim e2 As String = Nothing
If s.TryPeek(e2) Then
Console.WriteLine(e2)
Else
Console.WriteLine("(empty)")
End If
End Sub
End Class
Alice (empty)
要素数の取得 (Count)
Stackに現在格納されている要素の数を取得するには、Countプロパティを参照します。 Stackが空の状態、何も格納されていない状態の場合は、当然Countプロパティは0となります。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
var s = new Stack<string>();
// Stackの要素数を取得して出力
Console.WriteLine($"Count = {s.Count}"); // 0
// Stackに要素をPush
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
// Stackの要素数を取得して出力
Console.WriteLine($"Count = {s.Count}"); // 3
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
' Stackの要素数を取得して出力
Console.WriteLine($"Count = {s.Count}") ' 0
' Stackに要素をPush
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
' Stackの要素数を取得して出力
Console.WriteLine($"Count = {s.Count}") ' 3
End Sub
End Class
Count = 0 Count = 3
要素の有無の検証 (Contains)
Stackに指定した内容の要素が含まれているか調べるには、Containsメソッドを使います。
ただし、このメソッドではIEqualityComparerを指定できないため、Dictionaryのように大文字小文字の違いを無視して比較するといったことはできません。 そういった比較条件を指定した上で要素が含まれているかを調べるには、LINQの拡張メソッドContainsなどを使う必要があります。
using System;
using System.Collections.Generic;
using System.Linq;
class Sample {
static void Main()
{
var s = new Stack<string>();
// Stackに要素をPush
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
// Stackに"CHARLIE"が含まれているか
// (大文字小文字の違いが意識されるため、"CHARLIE"は含まれないものとして扱われる)
Console.WriteLine(s.Contains("CHARLIE"));
// Stackに"CHARLIE"が含まれているか
// (LINQのContainsメソッドを使い、大文字小文字の違いを無視して調べる)
Console.WriteLine(s.Contains("CHARLIE", StringComparer.OrdinalIgnoreCase));
}
}
Imports System
Imports System.Collections.Generic
Imports System.Linq
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
' Stackに要素をPush
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
' Stackに"CHARLIE"が含まれているか
' (大文字小文字の違いが意識されるため、"CHARLIE"は含まれないものとして扱われる)
Console.WriteLine(s.Contains("CHARLIE"))
' Stackに"CHARLIE"が含まれているか
' (LINQのContainsメソッドを使い、大文字小文字の違いを無視して調べる)
Console.WriteLine(s.Contains("CHARLIE", StringComparer.OrdinalIgnoreCase))
End Sub
End Class
False True
文字列の比較オプション(StringComparer)については文字列と比較オプション・カルチャの並べ替え規則、IEqualityComparer<T>インターフェイスによる同値比較のカスタマイズについては等価性の定義と比較 §.IEqualityComparer, IEqualityComparer<T>を参照してください。
同一の要素の格納
Stackには同一の要素(値)を複数格納することができます。 同じ要素を複数回Pushした場合でもそれぞれ個別の要素として扱われます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
var s = new Stack<string>();
s.Push("Alice");
s.Push("Bob");
s.Push("Bob"); // 同一の要素をPush
foreach (var e in s) {
Console.WriteLine(e);
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
s.Push("Alice")
s.Push("Bob")
s.Push("Bob") ' 同一の要素をPush
For Each e As String In s
Console.WriteLine(e)
Next
End Sub
End Class
Bob Bob Alice
null
/Nothing
の格納
stringなどの参照型を格納するStackの場合はnull
/Nothing
を格納することもできます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
// string(参照型)のStack
var s = new Stack<string>();
// nullをPushする
s.Push(null);
// Pushした内容をPeekする
Console.WriteLine(s.Peek() ?? "(null)");
}
}
(null)
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
' String(参照型)のStack
Dim s As New Stack(Of String)()
' NothingをPushする
s.Push(Nothing)
' Pushした内容をPeekする
If s.Peek() Is Nothing Then
Console.WriteLine("(Nothing)")
Else
Console.WriteLine(s.Peek())
End If
End Sub
End Class
(Nothing)
intなどの値型を格納するStackの場合、C#ではnull
を格納することはできません。 VBではNothing
を格納しようとすると、Nothing
そのものではなく、0
などその型のデフォルト値が格納されます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
// int(値型)のStack
var s = new Stack<int>();
// nullをPushしようとする
s.Push(null); // error CS1503: 引数 1: は '<null>' から 'int' へ変換することはできません。
// Pushした内容をPeekする
Console.WriteLine(s.Peek());
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
' Integer(値型)のStack
Dim s As New Stack(Of Integer)()
' NothingをPushする
s.Push(Nothing)
' Pushした内容をPeekする
Console.WriteLine(s.Peek())
End Sub
End Class
0
値型の値を格納するStackで、値が空であることを表すためにnull
/Nothing
を格納したいといった場合には、ヌル許容型を用いることができます。
内容のクリア (Clear)
Clearメソッドを呼び出すことで、Stackの内容を空にすることができます。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
var s = new Stack<string>();
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
Console.WriteLine($"Count = {s.Count}");
// Stackの内容をクリア
s.Clear();
Console.WriteLine($"Count = {s.Count}");
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
Console.WriteLine($"Count = {s.Count}")
' Stackの内容をクリア
s.Clear()
Console.WriteLine($"Count = {s.Count}")
End Sub
End Class
Count = 3 Count = 0
TrimExcessメソッドを使うことで、Stack内部で確保されているバッファを最小化することができます。
容量の縮小 (TrimExcess)
Stackに対してそれ以上要素を追加や取り出しをする必要がなくなった場合には、TrimExcessメソッドを呼び出すことで、Stackが内部的に確保しているバッファを最小化することができ、不要な容量を減らすことができます。
TrimExcessメソッドはStack内の再割当てを行うことで使用するメモリを最小化します。 そのため、Stackにそれ以上変更を加えない(追加によって容量を再度拡張する必要がない)ことが明らかな場合などに用いるべきで、不必要に何度も呼び出すことは逆にパフォーマンスの劣化に繋がります。
なお、List.CapacityのようなプロパティはStackには用意されていないため、実際にStackが確保しているバッファの容量を知ることはできません。
容量とバッファを最小化に関しては、Listクラスでの解説ジェネリックコレクション(1) List §.容量を参照してください。
列挙操作
StackはIEnumerable<T>を実装しているためforeach文による列挙ができます。 foreach文による列挙では、Pushした順とは逆、つまりPopするときと同じ順で要素が列挙されます。 ポップ操作とは異なり、Stackを列挙するだけでは要素の削除は行われません。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
var s = new Stack<string>();
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
// foreachでStackの内容を列挙
foreach (var e in s) {
Console.WriteLine(e);
}
// 列挙してもStackから要素は削除されず、内容は変わらない
Console.WriteLine($"Count = {s.Count}");
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
' For EachでStackの内容を列挙
For Each e As String In s
Console.WriteLine(e)
Next
' 列挙してもStackから要素は削除されず、内容は変わらない
Console.WriteLine($"Count = {s.Count}")
End Sub
End Class
Charlie Bob Alice Count = 3
インデックス付きの列挙操作
一方、Stackではインデクサがサポートされないのでfor文による列挙はできません。 for文でインデックスを用いた列挙を行うためには、Stackを配列に変換してから列挙するか、LINQの拡張メソッドSelectを使って次のようにします。
using System;
using System.Collections.Generic;
using System.Linq;
class Sample {
static void Main()
{
var s = new Stack<string>();
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
// Selectメソッドを使ってStackの要素をインデックス付きで列挙する
foreach (var pair in s.Select((e, i) => new {Element = e, Index = i})) {
Console.WriteLine($"{pair.Index} => {pair.Element}");
}
}
}
Option Infer On
Imports System
Imports System.Collections.Generic
Imports System.Linq
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
' Selectメソッドを使ってStackの要素をインデックス付きで列挙する
For Each pair In s.Select(Function(e, i)
Return New With {.Element = e, .Index = i}
End Function)
Console.WriteLine($"{pair.Index} => {pair.Element}")
Next
End Sub
End Class
0 => Eve 1 => Dave 2 => Charlie
配列からの変換
配列からStackに変換するには、コンストラクタが使えます。 あらかじめ内容を持った状態のStackを作成したい場合も、コンストラクタに配列などを指定してインスタンスを作成します。 コンストラクタに配列を指定した場合、Stackの内容は配列の要素を先頭から一つずつPushした場合と同じになります。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
var arr = new string[] {"Alice", "Bob", "Charlie", "Dave", "Eve"};
var s = new Stack<string>(arr); // 配列からStackを作成
while (0 < s.Count) {
Console.WriteLine(s.Pop());
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim arr() As String = New String() {"Alice", "Bob", "Charlie", "Dave", "Eve"}
Dim s As New Stack(Of String)(arr) ' 配列からStackを作成
While 0 < s.Count
Console.WriteLine(s.Pop())
End While
End Sub
End Class
Eve Dave Charlie Bob Alice
配列への変換・コピー (ToArray・CopyTo)
Stackから配列へ変換する場合にはToArrayメソッドやCopyToメソッドが使えます。 ToArrayメソッドではStackの内容を配列に変換したものが得られ、CopyToメソッドではStackの内容を既存の配列にコピーします。 変換・コピーした後の配列の内容は、列挙操作を行った場合と同様にStackの内容を一つずつPopした場合と同じ順序になります。 当然、変換・コピーの前後でStackの内容は変化しません。
using System;
using System.Collections.Generic;
class Sample {
static void Main()
{
var s = new Stack<string>();
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
// 配列に変換
Console.WriteLine("[ToArray]");
var arr1 = s.ToArray();
for (var i = 0; i < arr1.Length; i++) {
Console.WriteLine("arr1[{0}] => {1}", i, arr1[i]);
}
// 配列にコピー
Console.WriteLine("[CopyTo]");
var arr2 = new string[s.Count];
s.CopyTo(arr2, 0);
for (var i = 0; i < arr2.Length; i++) {
Console.WriteLine("arr2[{0}] => {1}", i, arr2[i]);
}
}
}
Imports System
Imports System.Collections.Generic
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
' 配列に変換
Console.WriteLine("[ToArray]")
Dim arr1() As String = s.ToArray()
For i As Integer = 0 To arr1.Length - 1
Console.WriteLine("arr1({0}) => {1}", i, arr1(i))
Next
' 配列にコピー
Console.WriteLine("[CopyTo]")
Dim arr2(s.Count - 1) As String
s.CopyTo(arr2, 0)
For i As Integer = 0 To arr2.Length - 1
Console.WriteLine("arr2({0}) => {1}", i, arr2(i))
Next
End Sub
End Class
[ToArray] arr1(0) => Charlie arr1(1) => Bob arr1(2) => Alice [CopyTo] arr2(0) => Charlie arr2(1) => Bob arr2(2) => Alice
一部分の配列への変換
Stackの一部分のみを配列として取得するメソッドは用意されていません。 そのため、全部を配列に変換した後必要な部分だけを抜き出して使うか、次のようにLINQの拡張メソッドSkipおよびTakeを組み合わせて一部分のみを取得します。
using System;
using System.Collections.Generic;
using System.Linq;
class Sample {
static void Main()
{
var s = new Stack<string>();
s.Push("Alice");
s.Push("Bob");
s.Push("Charlie");
s.Push("Dave");
s.Push("Eve");
// Stackの1番目から3つ分を配列に変換
// (Stackから要素1つ分をSkip、そこから要素3つをTake、その結果をToArray)
var arr = s.Skip(1).Take(3).ToArray();
for (var i = 0; i < arr.Length; i++) {
Console.WriteLine("arr[{0}] => {1}", i, arr[i]);
}
}
}
Imports System
Imports System.Collections.Generic
Imports System.Linq
Class Sample
Shared Sub Main()
Dim s As New Stack(Of String)()
s.Push("Alice")
s.Push("Bob")
s.Push("Charlie")
s.Push("Dave")
s.Push("Eve")
' Stackの1番目から3つ分を配列に変換
' (Stackから要素1つ分をSkip、そこから要素3つをTake、その結果をToArray)
Dim arr() As String = s.Skip(1).Take(3).ToArray()
For i As Integer = 0 To arr.Length - 1
Console.WriteLine("arr({0}) => {1}", i, arr(i))
Next
End Sub
End Class
arr[0] => Dave arr[1] => Charlie arr[2] => Bob
LinkedListを使ったスタックの実装
Stackクラス以外にも、双方向連結リストのデータ構造を構成するためのクラスであるLinkedList<T>クラスを用いることでもスタックのデータ構造を実装することができます。 具体例についてはジェネリックコレクション(4) LinkedList §.スタックとしての使用で紹介しています。