在“队列”结构中添加查找最小元素的功能

Posted

技术标签:

【中文标题】在“队列”结构中添加查找最小元素的功能【英文标题】:Add the function of finding the minimum element to the "Queue" structure 【发布时间】:2021-02-03 03:03:28 【问题描述】:

欢迎大家。了解队列的原理,自己实现了。 我需要用一个函数来补充代码,以在当前存在的元素中找到最小的元素。这段代码中的一些点不是我自己做的,原则上我只是开始接触面向对象的编程。 告诉我如何引用元素以及使用哪个循环来查找最小元素。 谢谢

class Program
    
        public static void Main()
        
            var watch = new Stopwatch();
            watch.Start(); // начало замера времени
            long before = GC.GetTotalMemory(false);
            int min = int.MaxValue;
            Queue queue = new Queue(); // Структура очередь
            File.WriteAllText(@"output.txt", string.Empty);
            using (StreamReader sr = new StreamReader(@"input.txt", System.Text.Encoding.Default)) // Считывание файла input.txt
            
                string line;
                while ((line = sr.ReadLine()) != null) // пока строки в файле не null
                
                    if (line[0] == '+') // если "+", добавить элемент со значением, стоящим после "+"
                    
                        var pattern = new Regex(@"\d+");
                        var numberStr = pattern.Match(line).Groups[0].Value;
                        queue.Enqueue(int.Parse(numberStr));
                    
                    if (line[0] == '-') // если "-", выпустить элемент из очереди (first in - first out)
                    
                        using (StreamWriter sw = new StreamWriter(@"output.txt", true, System.Text.Encoding.Default))
                        
                            sw.WriteLine(queue.Dequeue());
                        
                    
                    if (line[0] == '?') // если "?", вывести наименьший элемент в очереди
                    
                        using (StreamWriter sw = new StreamWriter(@"output.txt", true, System.Text.Encoding.Default))
                        
                            sw.WriteLine(queue.Minimum());
                        
                    
                
            
            long after = GC.GetTotalMemory(false);
            long consumedInMegabytes = (after - before) / (1024); // замер памяти в КБ
            Console.WriteLine($"Затраты памяти (КБ): consumedInMegabytes");
            watch.Stop(); // конец замера времени
            Console.WriteLine($"Время выполнения (миллисекунд): watch.ElapsedMilliseconds");


        
    

    public class QueueItem
    
        public int Value  get; set; 
        public QueueItem Next  get; set; 
    

    public class Queue
    
        QueueItem head;
        QueueItem tail;

        public void Enqueue(int value) // функция добавления элемента в очередь
        
            if (head == null)
                tail = head = new QueueItem  Value = value, Next = null ;
            else
            
                var item = new QueueItem  Value = value, Next = null ;
                tail.Next = item;
                tail = item;
            
        

        public int Dequeue() // функция удаления элемента из очереди
        
            if (head == null) throw new InvalidOperationException();
            var result = head.Value;
            head = head.Next;
            if (head == null)
                tail = null;
            return result;
        
        public int Minimum()
        
            // WHAT I NEED DO
        
    

【问题讨论】:

顺便说一下,最小元素的输出顺序必须和从文档中读取的顺序一致 不知道这是否只是为了玩,但Stopwatch 不是基准测试工具。 另外:如果你用英文注释你的代码,你会大大增加能够阅读它们的人数;) “请告诉我如何引用元素以及使用哪个循环来查找最小元素”。您基本上有两个选择:通过在 Dequeue / Enqueue 上更新它或每次迭代完整队列来跟踪 min Value。两者都有明显的优缺点。 对这个问题的主要观察是,一旦你将一个值x 排入队列,所有早先排入队列的值yy > x 变得无关紧要。这应该允许您保留第二个队列,该队列在O(1) 时间处理Minimum()Dequeue,在摊销O(n) 时间处理Enqueue 【参考方案1】:

假设我们将这些值排入队列:

index: 0 1 2 3 4 5 6 7 8 9
value: 5 3 8 4 2 1 6 3 7 2

第 3 项入队后,Minimum 的正确值是多少?这得看情况。它可以是 3(如果项目 1 尚未出队),也可以是 4。但它永远不可能是58,因为4 < 54 < 8,无论哪个值已经出队。

所以我们可以在每次入队后构建一个具有Minimum 潜在答案的数据结构:

index:     0   1      2      3   4   5      6      7         8      9
value:     5   3      8      4   2   1      6      3         7      2
minimum:  [5] [3] [3, 8] [3, 4] [2] [1] [1, 6] [1, 3] [1, 3, 7] [1, 2]

看到minimum 列表总是排序的。如果我们遇到一个大于列表中最大项目的新值,我们会追加它。如果它更小,我们将所有更大的值替换为新值。


现在,出队会发生什么?让我们取索引 8 之后的 minimum 列表(因为它恰好是最长/最有趣的),看看 dequeue 会发生什么:

index:          0         1         2         3         4      5      6   7   8
dequeue:        5         3         8         4         2      1      6   3   7
minimum: [1, 3, 7] [1, 3, 7] [1, 3, 7] [1, 3, 7] [1, 3, 7] [3, 7] [3, 7] [7] []

请注意,当我们将相同的值出列时,我们只是从列表中删除了最小值。


现在我们需要的是一个数据结构,它允许我们检查第一个元素(O(1) 时间),删除第一个元素(O(1) 时间),并在末尾添加一个新值(这需要也从末尾删除摊销的O(n) 元素)。

由于这是一个大学练习,我将把实际的实现留给你,但这应该会推动你朝着正确的方向前进。

【讨论】:

以上是关于在“队列”结构中添加查找最小元素的功能的主要内容,如果未能解决你的问题,请参考以下文章

链表队列栈

原生JS实现队结构及利用队列模拟‘击鼓传花’游戏

数据结构——优先队列

初识java集合——队列

最小堆(优先队列)基本概念,即一个完整建立,插入,删除代码

优先队列原理与实现