Queue

データ構造としてのキュー(queue)には、二つの操作エンキュー(enqueue)とデキュー(dequeue)が定義されます。 エンキューはキューの末尾に要素を追加する操作で、デキューはキューの先頭から要素を取り出す操作です。 この二つの操作により先入れ先出し(FIFO: First-In, First-Out)のデータ構造が実現されます。

例を挙げると、待ち行列の最後尾に一人並べる作業がエンキュー、待ち行列の先頭から一人引き抜く作業がデキューに相当します。

キュー
Alice Alice Alice Bob Bob Bob Charlie Charlie Bob enqueue enqueue dequeue Charlie Alice

.NETにおいて、キューのデータ構造を持つコレクションクラスがSystem.Collections.Generic.Queueクラスです。

Queueクラスに要素を追加するエンキューの操作はEnqueueメソッド、Queueから要素を取り出すデキューの操作はDequeueメソッドで行います(§.エンキュー操作とデキュー操作 (Enqueue/Dequeue))。 Queueから要素をデキューすると、取り出した要素はQueueから削除されます。 Queueから要素を取り出さずに参照だけ行う場合はPeekメソッドを使います。 Queueに現在いくつの要素が含まれているかを知るにはCountプロパティを参照します。

ListクラスDictionaryクラスとは異なり、Queueクラスでは要素が格納された順序が大きな意味を持ちます。 最初(または最後)に格納された要素のみに着目するため、インデックスを指定した要素へのアクセス(ランダムアクセス)はできません(§.インデックス付きの列挙操作)。 また、Queueに格納される要素は格納された順に並べられ、格納された後はその順序を並べ替えることはできません。

Listなどと同様、Queueは可変長のコレクションであるため任意の数の要素をエンキューできます。 エンキューの際、Queue内部の容量は必要に応じて自動的に拡充されます。 デキューの際に要素数が減っても、明示的に指示しない限りはQueue内部で確保されている容量が減ることはありません。

JavaScriptなど他のスクリプト言語では、配列をスタックやキューのように扱うための操作が用意されているものもありますが、Queueクラスではキューとしての操作しか提供されません。 つまり、Queueクラスに対してpush/pop操作を行うようなメソッドは用意されていません。 そういった操作を行いたい場合はStackクラスを使用します。

エンキュー操作とデキュー操作 (Enqueue/Dequeue)

Queueクラスでは、EnqueueメソッドでQueueに対して要素の追加(プッシュ操作)、DequeueメソッドでQueueからの要素の取り出し(ポップ操作)を行います。

次の例では、3つの要素をQueueにエンキューし、その後Queueが空になるまでデキューしています。 キューでは一番最初に入れた要素は一番始めに取り出される(First-In, First-Out)という特性上、要素を入れた順番と同じ順番で表示されている点に注目してください。

EnqueueメソッドでQueueに要素を追加する・DequeueメソッドでQueueから要素を取り出す
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    // Queueに要素をEnqueue
    q.Enqueue("Alice");
    q.Enqueue("Bob");
    q.Enqueue("Charlie");

    // Queueが空になるまで内容をDequeue
    while (0 < q.Count) {
      Console.WriteLine(q.Dequeue());
    }
  }
}
EnqueueメソッドでQueueに要素を追加する・DequeueメソッドでQueueから要素を取り出す
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    ' Queueに要素をEnqueue
    q.Enqueue("Alice")
    q.Enqueue("Bob")
    q.Enqueue("Charlie")

    ' Queueが空になるまで内容をDequeue
    While 0 < q.Count
      Console.WriteLine(q.Dequeue())
    End While
  End Sub
End Class
実行結果
Alice
Bob
Charlie

Queueでもforeachによる列挙操作を行うことができます。 Queueの内容をforeachで列挙すると、Enqueueしたのと同じ順序、Dequeueする場合と同じ順序で要素が列挙されます。

