在 C# 10 (.NET 6 或以上)增加了 PriorityQueue,每個元素都會依照優先等級離開佇列
不過由上面輸出可以發現有個和我們預想的不太一樣的地方,就是 PriorityQueue 和一般佇列不同,在優先等級相同的情況下不是先進先出。不過後面我們會介紹解決的方法。
參考資料:
Microsoft.learn - PriorityQueue<TElement,TPriority> Class
基本示範
需要指定兩個類型,第一個是放入佇列的內容,第二個是該內容的優先度,越小的越優先。
PriorityQueue<string, int> queue = new();
queue.Enqueue("A1", 1);
queue.Enqueue("B1", 2);
queue.Enqueue("C1", 3);
queue.Enqueue("A2", 1);
queue.Enqueue("B2", 2);
queue.Enqueue("C2", 3);
while (queue.Count > 0)
{
var item = queue.Dequeue();
Console.WriteLine(item);
}
/*
範例輸出:
A1
A2
B2
B1
C1
C2
*/
不過由上面輸出可以發現有個和我們預想的不太一樣的地方,就是 PriorityQueue 和一般佇列不同,在優先等級相同的情況下不是先進先出。不過後面我們會介紹解決的方法。
使用列舉(enum)
數字不容易記得,我們可以將優先度替換為 enum
/// <summary>
/// 會員等級
/// </summary>
public enum Status
{
/// <summary>
/// 金牌會員
/// </summary>
Gold = 1,
/// <summary>
/// 銀牌會員
/// </summary>
Silver = 2,
/// <summary>
/// 一般會員
/// </summary>
Normal = 3,
}
PriorityQueue<string, Status> queue = new();
queue.Enqueue("A1", Status.Gold);
queue.Enqueue("B1", Status.Silver);
queue.Enqueue("C1", Status.Normal);
queue.Enqueue("A2", Status.Gold);
queue.Enqueue("B2", Status.Silver);
queue.Enqueue("C2", Status.Normal);
while (queue.Count > 0)
{
var item = queue.Dequeue();
Console.WriteLine($"{item}");
}
/*
範例輸出:
A1
A2
B2
B1
C1
C2
*/
解決沒有先進先出的問題
其實有個非常簡單的方式,就是將「優先度」變為兩個屬性(使用 Tuple),增加時間戳記:
PriorityQueue<string, (Status, DateTime)> queue = new();
queue.Enqueue("A1", (Status.Gold, DateTime.Now));
queue.Enqueue("B1", (Status.Silver, DateTime.Now));
queue.Enqueue("C1", (Status.Normal, DateTime.Now));
queue.Enqueue("A2", (Status.Gold, DateTime.Now));
queue.Enqueue("B2", (Status.Silver, DateTime.Now));
queue.Enqueue("C2", (Status.Normal, DateTime.Now));
while (queue.Count > 0)
{
var item = queue.Dequeue();
Console.WriteLine($"{item}");
}
/*
範例輸出:
A1
A2
B1
B2
C1
C2
*/
自訂比較器
假設今天已經訂好金牌會員的值或是分數是 10,銀牌會員 5,一般會員是 1,不能更改,而預設的情況下是越小的月優先,該怎麼辦?很簡單,我們可以自訂比較器
/// <summary>
/// 會員等級
/// </summary>
public enum Status
{
/// <summary>
/// 金牌會員
/// </summary>
Gold = 10,
/// <summary>
/// 銀牌會員
/// </summary>
Silver = 5,
/// <summary>
/// 一般會員
/// </summary>
Normal = 1,
}
/// <summary>
/// 自訂比較器
/// </summary>
public class StatusComparer : IComparer<(Status, DateTime)>
{
public int Compare((Status, DateTime) x, (Status, DateTime) y)
{
if (x.Item1 == y.Item1) return x.Item2.CompareTo(y.Item2);
return y.Item1.CompareTo(x.Item1);
}
}
PriorityQueue<string, (Status, DateTime)> queue = new(new StatusComparer());
queue.Enqueue("A1", (Status.Gold, DateTime.Now));
queue.Enqueue("B1", (Status.Silver, DateTime.Now));
queue.Enqueue("C1", (Status.Normal, DateTime.Now));
queue.Enqueue("A2", (Status.Gold, DateTime.Now));
queue.Enqueue("B2", (Status.Silver, DateTime.Now));
queue.Enqueue("C2", (Status.Normal, DateTime.Now));
while (queue.Count > 0)
{
var item = queue.Dequeue();
Console.WriteLine($"{item}");
}
/*
範例輸出:
A1
A2
B1
B2
C1
C2
*/
參考資料:
Microsoft.learn - PriorityQueue<TElement,TPriority> Class
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com