C#最优队列最小堆小顶堆大顶堆小根堆大根堆PriorityQueue的使用

news/2024/5/18 22:35:53 标签: 算法, c#, 最优队列, PriorityQueue, 小根堆, 小顶堆

最优队列有多种叫法,什么小根堆,大根堆,小顶堆,大顶堆。

队列分多种,线性队列(简单队列),循环队列,最优队列等等。

最优队列,可以看作堆叠箱子,越小的越在上面,或者最大的越在上面。目的就是求出前面最值。比如最大的前3个,或最小的前3个。

framework中只能自己创建类,或者变通由sortedset等来做,现在.net6及以后有了。

下面由.net8(反正它也长期被支持了,就用它吧)。

PriorityQueue定义时要指明两个,前者是元素(对象),后者是优先级,一般是整型,如果是自定义类型,需要对这个优先级自己再定义一个比较器,以便最优队列根据这个比较得知哪个“最优”(最大或最小)。

下面创建多个结构体变量,用大量的数来入队,选取前4个(根据结构体的成员value)。

由于选4个前4个最大值,因此我们设置5为最大容量。满4后就要开始考虑出队问题。

第一种:   满4后,是先判断顶点后入队,还是直接入队出队,这两者哪个效率更优?简单测试一下:

    public struct RecSample
    {
        public int Name { get; set; }
        public int Value { get; set; }
    }

    //public class RecCompare : IComparer<RecSample>
    //{
    //    public int Compare(RecSample x, RecSample y)
    //    {
    //        return x.Value.CompareTo(y.Value);
    //    }
    //}
    internal class Program
    {
        private static void Main(string[] args)
        {
            Random r = new Random();
            List<RecSample> list = new List<RecSample>();
            for (int i = 0; i < 30; i++)
            {
                list.Add(new RecSample { Name = r.Next(0, 30), Value = r.Next(0, 30) });
            }

            // 先判断后入队
            PriorityQueue<RecSample, int> pq1 = new PriorityQueue<RecSample, int>();
            Stopwatch sw = Stopwatch.StartNew();
            for (int i = 0; i < 30000000; i++)
            {
                foreach (var item in list)
                {
                    if (pq1.Count < 5)
                        pq1.Enqueue(item, item.Value);
                    else if (item.Value > pq1.Peek().Value)
                        pq1.EnqueueDequeue(item, item.Value);
                }
            }
            sw.Stop();
            Console.WriteLine("先判断后入队耗时:" + sw.ElapsedMilliseconds);

            // 直接入队再出队
            PriorityQueue<RecSample, int> pq2 = new PriorityQueue<RecSample, int>();
            sw.Restart();
            for (int i = 0; i < 30000000; i++)
            {
                foreach (var item in list)
                {
                    if (pq2.Count < 5)
                        pq2.Enqueue(item, item.Value);
                    else
                        pq2.EnqueueDequeue(item, item.Value);
                }
            }
            sw.Stop();
            Console.WriteLine("直接入队再出队耗时:" + sw.ElapsedMilliseconds);

            Console.ReadKey();
        }
    }

多次结果都是后者更优。看来是杞人忧天,不需要再去什么顶点判断,直接入队出队。

第二种:平常我们都是入队出队分成两步使用,比如queue<T>,出队Dequeue,入队Enqueue。现在PriorityQueue里面把两者结合合并,要么直接入队出队DequeueEnqueue,要会出队入队EnqueueDequeue。