空のQueueに対するDequeue

Queueが空のときにDequeueメソッドを呼び出すと、null/Nothingが返されるのではなく、例外InvalidOperationExceptionがスローされます。 このため、Dequeueメソッドの戻り値からQueueが空だったかどうかを判断することはできません。

Queueが空の状態でDequeueメソッドを呼び出すとInvalidOperationExceptionとなる
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    Console.WriteLine($"Count = {q.Count}"); // 0

    // Queueが空の状態でDequeue操作を行うとInvalidOperationExceptionがスローされる
    Console.WriteLine(q.Dequeue());
  }
}
Queueが空の状態でDequeueメソッドを呼び出すとInvalidOperationExceptionとなる
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    Console.WriteLine($"Count = {q.Count}") ' 0

    ' Queueが空の状態でDequeue操作を行うとInvalidOperationExceptionがスローされる
    Console.WriteLine(q.Dequeue())
  End Sub
End Class
実行結果
Count = 0
Unhandled exception. System.InvalidOperationException: Queue empty.
   at System.Collections.Generic.Queue`1.ThrowForEmptyQueue()
   at System.Collections.Generic.Queue`1.Dequeue()
   at Sample.Main() in /home/smdn/samplecodes/dotnet/cs/test.cs:line 12

Queueが空かどうかに関わらず、例外をスローせずにポップ操作を試行するメソッドとしてTryDequeueメソッドが用意されています。

このほか、DequeueメソッドでInvalidOperationExceptionを避けるには、Dequeueメソッドを呼び出す前にCountプロパティを参照して、要素が1つ以上格納されているかチェックするようにします。

デキュー操作の試行 (TryDequeue)

Queueが空のときにDequeueメソッドを呼び出すと、例外InvalidOperationExceptionがスローされます。 一方、TryDequeueメソッドを使うと、Queueが空の場合でも例外をスローさせずにポップ操作を試行することができます。 TryDequeueメソッドは.NET Standard 2.1/.NET Core 2.0以降で使用できます。

TryDequeueメソッドは、成功した場合はデキューした要素をoutパラメータで出力し、戻り値trueを返します。 失敗した場合、つまりQueueが空だった場合は単に戻り値falseを返します。

TryDequeueメソッドを使ってQueueに対してデキュー操作を試行する .NET Standard 2.1/.NET Core 2.0
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    // Queueに要素をEnqueue
    q.Enqueue("Alice");
    q.Enqueue("Bob");
    q.Enqueue("Charlie");

    // Queueが空になるまで内容をDequeue
    // (Queueが空の場合、TryDequeueメソッドはfalseを返す)
    while (q.TryDequeue(out var e)) {
      Console.WriteLine(e);
    }
  }
}
TryDequeueメソッドを使ってQueueに対してデキュー操作を試行する .NET Standard 2.1/.NET Core 2.0
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    ' Queueに要素をEnqueue
    q.Enqueue("Alice")
    q.Enqueue("Bob")
    q.Enqueue("Charlie")

    ' Queueが空になるまで内容をDequeue
    ' (Queueが空の場合、TryDequeueメソッドはFalseを返す)
    Dim e As String = Nothing

    While q.TryDequeue(e)
      Console.WriteLine(e)
    End While
  End Sub
End Class
実行結果
Alice
Bob
Charlie

ピーク操作 (Peek)

DequeueメソッドはQueueの先頭にある要素を取り出して取得しますが、Peekメソッドを使うとQueueの内容を変更せず(Queueから削除せず)に先頭にある要素を参照できます。

