.NET 6新特性试用 | PriorityQueue

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.NET 6新特性试用 | PriorityQueue相关的知识,希望对你有一定的参考价值。

前言

我们常用Queue<T>类来表示先进先出(FIFO)集合,集合中的对象按照放入顺序检索。例如:

var jobs = new Queue<Job>();
 
jobs.Enqueue(new Job()  Id = 1 );
jobs.Enqueue(new Job()  Id = 2 );
jobs.Enqueue(new Job()  Id = 3 );
 
while (jobs.TryDequeue(out var job))

    Console.WriteLine(job.Id);


//输出
1
2
3

PriorityQueue

在.NET 6中,新增了PriorityQueue<TElement,TPriority>类,可以用来表示具有值和优先级的集合。集合中的对象按照优先级值从小到大的顺序检索。

例如,最后放入队列的任务最紧急,需要有限处理:

var jobs = new PriorityQueue<Job, int>(); 

jobs.Enqueue(new Job()  Id = 1 , 100);
jobs.Enqueue(new Job()  Id = 2 , 100);
jobs.Enqueue(new Job()  Id = 3 , 1);
 
while (jobs.TryDequeue(out var job,out var priority))

    Console.WriteLine(job.Id);


//输出
3
1
2

自定义比较器

优先级TPriority不必是数字,可以是任何类型,只要它的实例之间能比较大小。甚至,我们可以使用自定义比较器,实现复杂的优先级计算逻辑。

例如,我们按数字从大到小的顺序排列优先级:

var jobs = new PriorityQueue<Job, int>(); 

jobs.Enqueue(new Job()  Id = 1 , 100);
jobs.Enqueue(new Job()  Id = 2 , 200);
jobs.Enqueue(new Job()  Id = 3 , 300);
 
while (jobs.TryDequeue(out var job,out var priority))

    Console.WriteLine(job.Id);


public class JobComparer : IComparer<int>

    public int Compare(int x, int y)
    
        return y.CompareTo(x);
    


//输出
3
2
1

比较时机

那到底是放入队列时,还是从队列取出时进行比较呢?

我们用代码进行测试:

for (int i = 1; i <= 3; i++)

    Console.WriteLine($@"Enqueue i");
    jobs.Enqueue(new Job()  Id = i , 100 * i);


for (int i = 4; i <= 6; i++)

    Console.WriteLine($@"Enqueue i");
    jobs.Enqueue(new Job()  Id = i , -100 * i);

for (int i = 7; i <= 9; i++)

    Console.WriteLine($@"Enqueue i");
    jobs.Enqueue(new Job()  Id = i , 100 * i);


Console.WriteLine("Dequeue");

while (jobs.TryDequeue(out var job,out var priority))

    Console.WriteLine(job.Id);


//输出
Enqueue 1
Enqueue 2
Compare(200, 100)
Enqueue 3
Compare(300, 200)
Enqueue 4
Compare(-400, 300)
Enqueue 5
Compare(-500, 300)
Enqueue 6
Compare(-600, 100)
Enqueue 7
Compare(700, 100)
Compare(700, 300)
Enqueue 8
Compare(800, 300)
Compare(800, 700)
Enqueue 9
Compare(900, 700)
Compare(900, 800)
Dequeue
Compare(200, 800)
Compare(-400, 800)
Compare(-500, 800)
Compare(700, 800)
Compare(100, -600)
Compare(300, 100)
Compare(700, 300)
9
Compare(200, 700)
Compare(-400, 700)
Compare(-500, 700)
Compare(300, 700)
Compare(100, -600)
Compare(300, 100)
8
Compare(200, 300)
Compare(-400, 300)
Compare(-500, 300)
Compare(100, 300)
Compare(100, -600)
7
Compare(200, 100)
Compare(-400, 200)
Compare(-500, 200)
Compare(-600, 200)
3
Compare(-600, 100)
Compare(-400, 100)
Compare(-500, 100)
2
Compare(-600, -500)
Compare(-400, -500)
1
Compare(-600, -500)
4
5
6

可以看到,放入和取出时都需要进行优先级比较。

放入时只和队列最顶部的元素进行比较,而取出时需要比较队列中所有剩余元素的优先级。

结论

通过上面的代码,可以发现PriorityQueue实际把队列中的元素分成了2堆:

Enqueue 8
Compare(800, 300)
Compare(800, 700)
Enqueue 9
Compare(900, 700)
Compare(900, 800)

你觉得这样做有什么目的?欢迎到公众号“My IO”上留言讨论!

以上是关于.NET 6新特性试用 | PriorityQueue的主要内容,如果未能解决你的问题,请参考以下文章

.NET 6新特性试用 | PeriodicTimer

.NET 6新特性试用 | 可空引用类型

.NET 6新特性试用 | TryGetNonEnumeratedCount

.NET 6新特性试用 | PriorityQueue

.NET 6新特性试用 | 无需配置开发人员异常页

.NET 6新特性试用 | 异步流