【C#】Stackの基本:LIFO(後入れ先出し)コレクションの使い方

目次

Stack<T>とは何か? LIFO(後入れ先出し)

C#のSystem.Collections.Generic名前空間には、List<T>Dictionary<TKey, TValue>の他に、Stack<T>という特定の操作に特化したコレクションがあります。

Stack<T>(スタック)は、「LIFO (Last-In, First-Out)=後入れ先出し」というデータ構造を実装したものです。

これは、現実世界の「積み上げられた皿」や「重ねた本」に例えられます。

  • 新しい皿(データ)は、常に**一番上(Top)**に積みます。
  • 皿(データ)を取り出すときも、常に**一番上(Top)**から取ります。

このLIFOの特性は、アプリケーションの「元に戻す(Undo)」機能や、Webブラウザの「戻る」ボタンの履歴管理など、”最後に行った操作を最初に取り消す”ロジックを実装するのに最適です。


Stack<T>の基本的な操作

Stack<T>の操作は、List<T>AddRemoveとは異なる、専用のメソッド名(Push, Pop)を使用します。

  • Push(T item): スタックの一番上に新しい要素を追加(プッシュ)します。
  • Pop(): スタックの一番上から要素を取り出し、かつ削除(ポップ)します。
  • Peek(): スタックの一番上の要素を削除せずに参照(ピーク=覗き見)するだけです。
  • Count: スタックに現在含まれている要素の数を取得します。

コード例1:基本的な Push, Pop, Peek

シンプルなテキストエディタの「元に戻す(Undo)」履歴をStack<string>で管理する例です。

using System;
using System.Collections.Generic; // Stack<T> を使うために必要

public class StackBasicExample
{
    public static void Main()
    {
        // 1. string 型の Stack を初期化
        var undoHistory = new Stack<string>();

        // 2. Push: 操作履歴をスタックの一番上に追加
        undoHistory.Push("Action: 'Hello' と入力");
        undoHistory.Push("Action: 'World' と入力");
        undoHistory.Push("Action: '!' と入力");

        Console.WriteLine($"--- 履歴が積まれました ---");
        Console.WriteLine($"現在の履歴の数: {undoHistory.Count}"); // 3

        // 3. Peek: 一番上の要素を「削除せず」に参照
        // 最後に積んだ "Action: '!' と入力" が返る
        string nextUndoAction = undoHistory.Peek();
        Console.WriteLine($"\n次に'元に戻す'操作: {nextUndoAction}");
        Console.WriteLine($"Peek後の履歴の数: {undoHistory.Count}"); // 3 (減っていない)

        // 4. Pop: 一番上の要素を「削除して」取り出す
        string undoneAction = undoHistory.Pop();
        Console.WriteLine($"\n'元に戻す'を実行: {undoneAction}");
        Console.WriteLine($"Pop後の履歴の数: {undoHistory.Count}"); // 2 (1つ減った)

        // 5. 再度 Peek
        Console.WriteLine($"\n次に'元に戻す'操作: {undoHistory.Peek()}"); // "Action: 'World' と入力"
    }
}

出力結果:

--- 履歴が積まれました ---
現在の履歴の数: 3

次に'元に戻す'操作: Action: '!' と入力
Peek後の履歴の数: 3

'元に戻す'を実行: Action: '!' と入力
Pop後の履歴の数: 2

次に'元に戻す'操作: Action: 'World' と入力

whileループによるスタックの処理

スタックに積まれた全要素を、while (stack.Count > 0)ループとPopメソッドを使って、LIFO(後入れ先出し)の順序で取り出すのは一般的なパターンです。

using System;
using System.Collections.Generic;

public class StackWhileLoopExample
{
    public static void Main()
    {
        var numberStack = new Stack<int>();
        numberStack.Push(10);
        numberStack.Push(20);
        numberStack.Push(30);

        Console.WriteLine("--- スタックの全要素を Pop (LIFO) ---");
        
        // スタックの要素数が 0 より大きい間、ループ
        while (numberStack.Count > 0)
        {
            // 一番上 (最後に追加した 30) から順番に取り出される
            int item = numberStack.Pop();
            Console.WriteLine(item);
        }

        Console.WriteLine($"処理後の要素数: {numberStack.Count}"); // 0
    }
}

出力結果:

--- スタックの全要素を Pop (LIFO) ---
30
20
10
処理後の要素数: 0

注意点と安全な操作:TryPop / TryPeek

Stack<T>が**空(Count0)**の状態で、Pop()またはPeek()メソッドを呼び出すと、InvalidOperationExceptionという実行時エラーが発生してプログラムが停止します。

これを避けるため、while (stack.Count > 0)のようにCountをチェックする方法の他に、bool値を返すTryPopおよびTryPeekメソッド(DictionaryTryGetValueに似ています)を使用するのが安全な方法です。

using System;
using System.Collections.Generic;

public class StackTryPopExample
{
    public static void Main()
    {
        var numberStack = new Stack<int>();
        numberStack.Push(100);

        // 1. 成功する TryPop
        if (numberStack.TryPop(out int poppedValue))
        {
            Console.WriteLine($"Pop 成功: {poppedValue}"); // 100
        }

        // 2. スタックは空になった
        // 3. 失敗する TryPop (例外は発生しない)
        if (numberStack.TryPop(out int failedValue))
        {
            Console.WriteLine($"Pop 成功: {failedValue}");
        }
        else
        {
            Console.WriteLine("Pop 失敗: スタックは空です。");
        }
    }
}

出力結果:

Pop 成功: 100
Pop 失敗: スタックは空です。

まとめ

Stack<T>は、C#で**LIFO(後入れ先出し)**のロジックを実装するための専用コレクションです。

  • 追加: Push(item)
  • 削除と取得: Pop()
  • 参照のみ: Peek()

PopPeekはスタックが空だと例外をスローするため、Count > 0でチェックするか、TryPop / TryPeekメソッドを使用することで、安全に操作できます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次