Peekを使ってQueueの内容を変更せずに先頭の内容を参照する
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    // Queueに要素をEnqueue
    q.Enqueue("Alice");
    q.Enqueue("Bob");
    q.Enqueue("Charlie");

    // Queueの内容を変更せずに先頭にある要素を参照する
    Console.WriteLine(q.Peek());

    // PeekメソッドはQueueから要素を取り出さずに参照するので、要素数は変わらない
    Console.WriteLine($"Count = {q.Count}"); // 3
  }
}
Peekを使ってQueueの内容を変更せずに先頭の内容を参照する
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    ' Queueに要素をEnqueue
    q.Enqueue("Alice")
    q.Enqueue("Bob")
    q.Enqueue("Charlie")

    ' Queueの内容を変更せずに先頭にある要素を参照する
    Console.WriteLine(q.Peek())

    ' PeekメソッドはQueueから要素を取り出さずに参照するので、要素数は変わらない
    Console.WriteLine($"Count = {q.Count}")
  End Sub
End Class
実行結果
Alice
Count = 3

foreachなどによる列挙操作では、Queueの状態を変更せずにQueueに格納されているすべての内容を参照することができます。


Dequeueメソッドと同様に、Queueの内容が空の場合にPeekメソッドを呼び出すと、例外InvalidOperationExceptionがスローされます。

Queueが空の状態でPeekメソッドを呼び出すとInvalidOperationExceptionとなる
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    Console.WriteLine($"Count = {q.Count}"); // 0

    // Queueが空の状態でPeek操作を行うとInvalidOperationExceptionがスローされる
    Console.WriteLine(q.Peek());
  }
}
Queueが空の状態でPeekメソッドを呼び出すとInvalidOperationExceptionとなる
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    Console.WriteLine($"Count = {q.Count}") ' 0

    ' Queueが空の状態でPeek操作を行うとInvalidOperationExceptionがスローされる
    Console.WriteLine(q.Peek())
  End Sub
End Class
実行結果
Count = 0
Unhandled exception. System.InvalidOperationException: Queue empty.
   at System.Collections.Generic.Queue`1.ThrowForEmptyQueue()
   at System.Collections.Generic.Queue`1.Peek()
   at Sample.Main() in /home/smdn/samplecodes/dotnet/cs/test.cs:line 12

したがって、Peekメソッドの戻り値を見てQueueが空かどうかを判断することはできません。 Queueが空であるかどうかを判断するにはPeekメソッドではなくCountプロパティを参照します。

ピーク操作の試行 (TryPeek)

TryDequeueメソッドと同様に、TryPeekメソッドを使うと、Queueが空の場合でも例外をスローさせずにピーク操作を試行することができます。 TryPeekメソッドは.NET Standard 2.1/.NET Core 2.0以降で使用できます。

TryPeekメソッドを使ってQueueに対してPeek操作を試行する .NET Standard 2.1/.NET Core 2.0
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    // Queueに要素を追加する
    q.Enqueue("Alice");

    // Queueに要素がある状態で先頭の要素を参照する
    if (q.TryPeek(out var e1))
      Console.WriteLine(e1);
    else
      Console.WriteLine("(empty)");

    // Queueから要素を取り出す
    q.Dequeue();

    // Queueが空の状態で先頭の要素を参照する
    if (q.TryPeek(out var e2))
      Console.WriteLine(e2);
    else
      Console.WriteLine("(empty)");
  }
}
TryPeekメソッドを使ってQueueに対してPeek操作を試行する .NET Standard 2.1/.NET Core 2.0
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    ' Queueに要素を追加する
    q.Enqueue("Alice")

    ' Queueに要素がある状態で先頭の要素を参照する
    Dim e1 As String = Nothing

    If q.TryPeek(e1) Then
      Console.WriteLine(e1)
    Else
      Console.WriteLine("(empty)")
    End If

    ' Queueから要素を取り出す
    q.Dequeue()

    ' Queueが空の状態で先頭の要素を参照する
    Dim e2 As String = Nothing

    If q.TryPeek(e2) Then
      Console.WriteLine(e2)
    Else
      Console.WriteLine("(empty)")
    End If
  End Sub
End Class
実行結果
Alice
(empty)

要素数の取得 (Count)

