.NET 9 中的新增功能介绍:更新了集合中的优先级队列

8f3ad251197a2d43d23e525f4cc8a4f7.jpeg

概述:在这篇文章中,我将介绍 .NET 9(.NET 8 的继任者)中引入的最新集合功能。.NET 中的图形算法刚刚变得很酷! .NET 9 为该类引入了一个新功能:方法。这一新增功能使得使用优先级队列变得更加容易,这对于解决寻路问题和图形遍历(例如 Dijkstra 算法的变体)的软件工程师来说是个好消息。PriorityQueueTElement, TPriorityRemove(TElement, TElement, TPriority, IEqualityComparerTElement)了解优先级队列想象一下,人们不只是在等待轮到他们,而是根据他们的重要性来安排。这就是优先级队列的基本思想

在这篇文章中,我将介绍 .NET 9(.NET 8 的继任者)中引入的最新集合功能。

.NET 中的图形算法刚刚变得很酷! .NET 9 为该类引入了一个新功能:方法。这一新增功能使得使用优先级队列变得更加容易,这对于解决寻路问题和图形遍历(例如 Dijkstra 算法的变体)的软件工程师来说是个好消息。PriorityQueue<TElement, TPriority>Remove(TElement, TElement, TPriority, IEqualityComparer<TElement>)

了解优先级队列

想象一下,人们不只是在等待轮到他们,而是根据他们的重要性来安排。这就是优先级队列的基本思想。优先级较高的人可以更快地到达队伍的最前面,这使他们非常适合像 Dijkstra 的最短路径算法这样的算法。

然而,传统的优先队列有一个问题:很难改变已经排队的人的重要性。这可能会使使用某些图形算法变得棘手。

using System;  
using System.Collections.Generic;  
  
class Program  
{  
    static void Main(string[] args)  
    {  
        // Create a priority queue of strings with int priorities  
        PriorityQueue<string, int> priorityQueue = new PriorityQueue<string, int>();  
  
        // Enqueue elements with priority  
        priorityQueue.Enqueue("Niraj", 2); // John has priority 2  
        priorityQueue.Enqueue("Alice", 1); // Alice has priority 1  
        priorityQueue.Enqueue("Emily", 3); // Emily has priority 3  
        priorityQueue.Enqueue("David", 4); // David has priority 4  
  
        // Dequeue elements (sorted by priority)  
        Console.WriteLine("People are being served according to their priority:");  
        while (priorityQueue.Count > 0)  
        {  
            var person = priorityQueue.Dequeue();  
            Console.WriteLine($"Serving {person}");  
        }  
    }  
}

在这里,创建了一个优先级队列来保存人们的姓名以及他们各自的优先级。元素将按其分配的优先级排入优先级队列。然后,程序遍历队列,逐个对元素进行排队并将它们打印到控制台。

新方法Remove

一般来说,数组堆的一个问题是它们不支持优先级更新,这使得它们在算法(例如 Dijkstra 算法的变体)中使用时令人望而却步。

.NET 9 为类中的方法带来了一个新选项。此方法采用四个参数:RemovePriorityQueue

  • TElement element:想要从队列中取出的人(或事物)。

  • TElement outMatchingElement:此变量将保存实际被删除的人(或事物)(如果行中有重复项,则很有用)。

  • TPriority outPriority:此变量将保存被移除的人(或事物)的重要性级别。

  • IEqualityComparer<TElement> comparer:用于处理具有重复重要性级别的情况的可选工具。

其工作原理如下:

  1. 与想要改变重要性的人(或事物)通话。Remove

  2. 该方法删除人(或事物)(并将其存储在 和 中)。outMatchingElementoutPriority

  3. 然后,将同一个人(或事物)放回原处,但这次使用该方法使用新的、更高的重要性级别。Enqueue

简单示例

using System;  
using System.Collections.Generic;  
using System.Xml.Linq;  
  
