VB.NET Queue 佇列 筆記(基礎篇)
有些資料不能隨意挑選處理順序,而是必須按照進來的先後依序處理。例如櫃台叫號、待辦工單、背景任務、訊息排隊,都屬於「先排隊、先處理」的流程。
Queue 就是用來處理這種排隊資料的集合。Queue 的核心規則是 先進先出(FIFO, First In First Out):最早加入的資料,會最先被取出。
佇列原理分析
用排隊窗口理解 Queue
Queue 可視為一條排隊隊伍。新資料只能排到隊伍尾端,處理資料時只能從隊伍前端開始。中間的資料不能被直接抽走,也不能插隊到前面。
- 加入資料:使用
Enqueue,資料會排到 Queue 尾端。 - 取出資料:使用
Dequeue,會取出 Queue 前端最早加入的資料。 - 查看下一筆:使用
Peek,只查看前端資料,不會移除。 - 檢查數量:使用
Count,可確認目前 Queue 內還有幾筆資料。
Queue 可以先記住四個重點:
Enqueue:加入尾端。Dequeue:取出並移除前端。Peek:查看前端但不移除。Count:確認目前筆數,避免空 Queue 取值錯誤。
基本操作與語法實作
Windows Forms 物件配置
以下範例皆以 Windows Forms 為主。請於 Form1 放置下列控制項:
Button1:建立資料或加入新資料。Button2:取出下一筆資料。Button3:查看下一筆資料。TextBox1:輸入任務名稱。ListBox1:顯示目前 Queue 內容。Label1:顯示目前狀態。
場景一:建立 Queue 並依序取出資料
此範例建立一組待處理項目。按下 Button1 建立 Queue,按下 Button2 取出最前面的資料。取出後,該資料會從 Queue 中移除。
範例程式碼
VB.NET / Windows Forms
Imports System.Collections.Generic
Public Class Form1
Private serviceQueue As New Queue(Of String)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
serviceQueue.Clear()
serviceQueue.Enqueue("文件審核")
serviceQueue.Enqueue("帳號建立")
serviceQueue.Enqueue("權限配置")
RefreshQueueDisplay()
Label1.Text = "已建立待處理佇列,共 " & serviceQueue.Count.ToString() & " 筆"
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If serviceQueue.Count > 0 Then
Dim currentItem As String = serviceQueue.Dequeue()
RefreshQueueDisplay()
Label1.Text = "已取出項目:" & currentItem
Else
Label1.Text = "Queue 目前沒有可處理資料"
End If
End Sub
Private Sub RefreshQueueDisplay()
ListBox1.Items.Clear()
For Each item As String In serviceQueue
ListBox1.Items.Add(item)
Next
End Sub
End Class
畫面輸出結果(先按 Button1,再按 Button2)
ListBox1:
帳號建立
權限配置
Label1:
已取出項目:文件審核邏輯解析
New Queue(Of String)建立只能存放文字的佇列。Enqueue依序加入「文件審核」、「帳號建立」、「權限配置」。Dequeue會取出最早加入的「文件審核」,並將它從 Queue 移除。RefreshQueueDisplay只負責重新顯示目前剩下的 Queue 內容。
場景二:使用 Peek 查看下一筆資料
Peek 適合用於「先看下一筆是誰,但暫時不要處理」的情境。例如叫號系統可先顯示下一位編號,但尚未真的叫號完成。
範例程式碼
VB.NET / Windows Forms
Imports System.Collections.Generic
Public Class Form1
Private numberQueue As New Queue(Of String)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
numberQueue.Clear()
numberQueue.Enqueue("B101")
numberQueue.Enqueue("B102")
numberQueue.Enqueue("B103")
RefreshQueueDisplay()
Label1.Text = "目前排隊總數:" & numberQueue.Count.ToString()
End Sub
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
If numberQueue.Count > 0 Then
Dim nextItem As String = numberQueue.Peek()
Label1.Text = "下一位待處理編號:" & nextItem & ",目前總數仍為 " & numberQueue.Count.ToString()
Else
Label1.Text = "Queue 目前為空"
End If
End Sub
Private Sub RefreshQueueDisplay()
ListBox1.Items.Clear()
For Each number As String In numberQueue
ListBox1.Items.Add(number)
Next
End Sub
End Class
畫面輸出結果(先按 Button1,再按 Button3)
ListBox1:
B101
B102
B103
Label1:
下一位待處理編號:B101,目前總數仍為 3邏輯解析
Peek只讀取前端資料,不會移除資料。- 執行
Peek後,Count仍然是 3。 - 畫面中的
ListBox1仍保留 B101、B102、B103。 - 若需要真正處理並移除資料,應使用
Dequeue。
場景三:以 Queue 製作簡易待辦工作佇列
此範例改成由 TextBox1 輸入任務名稱。每次按下 Button1,任務會排到 Queue 尾端;每次按下 Button2,會取出最早加入的任務。
範例程式碼
VB.NET / Windows Forms
Imports System.Collections.Generic
Public Class Form1
Private taskQueue As New Queue(Of String)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim taskName As String = TextBox1.Text.Trim()
If taskName <> "" Then
taskQueue.Enqueue(taskName)
TextBox1.Clear()
RefreshTaskDisplay()
Label1.Text = "任務已加入佇列,目前共有 " & taskQueue.Count.ToString() & " 筆"
Else
Label1.Text = "請先輸入任務名稱"
End If
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If taskQueue.Count > 0 Then
Dim currentTask As String = taskQueue.Dequeue()
RefreshTaskDisplay()
Label1.Text = "目前執行任務:" & currentTask
Else
Label1.Text = "目前沒有待執行任務"
End If
End Sub
Private Sub RefreshTaskDisplay()
ListBox1.Items.Clear()
For Each task As String In taskQueue
ListBox1.Items.Add(task)
Next
End Sub
End Class
畫面輸出結果(依序加入「資料匯入、寄送通知、輸出報表」,再按 Button2)
ListBox1:
寄送通知
輸出報表
Label1:
目前執行任務:資料匯入邏輯解析
TextBox1.Text.Trim()先去除前後空白,避免只有空白的資料被加入。Enqueue(taskName)會將新任務排到尾端。Dequeue會取出最早加入的任務,所以「資料匯入」最先被執行。- Queue 適合這種任務派送流程,因為任務處理順序必須和加入順序一致。
進一步應用與實務觀念
場景四:以 Queue 模擬資料緩衝區
緩衝區可視為暫存資料的排隊區。資料先進入 Queue,之後再依序取出。此範例限制 Queue 最多只能保留三筆資料,避免資料無限制累積。
範例程式碼
VB.NET / Windows Forms
Imports System.Collections.Generic
Public Class Form1
Private bufferQueue As New Queue(Of Integer)
Private bufferLimit As Integer = 3
Private nextValue As Integer = 100
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If bufferQueue.Count < bufferLimit Then
bufferQueue.Enqueue(nextValue)
Label1.Text = "已寫入資料:" & nextValue.ToString()
nextValue += 1
Else
Label1.Text = "緩衝區已滿,暫時無法新增資料"
End If
RefreshBufferDisplay()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If bufferQueue.Count > 0 Then
Dim currentValue As Integer = bufferQueue.Dequeue()
Label1.Text = "已取出資料:" & currentValue.ToString()
Else
Label1.Text = "緩衝區目前為空"
End If
RefreshBufferDisplay()
End Sub
Private Sub RefreshBufferDisplay()
ListBox1.Items.Clear()
For Each item As Integer In bufferQueue
ListBox1.Items.Add(item)
Next
End Sub
End Class
畫面輸出結果(連續按 Button1 四次)
ListBox1:
100
101
102
Label1:
緩衝區已滿,暫時無法新增資料邏輯解析
bufferLimit設為 3,代表最多只允許三筆資料停留在 Queue 中。nextValue用來產生連續資料編號,避免取出資料後再次加入時出現重複編號。Count < bufferLimit成立時才允許Enqueue。- Queue 滿了以後,程式只顯示提醒,不再加入新資料。
Queue 適合與不適合的地方
- 適合:依加入順序處理資料,例如工單、叫號、背景任務、訊息暫存。
- 不適合:需要直接找中間某一筆資料,或經常依條件搜尋資料。
- 重要觀念:
Enqueue、Dequeue、Peek都圍繞「前端與尾端」運作,不是任意位置存取。
使用限制與常見注意事項
空 Queue 不可直接 Dequeue 或 Peek
若 Queue 內沒有任何元素,卻直接呼叫 Dequeue 或 Peek,會產生 InvalidOperationException。因此在取值前,應先檢查 Count 是否大於 0。
場景五:安全取出 Queue 資料
此範例示範 Queue 的基本防呆寫法。取出資料前先檢查 Count,確定仍有資料後才執行 Dequeue。
範例程式碼
VB.NET / Windows Forms
Imports System.Collections.Generic
Public Class Form1
Private myQueue As New Queue(Of String)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
myQueue.Clear()
myQueue.Enqueue("第一筆資料")
myQueue.Enqueue("第二筆資料")
RefreshQueueDisplay()
Label1.Text = "測試資料已建立"
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If myQueue.Count > 0 Then
Dim currentItem As String = myQueue.Dequeue()
RefreshQueueDisplay()
Label1.Text = "已處理:" & currentItem
Else
Label1.Text = "Queue 目前為空,無法取出資料"
End If
End Sub
Private Sub RefreshQueueDisplay()
ListBox1.Items.Clear()
For Each item As String In myQueue
ListBox1.Items.Add(item)
Next
End Sub
End Class
畫面輸出結果(資料取完後再次按 Button2)
ListBox1:
Label1:
Queue 目前為空,無法取出資料邏輯解析
myQueue.Count > 0先確認 Queue 仍有資料。- 條件成立時才執行
Dequeue,可避免空 Queue 取值錯誤。 - 條件不成立時只顯示提醒,不執行取出動作。
- 這種判斷應固定保留在
Dequeue與Peek前方。
Queue 使用時應注意:
- 不適合隨機存取:Queue 著重前端取出與尾端加入,不適合直接操作中間元素。
- 不適合大量搜尋:若需求是依關鍵字快速查找資料,
Dictionary或其他結構通常更合適。 - 多執行緒需另外處理:若多個執行緒同時操作同一個 Queue,需加入同步控制,或改用並行集合。
- 資料順序不可任意調整:Queue 的價值在於保留先後順序,若需要排序,應改用其他集合或先轉成其他資料結構。
Queue 與 Stack 的適用情境比較
| 比較項目 | Queue | Stack |
|---|---|---|
| 處理順序 | 先進先出(FIFO)。 | 後進先出(LIFO)。 |
| 取出位置 | 從最早加入的資料開始取出。 | 從最後加入的資料開始取出。 |
| 常見用途 | 叫號、工單派送、背景任務、訊息佇列。 | 復原操作、瀏覽紀錄回退、巢狀流程、深度優先處理。 |
| 適用情境 | 資料需要按照到達順序處理。 | 最後加入的資料需要優先處理。 |
重點整理
Queue是先進先出集合,最早加入的資料會最先被取出。Enqueue用來加入資料,資料會排到 Queue 尾端。Dequeue用來取出並移除前端資料。Peek用來查看前端資料,但不會移除資料。Dequeue與Peek前應先檢查Count > 0,避免空 Queue 取值錯誤。- Queue 適合排隊、派工、緩衝與順序處理,不適合隨機存取、排序或大量搜尋。