Queueに現在格納されている要素の数を取得するには、Countプロパティを参照します。 Queueが空の状態、何も格納されていない状態の場合は、当然Countプロパティは0となります。

Countプロパティを参照してQueue内の要素数を取得する
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    // Queueの要素数を取得して出力
    Console.WriteLine($"Count = {q.Count}"); // 0

    // Queueに要素をEnqueue
    q.Enqueue("Alice");
    q.Enqueue("Bob");
    q.Enqueue("Charlie");

    // Queueの要素数を取得して出力
    Console.WriteLine($"Count = {q.Count}"); // 3
  }
}
Countプロパティを参照してQueue内の要素数を取得する
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    ' Queueの要素数を取得して出力
    Console.WriteLine($"Count = {q.Count}") ' 0

    ' Queueに要素をEnqueue
    q.Enqueue("Alice")
    q.Enqueue("Bob")
    q.Enqueue("Charlie")

    ' Queueの要素数を取得して出力
    Console.WriteLine($"Count = {q.Count}") ' 3
  End Sub
End Class
実行結果
Count = 0
Count = 3

要素の有無の検証 (Contains)

Queueに指定した内容の要素が含まれているか調べるには、Containsメソッドを使います。

ただし、このメソッドではIEqualityComparerを指定できないため、Dictionaryのように大文字小文字の違いを無視して比較するといったことはできません。 そういった比較条件を指定した上で要素が含まれているかを調べるには、LINQの拡張メソッドContainsなどを使う必要があります。

Containsメソッドを使ってQueue内の要素の有無を調べる
using System;
using System.Collections.Generic;
using System.Linq;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    // Queueに要素をEnqueue
    q.Enqueue("Alice");
    q.Enqueue("Bob");
    q.Enqueue("Charlie");

    // Queueに"CHARLIE"が含まれているか
    // (大文字小文字の違いが意識されるため、"CHARLIE"は含まれないものとして扱われる)
    Console.WriteLine(q.Contains("CHARLIE"));

    // Queueに"CHARLIE"が含まれているか
    // (LINQのContainsメソッドを使い、大文字小文字の違いを無視して調べる)
    Console.WriteLine(q.Contains("CHARLIE", StringComparer.OrdinalIgnoreCase));
  }
}
Containsメソッドを使ってQueue内の要素の有無を調べる
Imports System
Imports System.Collections.Generic
Imports System.Linq

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    ' Queueに要素をEnqueue
    q.Enqueue("Alice")
    q.Enqueue("Bob")
    q.Enqueue("Charlie")

    ' Queueに"CHARLIE"が含まれているか
    ' (大文字小文字の違いが意識されるため、"CHARLIE"は含まれないものとして扱われる)
    Console.WriteLine(q.Contains("CHARLIE"))

    ' Queueに"CHARLIE"が含まれているか
    ' (LINQのContainsメソッドを使い、大文字小文字の違いを無視して調べる)
    Console.WriteLine(q.Contains("CHARLIE", StringComparer.OrdinalIgnoreCase))
  End Sub
End Class
実行結果
False
True

文字列の比較オプション(StringComparer)については文字列と比較オプション・カルチャの並べ替え規則、IEqualityComparer<T>インターフェイスによる同値比較のカスタマイズについては等価性の定義と比較 §.IEqualityComparer, IEqualityComparer<T>を参照してください。

同一の要素の格納

Queueには同一の要素(値)を複数格納することができます。 同じ要素を複数回Enqueueした場合でもそれぞれ個別の要素として扱われます。

Queueに同一の要素を複数個格納する
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    q.Enqueue("Alice");
    q.Enqueue("Bob");
    q.Enqueue("Bob"); // 同一の要素をEnqueue

    foreach (var e in q) {
      Console.WriteLine(e);
    }
  }
}
Queueに同一の要素を複数個格納する
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    q.Enqueue("Alice")
    q.Enqueue("Bob")
    q.Enqueue("Bob") ' 同一の要素をEnqueue

    For Each e As String In q
      Console.WriteLine(e)
    Next
  End Sub