class Program  
{  
    static void Main(string[] args)  
    {  
        // Create a priority queue of strings with int priorities  
        PriorityQueue<string, int> priorityQueue = new PriorityQueue<string, int>();  
  
        // Enqueue elements with priority  
        priorityQueue.Enqueue("Niraj", 2); // John has priority 2  
        priorityQueue.Enqueue("Alice", 1); // Alice has priority 1  
        priorityQueue.Enqueue("Emily", 3); // Emily has priority 3  
        priorityQueue.Enqueue("David", 4); // David has priority 4  
        priorityQueue.Enqueue("John", 2); // John has priority 2  
  
        // removing the element - "Alice" from priority queue  
        priorityQueue.Remove("Alice", out _, out _);  
  
        // removing the element - "Alice" from priority queue  
        string removedElement;  
        int priority;  
        priorityQueue.Remove("John", out removedElement, out priority);  
        Console.WriteLine($"Person {removedElement} which had a priority {priority} was removed from the queue.");  
  
        // Dequeue elements (sorted by priority)  
        Console.WriteLine("People are being served according to their priority:");  
        while (priorityQueue.Count > 0)  
        {  
  
            var person = priorityQueue.Dequeue();  
            Console.WriteLine($"Serving {person}");  
        }  
    }  
}

在此示例中,元素以其分配的优先级排队到优先级队列中,然后使用该方法从队列中删除 2 个元素。最后,程序遍历队列,逐个对元素进行排队并将它们打印到控制台。Remove

Dijkstra 的优先级队列算法示例

IGraph 接口:

public interface IGraph<TNode>  
{  
    IEnumerable<TNode> GetNeighbors(TNode node);  
    int GetEdgeWeight(TNode source, TNode target);  
}

此接口定义了表示图形所需的基本功能:

  • GetNeighbors(TNode node):此方法检索给定节点的相邻节点列表。

  • GetEdgeWeight(TNode source, TNode target):此方法返回与两个节点之间的边关联的权重。

SampleGraph 类:

public class SampleGraph : IGraph<string>
{
    private readonly Dictionary<string, List<KeyValuePair<string, int>>> edges = new Dictionary<string, List<KeyValuePair<string, int>>>();

    public SampleGraph()
    {
        // Add edges and their weights to the dictionary here
        edges.Add("A", new List<KeyValuePair<string, int>>() { new KeyValuePair<string, int>("B", 4), new KeyValuePair<string, int>("C", 2) });
        edges.Add("B", new List<KeyValuePair<string, int>>() { new KeyValuePair<string, int>("D", 2), new KeyValuePair<string, int>("E", 3) });
        edges.Add("C", new List<KeyValuePair<string, int>>() { new KeyValuePair<string, int>("D", 5) });
        edges.Add("D", new List<KeyValuePair<string, int>>() { new KeyValuePair<string, int>("E", 1) });
    }

    public IEnumerable<string> GetNeighbors(string node)
    {
        if (!edges.ContainsKey(node))
        {
            return Enumerable.Empty<string>();
        }
        return edges[node].Select(x => x.Key);
    }

    public int GetEdgeWeight(string source, string target)
    {
        if (!edges.ContainsKey(source) || !edges[source].Any(x => x.Key == target))
        {
            throw new ArgumentException("Edge not found in the graph");
        }
        return edges[source].First(x => x.Key == target).Value;
    }
}

此类实现简单内存中图的接口。IGraph

  • 它使用字典,其中键是节点名称(字符串),值是键值对的列表。每个键值对代表一个邻居及其权重。edges

  • 构造函数 () 通过将边及其权重添加到字典中来初始化图形(您可以将其替换为实际的图形数据)。SampleGraph()

  • GetNeighbors(string node):此方法检查该节点是否存在于字典中。如果是这样,它通过从相应值中的键值对中提取键来返回相邻节点的列表。

  • GetEdgeWeight(string source, string target):此方法检查源节点是否存在,以及它是否具有指向目标节点的 Edge。如果同时满足这两个条件,则返回源节点和目标节点之间边的权重。否则,它会抛出 .ArgumentException

DijkstraWithPriorityQueue 类:

public static class DijkstraWithPriorityQueue
{
    public static Dictionary<TNode, int> FindShortestPaths<TNode>(
        IGraph<TNode> graph, TNode startNode)
    {
        var distances = new Dictionary<TNode, int>();
        distances[startNode] = 0;

        var priorityQueue = new PriorityQueue<TNode, int>();
        priorityQueue.Enqueue(startNode, 0);

        while (priorityQueue.TryDequeue(out TNode currentNode, out int currentDistance))
        {
            foreach (var neighbor in graph.GetNeighbors(currentNode))
            {
                var edgeWeight = graph.GetEdgeWeight(currentNode, neighbor);
                var tentativeDistance = currentDistance + edgeWeight;

                // Check if relaxation is needed
                if (!distances.ContainsKey(neighbor) || tentativeDistance < distances[neighbor])
                {
                    distances[neighbor] = tentativeDistance;

                    // Simulate priority update using Remove and Enqueue
                    priorityQueue.Remove(neighbor, out _, out _);
                    priorityQueue.Enqueue(neighbor, tentativeDistance);
                }
            }
        }

        return distances;
    }
}

此类使用优先级队列实现 Dijkstra 的最短路径算法。

  • FindShortestPaths<TNode>(IGraph<TNode> graph, TNode startNode):此静态方法将图形和起始节点作为输入。

  • 它创建一个字典来存储迄今为止为每个节点找到的最短距离。distances

  • 它将起始节点的距离初始化为 0,将所有其他节点的距离初始化为无穷大(通过不将它们包含在字典中来表示)。

  • 它创建一个优先级队列 (),其中节点根据其与起始节点的当前距离(距离越低 = 优先级越高)对节点进行优先级排序。priorityQueue

  • 该算法进入一个循环,该循环一直持续到优先级队列为空,它将优先级最高(最接近起始节点)的节点从队列中取消排队。它遍历已取消排队的节点的所有邻居。对于每个邻居,它通过将当前节点和邻居之间的边权重与当前节点的当前距离相加来计算暂定距离。如果暂定距离短于邻居的当前已知距离,则它会更新字典中的距离,并使用更新的距离将优先级队列中的邻居重新排队(模拟优先级更新)。distances

  • 最后,该方法返回字典,其中包含从起始节点到图中所有其他节点的最短距离。distances

课程类别:

public class Program  
{  
    public static void Main(string[] args)  
    {  
        var graph = new SampleGraph();  
        var startNode = "A";  
  
        var shortestDistances = DijkstraWithPriorityQueue.FindShortestPaths(graph, startNode);  
  
        Console.WriteLine("Shortest distances from {0}:", startNode);  
        foreach (var node in shortestDistances)  
        {  
            Console.WriteLine("{0}: {1}", node.Key, node.Value);  
        }  
    }  
}

此类是程序的入口点。

  • 它创建一个表示示例图的对象。SampleGraph

  • 它定义了起始节点。

  • 它从类中调用该方法,以查找从起始节点到所有其他节点的最短距离。FindShortestPathsDijkstraWithPriorityQueue

  • 它将计算出的最短距离打印到控制台。

总的来说,这段代码演示了如何使用类中的新方法(尽管用于模拟更新)来实现 Dijkstra 的算法并找到图中的最短路径。RemovePriorityQueue

优势和用例

新方法提供以下功能:Remove

  • 简化优先级队列更新:此方法提供了一种更易于管理的方式来更新基于阵列的队列中的优先级,即使它不是性能最高的选项。

  • 增强教育和原型设计体验:此功能允许更轻松地试验和理解 .NET 9 中的图形算法。

  • 开发基本的寻路解决方案:对于渐近性能不重要的方案,此方法提供了一种实现寻路算法的实用方法。


.NET 9 引入了令人兴奋的新功能和改进,旨在满足软件工程师不断变化的需求。若要详细了解 .NET 9 中的新功能和增强功能,请查看官方文档,并继续关注未来的更新。

如果你喜欢我的文章,请给我一个赞!谢谢

-

技术群:添加小编微信并备注进群

小编微信:mm1552923   

公众号:dotNet编程大全    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值