现在简单测试分两步,与两步结合的情况:

    public struct RecSample
    {
        public int Name { get; set; }
        public int Value { get; set; }
    }

    //public class RecCompare : IComparer<RecSample>
    //{
    //    public int Compare(RecSample x, RecSample y)
    //    {
    //        return x.Value.CompareTo(y.Value);
    //    }
    //}
    internal class Program
    {
        private static void Main(string[] args)
        {
            Random r = new Random();
            List<RecSample> list = new List<RecSample>();
            for (int i = 0; i < 30; i++)
            {
                list.Add(new RecSample { Name = r.Next(0, 30), Value = r.Next(0, 30) });
            }

            // 先判断后入队
            PriorityQueue<RecSample, int> pq1 = new PriorityQueue<RecSample, int>();
            Stopwatch sw = Stopwatch.StartNew();
            for (int i = 0; i < 30000000; i++)
            {
                foreach (var item in list)
                {
                    if (pq1.Count < 5)
                    {
                        pq1.Enqueue(item, item.Value);
                    }
                    else
                    {
                        pq1.Enqueue(item, item.Value);
                        pq1.Dequeue();
                    }
                }
            }
            sw.Stop();
            Console.WriteLine("先判断后入队耗时:" + sw.ElapsedMilliseconds);

            // 直接入队再出队
            PriorityQueue<RecSample, int> pq2 = new PriorityQueue<RecSample, int>();
            sw.Restart();
            for (int i = 0; i < 30000000; i++)
            {
                foreach (var item in list)
                {
                    if (pq2.Count < 5)
                        pq2.Enqueue(item, item.Value);
                    else
                        pq2.EnqueueDequeue(item, item.Value);
                }
            }
            sw.Stop();
            Console.WriteLine("直接入队再出队耗时:" + sw.ElapsedMilliseconds);

            Console.ReadKey();
        }
    }

结果是分两步还费时,结合效率更高。

下面截图就没有修改提示语了,自已结合代码看看吧。

结论:不用想当然,微软已经考虑了方方面面,所以直接使用吧,它既然有结合的,还有所考虑的,有时当傻瓜也是一种福气。


http://www.niftyadmin.cn/n/5395075.html

相关文章

Springboot 多级缓存设计与实现

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&…

ONE ID在数据管理和数字营销领域浅谈

在数据管理和数字营销领域&#xff0c;One ID 是一种关键的战略概念&#xff0c;用于解决企业普遍面临的数据孤岛问题。数据孤岛是指在企业内部&#xff0c;不同部门、业务线或产品各自独立地定义、存储和管理其数据&#xff0c;导致这些数据之间缺乏关联性和互通性。这种分散的…

我心里埋藏着小秘密

小秘密 - 刘文正 我心里埋藏着小秘密 我想要告诉你 那不是一般的情和意 那是我内心衷曲我心里埋藏着小秘密 从没有再提起&#xff08;那年在北京乘公交见到一位扎小辫细腰的新疆姑娘&#xff09;这秘密写在我心底 永远变成回忆 在一个偶然的机会里 匆匆地与你相遇对你有无限依…

R语言【rgbif】——occ_download(),occ_download_prep():启动GBIF数据的下载请求。

Package rgbif version 3.7.9 使用 occ_search() 只能获取十万条数据&#xff0c;如果妄想通过 start 和 limit 突破&#xff0c;则会返回&#xff1a; <simpleError: Max offset of 100001 exceeded Usage occ_download(...,body NULL,type "and",format &q…

刷题第1天:LeetCode27--移除数组元素--双指针法(快慢指针法)

LeetCode27移除元素&#xff1a;给你一个数组nums和一个值val&#xff0c;你需要原地移除所有数值等于val的元素&#xff0c;并返回移除后数组的新长度。不要使用额外的数组空间&#xff0c;你必须仅使用O(1)额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组…

AI:138-开发一种能够自动化生成艺术品描述的人工智能系统

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带关键代码,详细讲解供大家学习,希望…

windows 11+docker desktop+grafana+influxDB+python写入

下载安装docker desktop 出现WSL相关的错误。WSL是一个linux内核的子系统&#xff0c;docker是基于linux内核的&#xff0c;所以运行docker需要WSL。 以管理员权限打开powershell&#xff0c;查看WSL状态 wsl --status 我遇到的错误是因为我关闭了windows的某些更新 执行上…

LeetCode 2670.找出不同元素数目差数组

给你一个下标从 0 开始的数组 nums &#xff0c;数组长度为 n 。 nums 的 不同元素数目差 数组可以用一个长度为 n 的数组 diff 表示&#xff0c;其中 diff[i] 等于前缀 nums[0, …, i] 中不同元素的数目 减去 后缀 nums[i 1, …, n - 1] 中不同元素的数目。 返回 nums 的 不…