End Class
実行結果
Alice
Bob
Bob

null/Nothingの格納

stringなどの参照型を格納するQueueの場合はnull/Nothingを格納することもできます。

Queueにnullを格納する(参照型の場合)
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    // string(参照型)のQueue
    var q = new Queue<string>();

    // nullをEnqueueする
    q.Enqueue(null);

    // Enqueueした内容をPeekする
    Console.WriteLine(q.Peek() ?? "(null)");
  }
}
実行結果
(null)
Queueにnullを格納する(参照型の場合)
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    ' String(参照型)のQueue
    Dim q As New Queue(Of String)()

    ' NothingをEnqueueする
    q.Enqueue(Nothing)

    ' Enqueueした内容をPeekする
    If q.Peek() Is Nothing Then
      Console.WriteLine("(Nothing)")
    Else
      Console.WriteLine(q.Peek())
    End If
  End Sub
End Class
実行結果
(Nothing)

intなどの値型を格納するQueueの場合、C#ではnullを格納することはできません。 VBではNothingを格納しようとすると、Nothingそのものではなく、0などその型のデフォルト値が格納されます。

Queueにnullを格納する(値型の場合)
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    // int(値型)のQueue
    var q = new Queue<int>();

    // nullをEnqueueしようとする
    q.Enqueue(null); // error CS1503: 引数 1: は '<null>' から 'int' へ変換することはできません。

    // Enqueueした内容をPeekする
    Console.WriteLine(q.Peek());
  }
}
Queueにnullを格納する(値型の場合)
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    ' Integer(値型)のQueue
    Dim q As New Queue(Of Integer)()

    ' NothingをEnqueueする
    q.Enqueue(Nothing)

    ' Enqueueした内容をPeekする
    Console.WriteLine(q.Peek())
  End Sub
End Class
実行結果
0

値型の値を格納するStackで、値が空であることを表すためにnull/Nothingを格納したいといった場合には、ヌル許容型を用いることができます。

内容のクリア (Clear)

Clearメソッドを呼び出すことで、Queueの内容を空にすることができます。

Clearメソッドを使ってQueueの内容を空にする
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    q.Enqueue("Alice");
    q.Enqueue("Bob");
    q.Enqueue("Charlie");

    Console.WriteLine($"Count = {q.Count}");

    // Queueの内容をクリア
    q.Clear();

    Console.WriteLine($"Count = {q.Count}");
  }
}
Clearメソッドを使ってQueueの内容を空にする
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    q.Enqueue("Alice")
    q.Enqueue("Bob")
    q.Enqueue("Charlie")

    Console.WriteLine($"Count = {q.Count}")

    ' Queueの内容をクリア
    q.Clear()

    Console.WriteLine($"Count = {q.Count}")
  End Sub
End Class
実行結果
Count = 3
Count = 0

TrimExcessメソッドを使うことで、Queue内部で確保されているバッファを最小化することができます。

容量の縮小 (TrimExcess)

Queueに対してそれ以上要素を追加や取り出しをする必要がなくなった場合には、TrimExcessメソッドを呼び出すことで、Queueが内部的に確保しているバッファを最小化することができ、不要な容量を減らすことができます。

TrimExcessメソッドはQueue内の再割当てを行うことで使用するメモリを最小化します。 そのため、Queueにそれ以上変更を加えない(追加によって容量を再度拡張する必要がない)ことが明らかな場合などに用いるべきで、不必要に何度も呼び出すことは逆にパフォーマンスの劣化に繋がります。

なお、List.CapacityのようなプロパティはQueueには用意されていないため、実際にQueueが確保しているバッファの容量を知ることはできません。

容量とバッファを最小化に関しては、Listクラスでの解説ジェネリックコレクション(1) List §.容量を参照してください。

列挙操作

QueueはIEnumerable<T>を実装しているためforeach文による列挙ができるようになっています。 foreach文による列挙では、Enqueueした順と同じ順、つまりDequeueする順と同じ順で要素が列挙されます。 デキュー操作とは異なり、Queueを列挙するだけでは要素の削除は行われません。

foreachでQueueの内容を列挙する
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    q.Enqueue("Alice");
    q.Enqueue("Bob");
    q.Enqueue("Charlie");

    // foreachでQueueの内容を列挙
    foreach (var e in q) {
      Console.WriteLine(e);
    }

    // 列挙してもQueueから要素は削除されず、内容は変わらない
    Console.WriteLine($"Count = {q.Count}");
  }
}
foreachでQueueの内容を列挙する
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    q.Enqueue("Alice")
    q.Enqueue("Bob")
    q.Enqueue("Charlie")

    ' For EachでQueueの内容を列挙
    For Each e As String In q
      Console.WriteLine(e)
    Next

    ' 列挙してもQueueから要素は削除されず、内容は変わらない
    Console.WriteLine($"Count = {q.Count}")
  End Sub
End Class
実行結果
Alice
Bob
Charlie
Count = 3

インデックス付きの列挙操作

一方、Queueではインデクサがサポートされないのでfor文による列挙はできません。 for文でインデックスを用いた列挙を行うためには、Queueを配列に変換してから列挙するか、LINQの拡張メソッドSelectを使って次のようにします。

LINQのSelect拡張メソッドを使ってQueueに対してインデックス付きの列挙を行う
using System;
using System.Collections.Generic;
using System.Linq;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    q.Enqueue("Alice");
    q.Enqueue("Bob");
    q.Enqueue("Charlie");

    // Selectメソッドを使ってQueueの要素をインデックス付きで列挙する
    foreach (var pair in q.Select((e, i) => new {Element = e, Index = i})) {
      Console.WriteLine($"{pair.Index} => {pair.Element}");
    }
  }
}
LINQのSelect拡張メソッドを使ってQueueに対してインデックス付きの列挙を行う
Imports System
Imports System.Collections.Generic
Imports System.Linq

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    q.Enqueue("Alice")
    q.Enqueue("Bob")
    q.Enqueue("Charlie")

    ' Selectメソッドを使ってQueueの要素をインデックス付きで列挙する
    For Each pair In q.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 => Alice
1 => Bob
2 => Charlie

配列からの変換

配列からQueueに変換するには、コンストラクタが使えます。 あらかじめ内容を持った状態のQueueを作成したい場合も、コンストラクタに配列などを指定してインスタンスを作成します。 コンストラクタに配列を指定した場合、Queueの内容は配列の要素を先頭から一つずつEnqueueした場合と同じ内容になります。

配列の内容をQueueの初期内容としてインスタンスを作成する
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    var arr = new string[] {"Alice", "Bob", "Charlie", "Dave", "Eve"};
    var q = new Queue<string>(arr); // 配列からQueueを作成

    while (0 < q.Count) {
      Console.WriteLine(q.Dequeue());
    }
  }
}
配列の内容をQueueの初期内容としてインスタンスを作成する
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    Dim arr() As String = New String() {"Alice", "Bob", "Charlie", "Dave", "Eve"}
    Dim q As New Queue(Of String)(arr) ' 配列からQueueを作成

    While 0 < q.Count
      Console.WriteLine(q.Dequeue())
    End While
  End Sub
End Class
実行結果
Alice
Bob
Charlie
Dave
Eve

配列への変換・コピー (ToArray・CopyTo)

Queueから配列へ変換する場合にはToArrayメソッドCopyToメソッドが使えます。 ToArrayメソッドではQueueの内容を配列に変換したものが得られ、CopyToメソッドではQueueの内容を既存の配列にコピーします。 変換・コピーした後の配列の内容は、列挙操作を行った場合と同様にQueueの内容を一つずつDequeueした場合と同じ順序になります。 当然、変換・コピーの前後でQueueの内容は変化しません。

ToArrayメソッドでQueueを配列に変換する・CopyToメソッドでQueueの内容を配列にコピーする
using System;
using System.Collections.Generic;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    q.Enqueue("Alice");
    q.Enqueue("Bob");
    q.Enqueue("Charlie");

    // 配列に変換
    Console.WriteLine("[ToArray]");

    var arr1 = q.ToArray();

    for (var i = 0; i < arr1.Length; i++) {
      Console.WriteLine("arr1[{0}] => {1}", i, arr1[i]);
    }

    // 配列にコピー
    Console.WriteLine("[CopyTo]");

    var arr2 = new string[q.Count];

    q.CopyTo(arr2, 0);

    for (var i = 0; i < arr2.Length; i++) {
      Console.WriteLine("arr2[{0}] => {1}", i, arr2[i]);
    }
  }
}
ToArrayメソッドでQueueを配列に変換する・CopyToメソッドでQueueの内容を配列にコピーする
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    q.Enqueue("Alice")
    q.Enqueue("Bob")
    q.Enqueue("Charlie")

    ' 配列に変換
    Console.WriteLine("[ToArray]")

    Dim arr1() As String = q.ToArray()

    For i As Integer = 0 To arr1.Length - 1
      Console.WriteLine("arr1({0}) => {1}", i, arr1(i))
    Next

    ' 配列にコピー
    Console.WriteLine("[CopyTo]")

    Dim arr2(q.Count - 1) As String

    q.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) => Alice
arr1(1) => Bob
arr1(2) => Charlie
[CopyTo]
arr2(0) => Alice
arr2(1) => Bob
arr2(2) => Charlie

一部分の配列への変換

Queueの一部分のみを配列として取得するメソッドは用意されていません。 そのため、全部を配列に変換した後必要な部分だけを抜き出して使うか、次のようにLINQの拡張メソッドSkipおよびTakeを組み合わせて一部分のみを取得します。

LINQの拡張メソッドSkip・Takeを使ってQueueの一部分を配列に変換する
using System;
using System.Collections.Generic;
using System.Linq;

class Sample {
  static void Main()
  {
    var q = new Queue<string>();

    q.Enqueue("Alice");
    q.Enqueue("Bob");
    q.Enqueue("Charlie");
    q.Enqueue("Dave");
    q.Enqueue("Eve");

    // Queueの1番目から3つ分を配列に変換
    // (Queueから要素1つ分をSkip、そこから要素3つをTake、その結果をToArray)
    var arr = q.Skip(1).Take(3).ToArray();

    for (var i = 0; i < arr.Length; i++) {
      Console.WriteLine("arr[{0}] => {1}", i, arr[i]);
    }
  }
}
LINQの拡張メソッドSkip・Takeを使ってQueueの一部分を配列に変換する
Imports System
Imports System.Collections.Generic
Imports System.Linq

Class Sample
  Shared Sub Main()
    Dim q As New Queue(Of String)()

    q.Enqueue("Alice")
    q.Enqueue("Bob")
    q.Enqueue("Charlie")
    q.Enqueue("Dave")
    q.Enqueue("Eve")

    ' Queueの1番目から3つ分を配列に変換
    ' (Queueから要素1つ分をSkip、そこから要素3つをTake、その結果をToArray)
    Dim arr() As String = q.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] => Bob
arr[1] => Charlie
arr[2] => Dave

LinkedListを使ったキューの実装

Queueクラス以外にも、双方向連結リストのデータ構造を構成するためのクラスであるLinkedList<T>クラスを用いることでもキューのデータ構造を実装することができます。 具体例についてはジェネリックコレクション(4) LinkedList §.キューとしての使用で紹介しています。